mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
69b36c21f6
@ -602,7 +602,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
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)?, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?) -> 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?, availableReactions: AvailableReactions?, isCentered: Bool) -> 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
|
||||||
|
@ -13,7 +13,7 @@ import AnimatedAvatarSetNode
|
|||||||
import ReactionImageComponent
|
import ReactionImageComponent
|
||||||
|
|
||||||
public final class ReactionIconView: PortalSourceView {
|
public final class ReactionIconView: PortalSourceView {
|
||||||
fileprivate let imageView: UIImageView
|
public let imageView: UIImageView
|
||||||
|
|
||||||
override public init(frame: CGRect) {
|
override public init(frame: CGRect) {
|
||||||
self.imageView = UIImageView()
|
self.imageView = UIImageView()
|
||||||
@ -23,11 +23,11 @@ public final class ReactionIconView: PortalSourceView {
|
|||||||
self.addSubview(self.imageView)
|
self.addSubview(self.imageView)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required public init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(size: CGSize, transition: ContainedViewLayoutTransition) {
|
public func update(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||||
transition.updateFrame(view: self.imageView, frame: CGRect(origin: CGPoint(), size: size))
|
transition.updateFrame(view: self.imageView, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,7 +42,6 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Counter: Equatable {
|
struct Counter: Equatable {
|
||||||
var frame: CGRect
|
|
||||||
var components: [CounterLayout.Component]
|
var components: [CounterLayout.Component]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +121,19 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let image = generateImage(layout.baseSize, rotatedContext: { size, context in
|
var totalComponentWidth: CGFloat = 0.0
|
||||||
|
if let counter = layout.counter {
|
||||||
|
for component in counter.components {
|
||||||
|
totalComponentWidth += component.bounds.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageWidth = layout.baseSize.width
|
||||||
|
while imageWidth < layout.baseSize.height / 2.0 + 1.0 + totalComponentWidth + 8.0 {
|
||||||
|
imageWidth += 2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let image = generateImage(CGSize(width: imageWidth, height: layout.baseSize.height), rotatedContext: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
UIGraphicsPushContext(context)
|
UIGraphicsPushContext(context)
|
||||||
|
|
||||||
@ -143,15 +154,18 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - size.height, y: 0.0), size: CGSize(width: size.height, height: size.height)))
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - size.height, y: 0.0), size: CGSize(width: size.height, height: size.height)))
|
||||||
context.fill(CGRect(origin: CGPoint(x: size.height / 2.0, y: 0.0), size: CGSize(width: size.width - size.height, height: size.height)))
|
context.fill(CGRect(origin: CGPoint(x: size.height / 2.0, y: 0.0), size: CGSize(width: size.width - size.height, height: size.height)))
|
||||||
|
|
||||||
|
#if DEBUG && false
|
||||||
|
context.setFillColor(UIColor.blue.withAlphaComponent(0.5).cgColor)
|
||||||
|
context.fill(CGRect(origin: CGPoint(x: layout.baseSize.height / 2.0 + 1.0, y: 0.0), size: CGSize(width: size.width - (layout.baseSize.height / 2.0 + 1.0 + 8.0), height: size.height)))
|
||||||
|
#endif
|
||||||
|
|
||||||
if let counter = layout.counter {
|
if let counter = layout.counter {
|
||||||
context.setBlendMode(foregroundColor.alpha < 1.0 ? .copy : .normal)
|
let isForegroundTransparent = foregroundColor.alpha < 1.0
|
||||||
|
context.setBlendMode(isForegroundTransparent ? .copy : .normal)
|
||||||
|
|
||||||
var totalComponentWidth: CGFloat = 0.0
|
//let textAreaWidth = size.width - (layout.baseSize.height / 2.0 + 1.0 + 8.0)
|
||||||
for component in counter.components {
|
|
||||||
totalComponentWidth += component.bounds.width
|
|
||||||
}
|
|
||||||
|
|
||||||
var textOrigin: CGFloat = size.width - counter.frame.width - 8.0 + floorToScreenPixels((counter.frame.width - totalComponentWidth) / 2.0)
|
var textOrigin: CGFloat = layout.baseSize.height / 2.0 + 1.0
|
||||||
textOrigin = max(textOrigin, layout.baseSize.height / 2.0 + UIScreenPixel)
|
textOrigin = max(textOrigin, layout.baseSize.height / 2.0 + UIScreenPixel)
|
||||||
|
|
||||||
var rightTextOrigin = textOrigin + totalComponentWidth
|
var rightTextOrigin = textOrigin + totalComponentWidth
|
||||||
@ -186,15 +200,28 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
previousComponentVerticalOffset = -previousComponentVerticalOffset
|
previousComponentVerticalOffset = -previousComponentVerticalOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
let componentOrigin = rightTextOrigin - previousComponent.bounds.width
|
var componentOrigin = rightTextOrigin - previousComponent.bounds.width
|
||||||
let string = NSAttributedString(string: previousComponent.string, font: Font.medium(11.0), textColor: foregroundColor.mixedWith(backgroundColor, alpha: 1.0 - previousComponentAlpha))
|
componentOrigin = max(componentOrigin, layout.baseSize.height / 2.0 + UIScreenPixel)
|
||||||
|
let previousColor: UIColor
|
||||||
|
if isForegroundTransparent {
|
||||||
|
previousColor = foregroundColor.mixedWith(backgroundColor, alpha: 1.0 - previousComponentAlpha)
|
||||||
|
} else {
|
||||||
|
previousColor = foregroundColor.withMultipliedAlpha(previousComponentAlpha)
|
||||||
|
}
|
||||||
|
let string = NSAttributedString(string: previousComponent.string, font: Font.medium(11.0), textColor: previousColor)
|
||||||
string.draw(at: previousComponent.bounds.origin.offsetBy(dx: componentOrigin, dy: floorToScreenPixels(size.height - previousComponent.bounds.height) / 2.0 + previousComponentVerticalOffset))
|
string.draw(at: previousComponent.bounds.origin.offsetBy(dx: componentOrigin, dy: floorToScreenPixels(size.height - previousComponent.bounds.height) / 2.0 + previousComponentVerticalOffset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let componentOrigin = rightTextOrigin - component.bounds.width
|
let componentOrigin = rightTextOrigin - component.bounds.width
|
||||||
let string = NSAttributedString(string: component.string, font: Font.medium(11.0), textColor: foregroundColor.mixedWith(backgroundColor, alpha: 1.0 - componentAlpha))
|
let currentColor: UIColor
|
||||||
|
if isForegroundTransparent {
|
||||||
|
currentColor = foregroundColor.mixedWith(backgroundColor, alpha: 1.0 - componentAlpha)
|
||||||
|
} else {
|
||||||
|
currentColor = foregroundColor.withMultipliedAlpha(componentAlpha)
|
||||||
|
}
|
||||||
|
let string = NSAttributedString(string: component.string, font: Font.medium(11.0), textColor: currentColor)
|
||||||
string.draw(at: component.bounds.origin.offsetBy(dx: componentOrigin, dy: floorToScreenPixels(size.height - component.bounds.height) / 2.0 + componentVerticalOffset))
|
string.draw(at: component.bounds.origin.offsetBy(dx: componentOrigin, dy: floorToScreenPixels(size.height - component.bounds.height) / 2.0 + componentVerticalOffset))
|
||||||
|
|
||||||
rightTextOrigin -= component.bounds.width
|
rightTextOrigin -= component.bounds.width
|
||||||
@ -266,7 +293,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
|
|
||||||
resultComponents.append(Component(string: component, bounds: boundingRect))
|
resultComponents.append(Component(string: component, bounds: boundingRect))
|
||||||
|
|
||||||
if spec.stringComponents.count <= 2 {
|
if i == spec.stringComponents.count - 1 && component.count == 1 && component[component.startIndex].isNumber {
|
||||||
resultSize.width += CounterLayout.maxDigitWidth
|
resultSize.width += CounterLayout.maxDigitWidth
|
||||||
} else {
|
} else {
|
||||||
resultSize.width += boundingRect.width
|
resultSize.width += boundingRect.width
|
||||||
@ -296,9 +323,9 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
let sideInsets: CGFloat
|
let sideInsets: CGFloat
|
||||||
|
|
||||||
let imageFrame: CGRect
|
let imageFrame: CGRect
|
||||||
|
let imageSize: CGSize
|
||||||
|
|
||||||
let counterLayout: CounterLayout?
|
let counterLayout: CounterLayout?
|
||||||
let counterFrame: CGRect?
|
|
||||||
|
|
||||||
let backgroundLayout: ContainerButtonNode.Layout
|
let backgroundLayout: ContainerButtonNode.Layout
|
||||||
|
|
||||||
@ -309,8 +336,8 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
backgroundColor: UInt32,
|
backgroundColor: UInt32,
|
||||||
sideInsets: CGFloat,
|
sideInsets: CGFloat,
|
||||||
imageFrame: CGRect,
|
imageFrame: CGRect,
|
||||||
|
imageSize: CGSize,
|
||||||
counterLayout: CounterLayout?,
|
counterLayout: CounterLayout?,
|
||||||
counterFrame: CGRect?,
|
|
||||||
backgroundLayout: ContainerButtonNode.Layout,
|
backgroundLayout: ContainerButtonNode.Layout,
|
||||||
size: CGSize
|
size: CGSize
|
||||||
) {
|
) {
|
||||||
@ -318,18 +345,19 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
self.sideInsets = sideInsets
|
self.sideInsets = sideInsets
|
||||||
self.imageFrame = imageFrame
|
self.imageFrame = imageFrame
|
||||||
|
self.imageSize = imageSize
|
||||||
self.counterLayout = counterLayout
|
self.counterLayout = counterLayout
|
||||||
self.counterFrame = counterFrame
|
|
||||||
self.backgroundLayout = backgroundLayout
|
self.backgroundLayout = backgroundLayout
|
||||||
self.size = size
|
self.size = size
|
||||||
}
|
}
|
||||||
|
|
||||||
static func calculate(spec: Spec, currentLayout: Layout?) -> Layout {
|
static func calculate(spec: Spec, currentLayout: Layout?) -> Layout {
|
||||||
let sideInsets: CGFloat = 8.0
|
let sideInsets: CGFloat = 11.0
|
||||||
let height: CGFloat = 30.0
|
let height: CGFloat = 30.0
|
||||||
let spacing: CGFloat = 4.0
|
let spacing: CGFloat = 2.0
|
||||||
|
|
||||||
let defaultImageSize = CGSize(width: 26.0, height: 26.0)
|
let boundingImageSize = CGSize(width: 20.0, height: 20.0)
|
||||||
|
let defaultImageSize = CGSize(width: boundingImageSize.width + floor(boundingImageSize.width * 0.5 * 2.0), height: boundingImageSize.height + floor(boundingImageSize.height * 0.5 * 2.0))
|
||||||
let imageSize: CGSize
|
let imageSize: CGSize
|
||||||
if let file = spec.component.reaction.centerAnimation {
|
if let file = spec.component.reaction.centerAnimation {
|
||||||
imageSize = file.dimensions?.cgSize.aspectFitted(defaultImageSize) ?? defaultImageSize
|
imageSize = file.dimensions?.cgSize.aspectFitted(defaultImageSize) ?? defaultImageSize
|
||||||
@ -341,15 +369,20 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
for character in countString(Int64(spec.component.count)) {
|
for character in countString(Int64(spec.component.count)) {
|
||||||
counterComponents.append(String(character))
|
counterComponents.append(String(character))
|
||||||
}
|
}
|
||||||
|
#if DEBUG && false
|
||||||
|
counterComponents.removeAll()
|
||||||
|
for character in "42" {
|
||||||
|
counterComponents.append(String(character))
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
let backgroundColor = spec.component.isSelected ? spec.component.colors.selectedBackground : spec.component.colors.deselectedBackground
|
let backgroundColor = spec.component.isSelected ? spec.component.colors.selectedBackground : spec.component.colors.deselectedBackground
|
||||||
|
|
||||||
let imageFrame = CGRect(origin: CGPoint(x: sideInsets, y: floorToScreenPixels((height - imageSize.height) / 2.0)), size: imageSize)
|
let imageFrame = CGRect(origin: CGPoint(x: sideInsets + floorToScreenPixels((boundingImageSize.width - imageSize.width) / 2.0), y: floorToScreenPixels((height - imageSize.height) / 2.0)), size: imageSize)
|
||||||
|
|
||||||
var counterLayout: CounterLayout?
|
var counterLayout: CounterLayout?
|
||||||
var counterFrame: CGRect?
|
|
||||||
|
|
||||||
var size = CGSize(width: imageSize.width + sideInsets * 2.0, height: height)
|
var size = CGSize(width: boundingImageSize.width + sideInsets * 2.0, height: height)
|
||||||
if !spec.component.avatarPeers.isEmpty {
|
if !spec.component.avatarPeers.isEmpty {
|
||||||
size.width += 4.0 + 24.0
|
size.width += 4.0 + 24.0
|
||||||
if spec.component.avatarPeers.count > 1 {
|
if spec.component.avatarPeers.count > 1 {
|
||||||
@ -372,7 +405,6 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
}
|
}
|
||||||
counterLayout = counterValue
|
counterLayout = counterValue
|
||||||
size.width += spacing + counterValue.size.width
|
size.width += spacing + counterValue.size.width
|
||||||
counterFrame = CGRect(origin: CGPoint(x: size.width - sideInsets - counterValue.size.width, y: floorToScreenPixels((height - counterValue.size.height) / 2.0)), size: counterValue.size)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let backgroundColors = ReactionButtonAsyncNode.ContainerButtonNode.Colors(
|
let backgroundColors = ReactionButtonAsyncNode.ContainerButtonNode.Colors(
|
||||||
@ -382,15 +414,14 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
extractedForeground: spec.component.colors.extractedForeground
|
extractedForeground: spec.component.colors.extractedForeground
|
||||||
)
|
)
|
||||||
var backgroundCounter: ReactionButtonAsyncNode.ContainerButtonNode.Counter?
|
var backgroundCounter: ReactionButtonAsyncNode.ContainerButtonNode.Counter?
|
||||||
if let counterLayout = counterLayout, let counterFrame = counterFrame {
|
if let counterLayout = counterLayout {
|
||||||
backgroundCounter = ReactionButtonAsyncNode.ContainerButtonNode.Counter(
|
backgroundCounter = ReactionButtonAsyncNode.ContainerButtonNode.Counter(
|
||||||
frame: counterFrame,
|
|
||||||
components: counterLayout.components
|
components: counterLayout.components
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
let backgroundLayout = ContainerButtonNode.Layout(
|
let backgroundLayout = ContainerButtonNode.Layout(
|
||||||
colors: backgroundColors,
|
colors: backgroundColors,
|
||||||
baseSize: CGSize(width: height + 18.0, height: height),
|
baseSize: CGSize(width: height + 2.0, height: height),
|
||||||
counter: backgroundCounter
|
counter: backgroundCounter
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -399,8 +430,8 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
sideInsets: sideInsets,
|
sideInsets: sideInsets,
|
||||||
imageFrame: imageFrame,
|
imageFrame: imageFrame,
|
||||||
|
imageSize: boundingImageSize,
|
||||||
counterLayout: counterLayout,
|
counterLayout: counterLayout,
|
||||||
counterFrame: counterFrame,
|
|
||||||
backgroundLayout: backgroundLayout,
|
backgroundLayout: backgroundLayout,
|
||||||
size: size
|
size: size
|
||||||
)
|
)
|
||||||
@ -492,7 +523,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
|
|
||||||
if self.layout?.spec.component.reaction != layout.spec.component.reaction {
|
if self.layout?.spec.component.reaction != layout.spec.component.reaction {
|
||||||
if let file = layout.spec.component.reaction.centerAnimation {
|
if let file = layout.spec.component.reaction.centerAnimation {
|
||||||
self.iconImageDisposable.set((reactionStaticImage(context: layout.spec.component.context, animation: file, pixelSize: CGSize(width: 72.0, height: 72.0))
|
self.iconImageDisposable.set((reactionStaticImage(context: layout.spec.component.context, animation: file, pixelSize: CGSize(width: 64.0 * UIScreenScale, height: 64.0 * UIScreenScale))
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] data in
|
|> deliverOnMainQueue).start(next: { [weak self] data in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -526,7 +557,7 @@ public final class ReactionButtonAsyncNode: ContextControllerSourceNode {
|
|||||||
animation: animation,
|
animation: animation,
|
||||||
synchronousLoad: false
|
synchronousLoad: false
|
||||||
)
|
)
|
||||||
animation.animator.updateFrame(layer: avatarsView.layer, frame: CGRect(origin: CGPoint(x: layout.imageFrame.maxX + 4.0, y: floorToScreenPixels((layout.size.height - avatarsSize.height) / 2.0)), size: CGSize(width: avatarsSize.width, height: avatarsSize.height)), completion: nil)
|
animation.animator.updateFrame(layer: avatarsView.layer, frame: CGRect(origin: CGPoint(x: floorToScreenPixels(layout.imageFrame.midX + layout.imageSize.width / 2.0) + 4.0, y: floorToScreenPixels((layout.size.height - avatarsSize.height) / 2.0)), size: CGSize(width: avatarsSize.width, height: avatarsSize.height)), completion: nil)
|
||||||
} else if let avatarsView = self.avatarsView {
|
} else if let avatarsView = self.avatarsView {
|
||||||
self.avatarsView = nil
|
self.avatarsView = nil
|
||||||
if animation.isAnimated {
|
if animation.isAnimated {
|
||||||
|
@ -13,7 +13,7 @@ import RLottieBinding
|
|||||||
import GZip
|
import GZip
|
||||||
|
|
||||||
public func reactionStaticImage(context: AccountContext, animation: TelegramMediaFile, pixelSize: CGSize) -> Signal<EngineMediaResource.ResourceData, NoError> {
|
public func reactionStaticImage(context: AccountContext, animation: TelegramMediaFile, pixelSize: CGSize) -> Signal<EngineMediaResource.ResourceData, NoError> {
|
||||||
return context.engine.resources.custom(id: "\(animation.resource.id.stringRepresentation):reaction-static-v7", fetch: EngineMediaResource.Fetch {
|
return context.engine.resources.custom(id: "\(animation.resource.id.stringRepresentation):reaction-static-\(pixelSize.width)x\(pixelSize.height)-v10", fetch: EngineMediaResource.Fetch {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: MediaResourceReference.standalone(resource: animation.resource)).start()
|
let fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: MediaResourceReference.standalone(resource: animation.resource)).start()
|
||||||
let dataDisposable = context.account.postbox.mediaBox.resourceData(animation.resource).start(next: { data in
|
let dataDisposable = context.account.postbox.mediaBox.resourceData(animation.resource).start(next: { data in
|
||||||
@ -30,25 +30,14 @@ public func reactionStaticImage(context: AccountContext, animation: TelegramMedi
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let innerInsets = UIEdgeInsets(top: 2.4, left: 2.4, bottom: 2.4, right: 2.4)
|
let renderContext = DrawingContext(size: pixelSize, scale: 1.0, clear: true)
|
||||||
let renderContext = DrawingContext(size: CGSize(width: floor(pixelSize.width * (1.0 + innerInsets.left + innerInsets.right)), height: floor(pixelSize.height * (1.0 + innerInsets.bottom + innerInsets.top))), scale: 1.0, clear: true)
|
|
||||||
|
|
||||||
instance.renderFrame(with: Int32(instance.frameCount - 1), into: renderContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(renderContext.size.width * renderContext.scale), height: Int32(renderContext.size.height * renderContext.scale), bytesPerRow: Int32(renderContext.bytesPerRow))
|
instance.renderFrame(with: Int32(instance.frameCount - 1), into: renderContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(renderContext.size.width * renderContext.scale), height: Int32(renderContext.size.height * renderContext.scale), bytesPerRow: Int32(renderContext.bytesPerRow))
|
||||||
|
|
||||||
guard let image = renderContext.generateImage() else {
|
guard let image = renderContext.generateImage() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
guard let pngData = image.pngData() else {
|
||||||
let clippingContext = DrawingContext(size: pixelSize, scale: 1.0, clear: true)
|
|
||||||
clippingContext.withContext { context in
|
|
||||||
UIGraphicsPushContext(context)
|
|
||||||
|
|
||||||
image.draw(at: CGPoint(x: -innerInsets.left * pixelSize.width, y: -innerInsets.top * pixelSize.height))
|
|
||||||
|
|
||||||
UIGraphicsPopContext()
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let pngData = clippingContext.generateImage()?.pngData() else {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -840,6 +840,10 @@ public class TextNode: ASDisplayNode {
|
|||||||
self.clipsToBounds = false
|
self.clipsToBounds = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public func didLoad() {
|
||||||
|
super.didLoad()
|
||||||
|
}
|
||||||
|
|
||||||
public func attributesAtPoint(_ point: CGPoint, orNearest: Bool = false) -> (Int, [NSAttributedString.Key: Any])? {
|
public func attributesAtPoint(_ point: CGPoint, orNearest: Bool = false) -> (Int, [NSAttributedString.Key: Any])? {
|
||||||
if let cachedLayout = self.cachedLayout {
|
if let cachedLayout = self.cachedLayout {
|
||||||
return cachedLayout.attributesAtPoint(point, orNearest: orNearest)
|
return cachedLayout.attributesAtPoint(point, orNearest: orNearest)
|
||||||
|
@ -209,6 +209,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let rowHeight: CGFloat = 30.0
|
let rowHeight: CGFloat = 30.0
|
||||||
|
|
||||||
let visibleBounds = self.scrollNode.view.bounds
|
let visibleBounds = self.scrollNode.view.bounds
|
||||||
|
let appearBounds = self.scrollNode.view.bounds.insetBy(dx: 16.0, dy: 0.0)
|
||||||
self.previewingItemContainer.bounds = visibleBounds
|
self.previewingItemContainer.bounds = visibleBounds
|
||||||
|
|
||||||
let highlightedReactionIndex = self.items.firstIndex(where: { $0.reaction == self.highlightedReaction })
|
let highlightedReactionIndex = self.items.firstIndex(where: { $0.reaction == self.highlightedReaction })
|
||||||
@ -223,9 +224,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
var baseItemFrame = CGRect(origin: CGPoint(x: sideInset + column * (itemSize + itemSpacing), y: verticalInset + floor((rowHeight - itemSize) / 2.0) + itemOffsetY), size: CGSize(width: itemSize, height: itemSize))
|
var baseItemFrame = CGRect(origin: CGPoint(x: sideInset + column * (itemSize + itemSpacing), y: verticalInset + floor((rowHeight - itemSize) / 2.0) + itemOffsetY), size: CGSize(width: itemSize, height: itemSize))
|
||||||
if let highlightedReactionIndex = highlightedReactionIndex {
|
if let highlightedReactionIndex = highlightedReactionIndex {
|
||||||
if i > highlightedReactionIndex {
|
if i > highlightedReactionIndex {
|
||||||
baseItemFrame.origin.x += 4.0
|
baseItemFrame.origin.x += 8.0
|
||||||
} else if i == highlightedReactionIndex {
|
} else if i == highlightedReactionIndex {
|
||||||
baseItemFrame.origin.x += 2.0
|
baseItemFrame.origin.x += 4.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +239,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let updatedSize = CGSize(width: floor(itemFrame.width * 1.66), height: floor(itemFrame.height * 1.66))
|
let updatedSize = CGSize(width: floor(itemFrame.width * 1.66), height: floor(itemFrame.height * 1.66))
|
||||||
itemFrame = CGRect(origin: CGPoint(x: itemFrame.midX - updatedSize.width / 2.0, y: itemFrame.maxY + 4.0 - updatedSize.height), size: updatedSize)
|
itemFrame = CGRect(origin: CGPoint(x: itemFrame.midX - updatedSize.width / 2.0, y: itemFrame.maxY + 4.0 - updatedSize.height), size: updatedSize)
|
||||||
isPreviewing = true
|
isPreviewing = true
|
||||||
|
} else if self.highlightedReaction != nil {
|
||||||
|
let updatedSize = CGSize(width: floor(itemFrame.width * 0.9), height: floor(itemFrame.height * 0.9))
|
||||||
|
itemFrame = CGRect(origin: CGPoint(x: itemFrame.midX - updatedSize.width / 2.0, y: itemFrame.midY - updatedSize.height / 2.0), size: updatedSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
var animateIn = false
|
var animateIn = false
|
||||||
@ -276,7 +280,13 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
itemNode.updateLayout(size: itemFrame.size, isExpanded: false, isPreviewing: isPreviewing, transition: transition)
|
itemNode.updateLayout(size: itemFrame.size, isExpanded: false, isPreviewing: isPreviewing, transition: transition)
|
||||||
|
|
||||||
if animateIn {
|
if animateIn {
|
||||||
itemNode.appear(animated: !self.context.sharedContext.currentPresentationData.with({ $0 }).reduceMotion)
|
if !self.context.sharedContext.currentPresentationData.with({ $0 }).reduceMotion {
|
||||||
|
if appearBounds.intersects(baseItemFrame) {
|
||||||
|
itemNode.appear(animated: true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
itemNode.appear(animated: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,15 +508,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
let selfSourceRect = itemNode.view.convert(itemNode.view.bounds, to: self.view)
|
let selfSourceRect = itemNode.view.convert(itemNode.view.bounds, to: self.view)
|
||||||
let selfTargetRect = self.view.convert(targetView.bounds, from: targetView)
|
let selfTargetRect = self.view.convert(targetView.bounds, from: targetView)
|
||||||
|
|
||||||
let expandedSize: CGSize
|
let expandedSize: CGSize = selfTargetRect.size
|
||||||
if targetView.bounds.width < 20.0 {
|
|
||||||
expandedSize = CGSize(width: 21.0, height: 21.0)
|
|
||||||
} else {
|
|
||||||
expandedSize = CGSize(width: 32.0, height: 32.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var expandedFrame = CGRect(origin: CGPoint(x: floor(selfTargetRect.midX - expandedSize.width / 2.0), y: floor(selfTargetRect.midY - expandedSize.height / 2.0)), size: expandedSize)
|
let expandedFrame = CGRect(origin: CGPoint(x: selfTargetRect.midX - expandedSize.width / 2.0, y: selfTargetRect.midY - expandedSize.height / 2.0), size: expandedSize)
|
||||||
expandedFrame.origin.y += UIScreenPixel
|
|
||||||
|
|
||||||
let effectFrame = expandedFrame.insetBy(dx: -60.0, dy: -60.0)
|
let effectFrame = expandedFrame.insetBy(dx: -60.0, dy: -60.0)
|
||||||
|
|
||||||
@ -727,6 +731,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
public final class StandaloneReactionAnimation: ASDisplayNode {
|
public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||||
private var itemNode: ReactionNode? = nil
|
private var itemNode: ReactionNode? = nil
|
||||||
|
private var itemNodeIsEmbedded: Bool = false
|
||||||
private let hapticFeedback = HapticFeedback()
|
private let hapticFeedback = HapticFeedback()
|
||||||
private var isCancelled: Bool = false
|
private var isCancelled: Bool = false
|
||||||
|
|
||||||
@ -760,24 +765,25 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.itemNode = itemNode
|
self.itemNode = itemNode
|
||||||
|
|
||||||
self.addSubnode(itemNode)
|
if let targetView = targetView as? ReactionIconView {
|
||||||
|
self.itemNodeIsEmbedded = true
|
||||||
if hideNode {
|
targetView.addSubnode(itemNode)
|
||||||
targetView.isHidden = true
|
|
||||||
|
targetView.imageView.isHidden = true
|
||||||
|
} else {
|
||||||
|
self.addSubnode(itemNode)
|
||||||
|
|
||||||
|
if hideNode {
|
||||||
|
targetView.isHidden = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
itemNode.isExtracted = true
|
itemNode.isExtracted = true
|
||||||
let selfTargetRect = self.view.convert(targetView.bounds, from: targetView)
|
let selfTargetRect = self.view.convert(targetView.bounds, from: targetView)
|
||||||
|
|
||||||
let expandedSize: CGSize
|
let expandedSize: CGSize = selfTargetRect.size
|
||||||
if targetView.bounds.width < 20.0 {
|
|
||||||
expandedSize = CGSize(width: 21.0, height: 21.0)
|
|
||||||
} else {
|
|
||||||
expandedSize = CGSize(width: 32.0, height: 32.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var expandedFrame = CGRect(origin: CGPoint(x: floor(selfTargetRect.midX - expandedSize.width / 2.0), y: floor(selfTargetRect.midY - expandedSize.height / 2.0)), size: expandedSize)
|
let expandedFrame = CGRect(origin: CGPoint(x: selfTargetRect.midX - expandedSize.width / 2.0, y: selfTargetRect.midY - expandedSize.height / 2.0), size: expandedSize)
|
||||||
expandedFrame.origin.y += UIScreenPixel
|
|
||||||
|
|
||||||
let effectFrame = expandedFrame.insetBy(dx: -60.0, dy: -60.0)
|
let effectFrame = expandedFrame.insetBy(dx: -60.0, dy: -60.0)
|
||||||
|
|
||||||
@ -789,17 +795,21 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
sourceSnapshotView?.removeFromSuperview()
|
sourceSnapshotView?.removeFromSuperview()
|
||||||
})
|
})
|
||||||
|
|
||||||
self.addSubnode(itemNode)
|
if self.itemNodeIsEmbedded {
|
||||||
itemNode.frame = expandedFrame
|
itemNode.frame = targetView.bounds
|
||||||
itemNode.updateLayout(size: expandedFrame.size, isExpanded: true, isPreviewing: false, transition: .immediate)
|
} else {
|
||||||
|
itemNode.frame = expandedFrame
|
||||||
itemNode.layer.animateSpring(from: (selfTargetRect.width / expandedFrame.width) as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
|
||||||
|
itemNode.layer.animateSpring(from: (selfTargetRect.width / expandedFrame.width) as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||||
if targetView.bounds.width < 20.0 {
|
|
||||||
itemNode.layer.animateScale(from: 0.01, to: 1.0, duration: 0.15)
|
if targetView.bounds.width < 25.0 {
|
||||||
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
itemNode.layer.animateScale(from: 0.01, to: 1.0, duration: 0.15)
|
||||||
|
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemNode.updateLayout(size: expandedFrame.size, isExpanded: true, isPreviewing: false, transition: .immediate)
|
||||||
|
|
||||||
let additionalAnimationNode = AnimatedStickerNode()
|
let additionalAnimationNode = AnimatedStickerNode()
|
||||||
additionalAnimationNode.setup(source: AnimatedStickerResourceSource(account: itemNode.context.account, resource: itemNode.item.applicationAnimation.resource), width: Int(effectFrame.width * 2.0), height: Int(effectFrame.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: itemNode.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(itemNode.item.applicationAnimation.resource.id)))
|
additionalAnimationNode.setup(source: AnimatedStickerResourceSource(account: itemNode.context.account, resource: itemNode.item.applicationAnimation.resource), width: Int(effectFrame.width * 2.0), height: Int(effectFrame.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: itemNode.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(itemNode.item.applicationAnimation.resource.id)))
|
||||||
additionalAnimationNode.frame = effectFrame
|
additionalAnimationNode.frame = effectFrame
|
||||||
@ -824,10 +834,24 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
intermediateCompletion()
|
intermediateCompletion()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.animateFromItemNodeToReaction(itemNode: itemNode, targetView: targetView, hideNode: hideNode, completion: {
|
|
||||||
mainAnimationCompleted = true
|
if let targetView = strongSelf.targetView {
|
||||||
intermediateCompletion()
|
if let targetView = targetView as? ReactionIconView {
|
||||||
})
|
targetView.imageView.isHidden = false
|
||||||
|
} else {
|
||||||
|
if strongSelf.hideNode {
|
||||||
|
targetView.alpha = 1.0
|
||||||
|
targetView.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strongSelf.itemNodeIsEmbedded {
|
||||||
|
strongSelf.itemNode?.removeFromSupernode()
|
||||||
|
}
|
||||||
|
|
||||||
|
mainAnimationCompleted = true
|
||||||
|
intermediateCompletion()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,17 +862,14 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
beginDismissAnimation()
|
beginDismissAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1 * UIView.animationDurationFactor(), execute: {
|
additionalAnimationNode.visibility = true
|
||||||
additionalAnimationNode.visibility = true
|
|
||||||
})
|
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0, execute: {
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0, execute: {
|
||||||
beginDismissAnimation()
|
beginDismissAnimation()
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func animateFromItemNodeToReaction(itemNode: ReactionNode, targetView: UIView, hideNode: Bool, completion: @escaping () -> Void) {
|
/*private func animateFromItemNodeToReaction(itemNode: ReactionNode, targetView: UIView, hideNode: Bool, completion: @escaping () -> Void) {
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
if hideNode {
|
if hideNode {
|
||||||
targetView.alpha = 1.0
|
targetView.alpha = 1.0
|
||||||
@ -903,7 +924,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
})
|
})
|
||||||
|
|
||||||
itemNode.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 1.0) / itemNode.bounds.width, duration: duration, removeOnCompletion: false)
|
itemNode.layer.animateScale(from: 1.0, to: (targetSnapshotView.bounds.width * 1.0) / itemNode.bounds.width, duration: duration, removeOnCompletion: false)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
public func addRelativeContentOffset(_ offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
public func addRelativeContentOffset(_ offset: CGPoint, transition: ContainedViewLayoutTransition) {
|
||||||
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: offset.y)
|
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: offset.y)
|
||||||
@ -914,8 +935,16 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||||||
self.isCancelled = true
|
self.isCancelled = true
|
||||||
|
|
||||||
if let targetView = self.targetView, self.hideNode {
|
if let targetView = self.targetView, self.hideNode {
|
||||||
targetView.alpha = 1.0
|
if let targetView = targetView as? ReactionIconView {
|
||||||
targetView.isHidden = false
|
targetView.imageView.isHidden = false
|
||||||
|
} else {
|
||||||
|
targetView.alpha = 1.0
|
||||||
|
targetView.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.itemNodeIsEmbedded {
|
||||||
|
self.itemNode?.removeFromSupernode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,8 +120,7 @@ final class ReactionNode: ASDisplayNode {
|
|||||||
var animationFrame = CGRect(origin: CGPoint(x: floor((intrinsicSize.width - animationDisplaySize.width) / 2.0), y: floor((intrinsicSize.height - animationDisplaySize.height) / 2.0)), size: animationDisplaySize)
|
var animationFrame = CGRect(origin: CGPoint(x: floor((intrinsicSize.width - animationDisplaySize.width) / 2.0), y: floor((intrinsicSize.height - animationDisplaySize.height) / 2.0)), size: animationDisplaySize)
|
||||||
animationFrame.origin.y = floor(animationFrame.origin.y + animationFrame.height * offsetFactor)
|
animationFrame.origin.y = floor(animationFrame.origin.y + animationFrame.height * offsetFactor)
|
||||||
|
|
||||||
let expandedInset: CGFloat = floor(size.width / 32.0 * 60.0)
|
let expandedAnimationFrame = animationFrame
|
||||||
let expandedAnimationFrame = animationFrame.insetBy(dx: -expandedInset, dy: -expandedInset)
|
|
||||||
|
|
||||||
if isExpanded, self.animationNode == nil {
|
if isExpanded, self.animationNode == nil {
|
||||||
let animationNode = AnimatedStickerNode()
|
let animationNode = AnimatedStickerNode()
|
||||||
@ -176,16 +175,19 @@ final class ReactionNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.17, execute: {
|
||||||
|
animationNode.visibility = true
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
if let stillAnimationNode = self.stillAnimationNode {
|
if let stillAnimationNode = self.stillAnimationNode {
|
||||||
self.stillAnimationNode = nil
|
self.stillAnimationNode = nil
|
||||||
stillAnimationNode.removeFromSupernode()
|
stillAnimationNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
self.staticAnimationNode.isHidden = true
|
self.staticAnimationNode.isHidden = true
|
||||||
}
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.17, execute: {
|
|
||||||
animationNode.visibility = true
|
animationNode.visibility = true
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.validSize != size {
|
if self.validSize != size {
|
||||||
|
@ -170,20 +170,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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
||||||
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)]
|
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: 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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -149,7 +149,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, backgroundNode: currentBackgroundNode, availableReactions: 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: currentBackgroundNode, availableReactions: nil, isCentered: false)
|
||||||
|
|
||||||
var node: ListViewItemNode?
|
var node: ListViewItemNode?
|
||||||
if let current = currentNode {
|
if let current = currentNode {
|
||||||
|
@ -16,13 +16,16 @@ import ReactionImageComponent
|
|||||||
private final class QuickReactionSetupControllerArguments {
|
private final class QuickReactionSetupControllerArguments {
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let selectItem: (String) -> Void
|
let selectItem: (String) -> Void
|
||||||
|
let toggleReaction: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
selectItem: @escaping (String) -> Void
|
selectItem: @escaping (String) -> Void,
|
||||||
|
toggleReaction: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.selectItem = selectItem
|
self.selectItem = selectItem
|
||||||
|
self.toggleReaction = toggleReaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +144,10 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
|||||||
dateTimeFormat: dateTimeFormat,
|
dateTimeFormat: dateTimeFormat,
|
||||||
nameDisplayOrder: nameDisplayOrder,
|
nameDisplayOrder: nameDisplayOrder,
|
||||||
availableReactions: availableReactions,
|
availableReactions: availableReactions,
|
||||||
reaction: reaction
|
reaction: reaction,
|
||||||
|
toggleReaction: {
|
||||||
|
arguments.toggleReaction()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
case let .demoDescription(text):
|
case let .demoDescription(text):
|
||||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||||
@ -167,13 +173,15 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private struct QuickReactionSetupControllerState: Equatable {
|
private struct QuickReactionSetupControllerState: Equatable {
|
||||||
|
var hasReaction: Bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private func quickReactionSetupControllerEntries(
|
private func quickReactionSetupControllerEntries(
|
||||||
presentationData: PresentationData,
|
presentationData: PresentationData,
|
||||||
availableReactions: AvailableReactions?,
|
availableReactions: AvailableReactions?,
|
||||||
images: [String: UIImage],
|
images: [String: UIImage],
|
||||||
reactionSettings: ReactionSettings
|
reactionSettings: ReactionSettings,
|
||||||
|
state: QuickReactionSetupControllerState
|
||||||
) -> [QuickReactionSetupControllerEntry] {
|
) -> [QuickReactionSetupControllerEntry] {
|
||||||
var entries: [QuickReactionSetupControllerEntry] = []
|
var entries: [QuickReactionSetupControllerEntry] = []
|
||||||
|
|
||||||
@ -186,7 +194,7 @@ private func quickReactionSetupControllerEntries(
|
|||||||
dateTimeFormat: presentationData.dateTimeFormat,
|
dateTimeFormat: presentationData.dateTimeFormat,
|
||||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||||
availableReactions: availableReactions,
|
availableReactions: availableReactions,
|
||||||
reaction: reactionSettings.quickReaction
|
reaction: state.hasReaction ? reactionSettings.quickReaction : nil
|
||||||
))
|
))
|
||||||
entries.append(.demoDescription(presentationData.strings.Settings_QuickReactionSetup_DemoInfo))
|
entries.append(.demoDescription(presentationData.strings.Settings_QuickReactionSetup_DemoInfo))
|
||||||
|
|
||||||
@ -224,14 +232,24 @@ public func quickReactionSetupController(
|
|||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
let _ = dismissImpl
|
let _ = dismissImpl
|
||||||
|
|
||||||
let _ = updateState
|
|
||||||
|
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
let arguments = QuickReactionSetupControllerArguments(
|
let arguments = QuickReactionSetupControllerArguments(
|
||||||
context: context,
|
context: context,
|
||||||
selectItem: { reaction in
|
selectItem: { reaction in
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
state.hasReaction = false
|
||||||
|
return state
|
||||||
|
}
|
||||||
let _ = context.engine.stickers.updateQuickReaction(reaction: reaction).start()
|
let _ = context.engine.stickers.updateQuickReaction(reaction: reaction).start()
|
||||||
|
},
|
||||||
|
toggleReaction: {
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
state.hasReaction = !state.hasReaction
|
||||||
|
return state
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -297,14 +315,15 @@ public func quickReactionSetupController(
|
|||||||
images
|
images
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, _, availableReactions, settings, images -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> map { presentationData, state, availableReactions, settings, images -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||||
let title: String = presentationData.strings.Settings_QuickReactionSetup_Title
|
let title: String = presentationData.strings.Settings_QuickReactionSetup_Title
|
||||||
|
|
||||||
let entries = quickReactionSetupControllerEntries(
|
let entries = quickReactionSetupControllerEntries(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
availableReactions: availableReactions,
|
availableReactions: availableReactions,
|
||||||
images: images,
|
images: images,
|
||||||
reactionSettings: settings
|
reactionSettings: settings,
|
||||||
|
state: state
|
||||||
)
|
)
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(
|
let controllerState = ItemListControllerState(
|
||||||
|
@ -11,7 +11,6 @@ import ItemListUI
|
|||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
import AccountContext
|
import AccountContext
|
||||||
import WallpaperBackgroundNode
|
import WallpaperBackgroundNode
|
||||||
import AvatarNode
|
|
||||||
import ReactionSelectionNode
|
import ReactionSelectionNode
|
||||||
|
|
||||||
class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
||||||
@ -26,8 +25,9 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
|||||||
let nameDisplayOrder: PresentationPersonNameOrder
|
let nameDisplayOrder: PresentationPersonNameOrder
|
||||||
let availableReactions: AvailableReactions?
|
let availableReactions: AvailableReactions?
|
||||||
let reaction: String?
|
let reaction: String?
|
||||||
|
let toggleReaction: () -> Void
|
||||||
|
|
||||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: String?) {
|
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: String?, toggleReaction: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
@ -39,6 +39,7 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
|||||||
self.nameDisplayOrder = nameDisplayOrder
|
self.nameDisplayOrder = nameDisplayOrder
|
||||||
self.availableReactions = availableReactions
|
self.availableReactions = availableReactions
|
||||||
self.reaction = reaction
|
self.reaction = reaction
|
||||||
|
self.toggleReaction = toggleReaction
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
@ -80,7 +81,6 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
private let maskNode: ASImageNode
|
private let maskNode: ASImageNode
|
||||||
private let avatarNode: ASImageNode
|
|
||||||
|
|
||||||
private let containerNode: ASDisplayNode
|
private let containerNode: ASDisplayNode
|
||||||
|
|
||||||
@ -98,8 +98,6 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
self.maskNode = ASImageNode()
|
self.maskNode = ASImageNode()
|
||||||
|
|
||||||
self.avatarNode = ASImageNode()
|
|
||||||
|
|
||||||
self.containerNode = ASDisplayNode()
|
self.containerNode = ASDisplayNode()
|
||||||
self.containerNode.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
self.containerNode.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
@ -107,7 +105,6 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
self.clipsToBounds = true
|
self.clipsToBounds = true
|
||||||
|
|
||||||
self.addSubnode(self.avatarNode)
|
|
||||||
self.addSubnode(self.containerNode)
|
self.addSubnode(self.containerNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,45 +124,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
|
||||||
switch gesture {
|
switch gesture {
|
||||||
case .doubleTap:
|
case .doubleTap:
|
||||||
if let item = self.item, let updatedReaction = item.reaction, let availableReactions = item.availableReactions, let messageNode = self.messageNode as? ChatMessageItemNodeProtocol {
|
self.item?.toggleReaction()
|
||||||
if let targetView = messageNode.targetReactionView(value: updatedReaction) {
|
|
||||||
for reaction in availableReactions.reactions {
|
|
||||||
if reaction.value == updatedReaction {
|
|
||||||
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
|
|
||||||
standaloneReactionAnimation.cancel()
|
|
||||||
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
|
||||||
standaloneReactionAnimation?.removeFromSupernode()
|
|
||||||
})
|
|
||||||
self.standaloneReactionAnimation = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if let supernode = self.supernode {
|
|
||||||
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
|
||||||
self.standaloneReactionAnimation = standaloneReactionAnimation
|
|
||||||
|
|
||||||
supernode.addSubnode(standaloneReactionAnimation)
|
|
||||||
standaloneReactionAnimation.frame = supernode.bounds
|
|
||||||
standaloneReactionAnimation.animateReactionSelection(
|
|
||||||
context: item.context, theme: item.theme, reaction: ReactionContextItem(
|
|
||||||
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
|
||||||
appearAnimation: reaction.appearAnimation,
|
|
||||||
stillAnimation: reaction.selectAnimation,
|
|
||||||
listAnimation: reaction.activateAnimation,
|
|
||||||
applicationAnimation: reaction.effectAnimation
|
|
||||||
),
|
|
||||||
targetView: targetView,
|
|
||||||
hideNode: true,
|
|
||||||
completion: { [weak standaloneReactionAnimation] in
|
|
||||||
standaloneReactionAnimation?.removeFromSupernode()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -175,9 +134,59 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func beginReactionAnimation() {
|
||||||
|
if let item = self.item, let updatedReaction = item.reaction, let availableReactions = item.availableReactions, let messageNode = self.messageNode as? ChatMessageItemNodeProtocol {
|
||||||
|
if let targetView = messageNode.targetReactionView(value: updatedReaction) {
|
||||||
|
for reaction in availableReactions.reactions {
|
||||||
|
guard let centerAnimation = reaction.centerAnimation else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if reaction.value == updatedReaction {
|
||||||
|
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
|
||||||
|
standaloneReactionAnimation.cancel()
|
||||||
|
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
||||||
|
standaloneReactionAnimation?.removeFromSupernode()
|
||||||
|
})
|
||||||
|
self.standaloneReactionAnimation = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if let supernode = self.supernode {
|
||||||
|
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
||||||
|
self.standaloneReactionAnimation = standaloneReactionAnimation
|
||||||
|
|
||||||
|
supernode.addSubnode(standaloneReactionAnimation)
|
||||||
|
standaloneReactionAnimation.frame = supernode.bounds
|
||||||
|
standaloneReactionAnimation.animateReactionSelection(
|
||||||
|
context: item.context, theme: item.theme, reaction: ReactionContextItem(
|
||||||
|
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
||||||
|
appearAnimation: reaction.appearAnimation,
|
||||||
|
stillAnimation: reaction.selectAnimation,
|
||||||
|
listAnimation: centerAnimation,
|
||||||
|
applicationAnimation: aroundAnimation
|
||||||
|
),
|
||||||
|
targetView: targetView,
|
||||||
|
hideNode: true,
|
||||||
|
completion: { [weak standaloneReactionAnimation] in
|
||||||
|
standaloneReactionAnimation?.removeFromSupernode()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ReactionChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
func asyncLayout() -> (_ item: ReactionChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let currentNode = self.messageNode
|
let currentNode = self.messageNode
|
||||||
|
|
||||||
|
let previousItem = self.item
|
||||||
var currentBackgroundNode = self.backgroundNode
|
var currentBackgroundNode = self.backgroundNode
|
||||||
|
|
||||||
return { item, params, neighbors in
|
return { item, params, neighbors in
|
||||||
@ -190,13 +199,12 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
let insets: UIEdgeInsets
|
let insets: UIEdgeInsets
|
||||||
let separatorHeight = UIScreenPixel
|
let separatorHeight = UIScreenPixel
|
||||||
|
|
||||||
let chatPeerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(1))
|
|
||||||
let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2))
|
let userPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2))
|
||||||
|
let chatPeerId = userPeerId
|
||||||
|
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
let messages = SimpleDictionary<MessageId, Message>()
|
let messages = SimpleDictionary<MessageId, Message>()
|
||||||
|
|
||||||
peers[chatPeerId] = TelegramGroup(id: chatPeerId, title: "Chat", photo: [], participantCount: 1, role: .member, membership: .Member, flags: [], defaultBannedRights: nil, migrationReference: nil, creationDate: 1, version: 1)
|
|
||||||
peers[userPeerId] = TelegramUser(id: userPeerId, accessHash: nil, firstName: item.strings.Settings_QuickReactionSetup_DemoMessageAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
peers[userPeerId] = TelegramUser(id: userPeerId, accessHash: nil, firstName: item.strings.Settings_QuickReactionSetup_DemoMessageAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||||
|
|
||||||
let messageText = item.strings.Settings_QuickReactionSetup_DemoMessageText
|
let messageText = item.strings.Settings_QuickReactionSetup_DemoMessageText
|
||||||
@ -206,12 +214,12 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
attributes.append(ReactionsMessageAttribute(canViewList: false, reactions: [MessageReaction(value: reaction, count: 1, isSelected: true)], recentPeers: []))
|
attributes.append(ReactionsMessageAttribute(canViewList: false, reactions: [MessageReaction(value: reaction, count: 1, isSelected: true)], recentPeers: []))
|
||||||
}
|
}
|
||||||
|
|
||||||
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: chatPeerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[userPeerId], text: messageText, attributes: 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: currentBackgroundNode, availableReactions: item.availableReactions)
|
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: chatPeerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[userPeerId], text: messageText, attributes: 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: currentBackgroundNode, availableReactions: item.availableReactions, isCentered: true)
|
||||||
|
|
||||||
var node: ListViewItemNode?
|
var node: ListViewItemNode?
|
||||||
if let current = currentNode {
|
if let current = currentNode {
|
||||||
node = current
|
node = current
|
||||||
messageItem.updateNode(async: { $0() }, node: { return current }, params: params, previousItem: nil, nextItem: nil, animation: .None, completion: { (layout, apply) in
|
messageItem.updateNode(async: { $0() }, node: { return current }, params: params, previousItem: nil, nextItem: nil, animation: .System(duration: 0.3, transition: ControlledTransition(duration: 0.3, curve: .easeInOut, interactive: false)), completion: { (layout, apply) in
|
||||||
let nodeFrame = CGRect(origin: current.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
|
let nodeFrame = CGRect(origin: current.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||||
|
|
||||||
current.contentSize = layout.contentSize
|
current.contentSize = layout.contentSize
|
||||||
@ -228,7 +236,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
node?.isUserInteractionEnabled = false
|
node?.isUserInteractionEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentSize = CGSize(width: params.width, height: 8.0 + 8.0)
|
var contentSize = CGSize(width: params.width, height: 16.0 + 16.0)
|
||||||
if let node = node {
|
if let node = node {
|
||||||
contentSize.height += node.frame.size.height
|
contentSize.height += node.frame.size.height
|
||||||
}
|
}
|
||||||
@ -252,7 +260,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
|
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
|
||||||
|
|
||||||
var topOffset: CGFloat = 8.0
|
var topOffset: CGFloat = 16.0
|
||||||
if let node = node {
|
if let node = node {
|
||||||
strongSelf.messageNode = node
|
strongSelf.messageNode = node
|
||||||
if node.supernode == nil {
|
if node.supernode == nil {
|
||||||
@ -260,23 +268,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
node.updateFrame(CGRect(origin: CGPoint(x: 0.0, y: topOffset), size: node.frame.size), within: layout.contentSize)
|
node.updateFrame(CGRect(origin: CGPoint(x: 0.0, y: topOffset), size: node.frame.size), within: layout.contentSize)
|
||||||
|
|
||||||
let avatarSize: CGFloat = 34.0
|
|
||||||
if strongSelf.avatarNode.image == nil {
|
|
||||||
strongSelf.avatarNode.image = generateImage(CGSize(width: avatarSize, height: avatarSize), rotatedContext: { size, context in
|
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
||||||
context.addEllipse(in: CGRect(origin: CGPoint(), size: size))
|
|
||||||
context.clip()
|
|
||||||
UIGraphicsPushContext(context)
|
|
||||||
if let image = UIImage(bundleImageName: "Avatar/SampleAvatar1") {
|
|
||||||
image.draw(in: CGRect(origin: CGPoint(), size: size))
|
|
||||||
}
|
|
||||||
UIGraphicsPopContext()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
topOffset += node.frame.size.height
|
topOffset += node.frame.size.height
|
||||||
|
|
||||||
strongSelf.avatarNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 7.0, y: topOffset - avatarSize), size: CGSize(width: avatarSize, height: avatarSize))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
strongSelf.topStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
|
||||||
@ -333,6 +325,10 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
|||||||
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
||||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||||
|
|
||||||
|
if let previousItem = previousItem, previousItem.reaction != item.reaction {
|
||||||
|
strongSelf.beginReactionAnimation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -413,20 +413,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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
|
||||||
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)]
|
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: 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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
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, backgroundNode: self.chatBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
if case .regular = layout.metrics.widthClass {
|
if case .regular = layout.metrics.widthClass {
|
||||||
|
@ -1043,7 +1043,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
|||||||
return state
|
return state
|
||||||
}, animated: true)
|
}, animated: true)
|
||||||
}, clickThroughMessage: {
|
}, clickThroughMessage: {
|
||||||
}, backgroundNode: self.backgroundNode, availableReactions: nil)
|
}, backgroundNode: self.backgroundNode, availableReactions: nil, isCentered: false)
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +593,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, backgroundNode: self.wallpaperNode, availableReactions: 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, availableReactions: nil, isCentered: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
let width: CGFloat
|
let width: CGFloat
|
||||||
|
@ -160,7 +160,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, backgroundNode: currentBackgroundNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodes: [ListViewItemNode] = []
|
var nodes: [ListViewItemNode] = []
|
||||||
|
@ -1103,10 +1103,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, backgroundNode: self.nativeNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
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, backgroundNode: self.nativeNode, availableReactions: 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, availableReactions: nil, isCentered: false))
|
||||||
|
|
||||||
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 messageNodes = self.messageNodes {
|
if let messageNodes = self.messageNodes {
|
||||||
|
@ -1041,7 +1041,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, backgroundNode: nil, availableReactions: 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, availableReactions: nil, isCentered: false)]
|
||||||
|
|
||||||
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
|
||||||
|
@ -605,6 +605,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
strongSelf.commitPurposefulAction()
|
strongSelf.commitPurposefulAction()
|
||||||
strongSelf.dismissAllTooltips()
|
strongSelf.dismissAllTooltips()
|
||||||
|
|
||||||
|
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||||
|
|
||||||
var openMessageByAction = false
|
var openMessageByAction = false
|
||||||
var isLocation = false
|
var isLocation = false
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
|
@ -88,7 +88,7 @@ func chatHistoryEntriesForView(
|
|||||||
|
|
||||||
if let maybeJoinMessage = joinMessage {
|
if let maybeJoinMessage = joinMessage {
|
||||||
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
|
if message.timestamp > maybeJoinMessage.timestamp, (!view.holeEarlier || count > 0) {
|
||||||
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false)))
|
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||||
joinMessage = nil
|
joinMessage = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ func chatHistoryEntriesForView(
|
|||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
groupBucket.append((message, isRead, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false), entry.location))
|
groupBucket.append((message, isRead, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false), entry.location))
|
||||||
} else {
|
} else {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
if let selectedMessages = selectedMessages {
|
if let selectedMessages = selectedMessages {
|
||||||
@ -162,7 +162,7 @@ func chatHistoryEntriesForView(
|
|||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId)))
|
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: false)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
@ -171,7 +171,7 @@ func chatHistoryEntriesForView(
|
|||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId)))
|
entries.append(.MessageEntry(message, presentationData, isRead, entry.location, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: entry.attributes.authorIsContact, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: message.index == associatedData.currentlyPlayingMessageId, isCentered: false)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ func chatHistoryEntriesForView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let maybeJoinMessage = joinMessage, !view.holeLater {
|
if let maybeJoinMessage = joinMessage, !view.holeLater {
|
||||||
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false)))
|
entries.append(.MessageEntry(maybeJoinMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||||
joinMessage = nil
|
joinMessage = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,11 +227,11 @@ func chatHistoryEntriesForView(
|
|||||||
if messages.count > 1, let groupInfo = messages[0].groupInfo {
|
if messages.count > 1, let groupInfo = messages[0].groupInfo {
|
||||||
var groupMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = []
|
var groupMessages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)] = []
|
||||||
for message in messages {
|
for message in messages {
|
||||||
groupMessages.append((message, false, .none, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false), nil))
|
groupMessages.append((message, false, .none, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[message.id], isPlaying: false, isCentered: false), nil))
|
||||||
}
|
}
|
||||||
entries.insert(.MessageGroupEntry(groupInfo, groupMessages, presentationData), at: 0)
|
entries.insert(.MessageGroupEntry(groupInfo, groupMessages, presentationData), at: 0)
|
||||||
} else {
|
} else {
|
||||||
entries.insert(.MessageEntry(messages[0], presentationData, false, nil, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[messages[0].id], isPlaying: false)), at: 0)
|
entries.insert(.MessageEntry(messages[0], presentationData, false, nil, selection, ChatMessageEntryAttributes(rank: adminRank, isContact: false, contentTypeHint: contentTypeHint, updatingMedia: updatingMedia[messages[0].id], isPlaying: false, isCentered: false)), at: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
let replyCount = view.entries.isEmpty ? 0 : 1
|
let replyCount = view.entries.isEmpty ? 0 : 1
|
||||||
@ -327,7 +327,7 @@ func chatHistoryEntriesForView(
|
|||||||
associatedMessageIds: message.associatedMessageIds
|
associatedMessageIds: message.associatedMessageIds
|
||||||
)
|
)
|
||||||
nextAdMessageId += 1
|
nextAdMessageId += 1
|
||||||
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false)))
|
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,18 +12,20 @@ public enum ChatMessageEntryContentType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatMessageEntryAttributes: Equatable {
|
public struct ChatMessageEntryAttributes: Equatable {
|
||||||
let rank: CachedChannelAdminRank?
|
var rank: CachedChannelAdminRank?
|
||||||
let isContact: Bool
|
var isContact: Bool
|
||||||
let contentTypeHint: ChatMessageEntryContentType
|
var contentTypeHint: ChatMessageEntryContentType
|
||||||
let updatingMedia: ChatUpdatingMessageMedia?
|
var updatingMedia: ChatUpdatingMessageMedia?
|
||||||
let isPlaying: Bool
|
var isPlaying: Bool
|
||||||
|
var isCentered: Bool
|
||||||
|
|
||||||
init(rank: CachedChannelAdminRank?, isContact: Bool, contentTypeHint: ChatMessageEntryContentType, updatingMedia: ChatUpdatingMessageMedia?, isPlaying: Bool) {
|
init(rank: CachedChannelAdminRank?, isContact: Bool, contentTypeHint: ChatMessageEntryContentType, updatingMedia: ChatUpdatingMessageMedia?, isPlaying: Bool, isCentered: Bool) {
|
||||||
self.rank = rank
|
self.rank = rank
|
||||||
self.isContact = isContact
|
self.isContact = isContact
|
||||||
self.contentTypeHint = contentTypeHint
|
self.contentTypeHint = contentTypeHint
|
||||||
self.updatingMedia = updatingMedia
|
self.updatingMedia = updatingMedia
|
||||||
self.isPlaying = isPlaying
|
self.isPlaying = isPlaying
|
||||||
|
self.isCentered = isCentered
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
@ -32,6 +34,7 @@ public struct ChatMessageEntryAttributes: Equatable {
|
|||||||
self.contentTypeHint = .generic
|
self.contentTypeHint = .generic
|
||||||
self.updatingMedia = nil
|
self.updatingMedia = nil
|
||||||
self.isPlaying = false
|
self.isPlaying = false
|
||||||
|
self.isCentered = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2568,6 +2568,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
strongSelf.forEachVisibleItemNode { itemNode in
|
strongSelf.forEachVisibleItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let updatedReaction = newIncomingReactions[item.content.firstMessage.id], let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: updatedReaction) {
|
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let updatedReaction = newIncomingReactions[item.content.firstMessage.id], let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: updatedReaction) {
|
||||||
for reaction in availableReactions.reactions {
|
for reaction in availableReactions.reactions {
|
||||||
|
guard let centerAnimation = reaction.centerAnimation else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if reaction.value == updatedReaction {
|
if reaction.value == updatedReaction {
|
||||||
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
let standaloneReactionAnimation = StandaloneReactionAnimation()
|
||||||
|
|
||||||
@ -2582,8 +2589,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
|||||||
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
reaction: ReactionContextItem.Reaction(rawValue: reaction.value),
|
||||||
appearAnimation: reaction.appearAnimation,
|
appearAnimation: reaction.appearAnimation,
|
||||||
stillAnimation: reaction.selectAnimation,
|
stillAnimation: reaction.selectAnimation,
|
||||||
listAnimation: reaction.activateAnimation,
|
listAnimation: centerAnimation,
|
||||||
applicationAnimation: reaction.effectAnimation
|
applicationAnimation: aroundAnimation
|
||||||
),
|
),
|
||||||
targetView: targetView,
|
targetView: targetView,
|
||||||
hideNode: true,
|
hideNode: true,
|
||||||
|
@ -927,7 +927,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unvote"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unvote"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
interfaceInteraction.requestUnvoteInMessage(messages[0].id)
|
interfaceInteraction.requestUnvoteInMessage(messages[0].id)
|
||||||
f(.dismissWithoutContent)
|
f(.default)
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,9 +373,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if false, strongSelf.telegramFile == nil {
|
if strongSelf.telegramFile == nil {
|
||||||
if let animationNode = strongSelf.animationNode, animationNode.frame.contains(point) {
|
if let animationNode = strongSelf.animationNode, animationNode.frame.contains(point) {
|
||||||
return .waitForDoubleTap
|
return .waitForSingleTap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1516,6 +1516,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
} else if case .tap = gesture {
|
} else if case .tap = gesture {
|
||||||
item.controllerInteraction.clickThroughMessage()
|
item.controllerInteraction.clickThroughMessage()
|
||||||
|
} else if case .doubleTap = gesture {
|
||||||
|
if canAddMessageReactions(message: item.message) {
|
||||||
|
item.controllerInteraction.updateMessageReaction(item.message, .default)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -858,7 +858,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !strongSelf.backgroundNode.frame.contains(point) {
|
if !strongSelf.backgroundNode.frame.contains(point) {
|
||||||
return .waitForSingleTap
|
return .waitForDoubleTap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1321,9 +1321,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
var isItemEdited = false
|
var isItemEdited = false
|
||||||
|
|
||||||
switch item.content {
|
switch item.content {
|
||||||
case let .message(message, value, _, _, _):
|
case let .message(message, value, _, attributes, _):
|
||||||
read = value
|
read = value
|
||||||
isItemPinned = message.tags.contains(.pinned)
|
isItemPinned = message.tags.contains(.pinned)
|
||||||
|
if attributes.isCentered {
|
||||||
|
alignment = .center
|
||||||
|
}
|
||||||
case let .group(messages):
|
case let .group(messages):
|
||||||
read = messages[0].1
|
read = messages[0].1
|
||||||
for message in messages {
|
for message in messages {
|
||||||
@ -3037,6 +3040,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
}
|
}
|
||||||
} else if case .tap = gesture {
|
} else if case .tap = gesture {
|
||||||
item.controllerInteraction.clickThroughMessage()
|
item.controllerInteraction.clickThroughMessage()
|
||||||
|
} else if case .doubleTap = gesture {
|
||||||
|
if canAddMessageReactions(message: item.message) {
|
||||||
|
item.controllerInteraction.updateMessageReaction(item.message, .default)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -47,7 +47,7 @@ private let reactionCountFont = Font.semibold(11.0)
|
|||||||
private let reactionFont = Font.regular(12.0)
|
private let reactionFont = Font.regular(12.0)
|
||||||
|
|
||||||
private final class StatusReactionNode: ASDisplayNode {
|
private final class StatusReactionNode: ASDisplayNode {
|
||||||
let iconView: UIImageView
|
let iconView: ReactionIconView
|
||||||
|
|
||||||
private let iconImageDisposable = MetaDisposable()
|
private let iconImageDisposable = MetaDisposable()
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ private final class StatusReactionNode: ASDisplayNode {
|
|||||||
private var isSelected: Bool?
|
private var isSelected: Bool?
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
self.iconView = UIImageView()
|
self.iconView = ReactionIconView()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -71,7 +71,8 @@ private final class StatusReactionNode: ASDisplayNode {
|
|||||||
if self.value != value {
|
if self.value != value {
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
let defaultImageSize = CGSize(width: 17.0, height: 17.0)
|
let boundingImageSize = CGSize(width: 17.0, height: 17.0)
|
||||||
|
let defaultImageSize = CGSize(width: boundingImageSize.width + floor(boundingImageSize.width * 0.5 * 2.0), height: boundingImageSize.height + floor(boundingImageSize.height * 0.5 * 2.0))
|
||||||
let imageSize: CGSize
|
let imageSize: CGSize
|
||||||
if let file = file {
|
if let file = file {
|
||||||
self.iconImageDisposable.set((reactionStaticImage(context: context, animation: file, pixelSize: CGSize(width: 72.0, height: 72.0))
|
self.iconImageDisposable.set((reactionStaticImage(context: context, animation: file, pixelSize: CGSize(width: 72.0, height: 72.0))
|
||||||
@ -82,7 +83,7 @@ private final class StatusReactionNode: ASDisplayNode {
|
|||||||
|
|
||||||
if data.isComplete, let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
if data.isComplete, let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||||
if let image = UIImage(data: dataValue) {
|
if let image = UIImage(data: dataValue) {
|
||||||
strongSelf.iconView.image = image
|
strongSelf.iconView.imageView.image = image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -91,7 +92,9 @@ private final class StatusReactionNode: ASDisplayNode {
|
|||||||
imageSize = defaultImageSize
|
imageSize = defaultImageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
self.iconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((defaultImageSize.width - imageSize.width) / 2.0), y: floorToScreenPixels((defaultImageSize.height - imageSize.height) / 2.0)), size: imageSize)
|
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingImageSize.width - imageSize.width) / 2.0), y: floorToScreenPixels((boundingImageSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||||
|
self.iconView.frame = iconFrame
|
||||||
|
self.iconView.update(size: iconFrame.size, transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1235,7 @@ 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, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?) -> 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)?, clickThroughMessage: (() -> Void)? = nil, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, isCentered: Bool) -> ListViewItem {
|
||||||
let controllerInteraction: ChatControllerInteraction
|
let controllerInteraction: ChatControllerInteraction
|
||||||
|
|
||||||
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||||
@ -1300,13 +1300,16 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
|
||||||
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: backgroundNode as? WallpaperBackgroundNode))
|
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false), presentationContext: ChatPresentationContext(backgroundNode: backgroundNode as? WallpaperBackgroundNode))
|
||||||
|
|
||||||
|
var entryAttributes = ChatMessageEntryAttributes()
|
||||||
|
entryAttributes.isCentered = isCentered
|
||||||
|
|
||||||
let content: ChatMessageItemContent
|
let content: ChatMessageItemContent
|
||||||
let chatLocation: ChatLocation
|
let chatLocation: ChatLocation
|
||||||
if messages.count > 1 {
|
if messages.count > 1 {
|
||||||
content = .group(messages: messages.map { ($0, true, .none, ChatMessageEntryAttributes(), nil) })
|
content = .group(messages: messages.map { ($0, true, .none, entryAttributes, nil) })
|
||||||
chatLocation = .peer(messages.first!.id.peerId)
|
chatLocation = .peer(messages.first!.id.peerId)
|
||||||
} else {
|
} else {
|
||||||
content = .message(message: messages.first!, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil)
|
content = .message(message: messages.first!, read: true, selection: .none, attributes: entryAttributes, location: nil)
|
||||||
chatLocation = .peer(messages.first!.id.peerId)
|
chatLocation = .peer(messages.first!.id.peerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user