mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
04ca831081
commit
266f9e5ad8
@ -46,6 +46,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
|
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
|
||||||
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
|
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
|
||||||
"//submodules/TelegramUI/Components/SliderContextItem:SliderContextItem",
|
"//submodules/TelegramUI/Components/SliderContextItem:SliderContextItem",
|
||||||
|
"//submodules/TooltipUI",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -11,6 +11,7 @@ import RadialStatusNode
|
|||||||
import ScreenCaptureDetection
|
import ScreenCaptureDetection
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import LocalizedPeerData
|
import LocalizedPeerData
|
||||||
|
import TooltipUI
|
||||||
|
|
||||||
private func galleryMediaForMedia(media: Media) -> Media? {
|
private func galleryMediaForMedia(media: Media) -> Media? {
|
||||||
if let media = media as? TelegramMediaImage {
|
if let media = media as? TelegramMediaImage {
|
||||||
@ -57,23 +58,54 @@ private final class SecretMediaPreviewControllerNode: GalleryControllerNode {
|
|||||||
private var timeoutNode: RadialStatusNode?
|
private var timeoutNode: RadialStatusNode?
|
||||||
|
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
var beginTimeAndTimeout: (Double, Double)? {
|
var beginTimeAndTimeout: (Double, Double)? {
|
||||||
didSet {
|
didSet {
|
||||||
if let (beginTime, timeout) = self.beginTimeAndTimeout, Int32(timeout) != viewOnceTimeout {
|
if let (beginTime, timeout) = self.beginTimeAndTimeout {
|
||||||
|
var beginTime = beginTime
|
||||||
if self.timeoutNode == nil {
|
if self.timeoutNode == nil {
|
||||||
let timeoutNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5))
|
let timeoutNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5))
|
||||||
self.timeoutNode = timeoutNode
|
self.timeoutNode = timeoutNode
|
||||||
var iconImage: UIImage?
|
let icon: RadialStatusNodeState.SecretTimeoutIcon
|
||||||
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/SecretMediaIcon"), color: .white) {
|
let timeoutValue = Int32(timeout)
|
||||||
let factor: CGFloat = 0.48
|
if timeoutValue == viewOnceTimeout || "".isEmpty {
|
||||||
iconImage = generateImage(CGSize(width: floor(image.size.width * factor), height: floor(image.size.height * factor)), contextGenerator: { size, context in
|
beginTime = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
||||||
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size))
|
if let image = generateImage(CGSize(width: 28.0, height: 28.0), rotatedContext: { size, context in
|
||||||
})
|
let bounds = CGRect(origin: .zero, size: size)
|
||||||
|
context.clear(bounds)
|
||||||
|
|
||||||
|
let string = "1"
|
||||||
|
let attributedString = NSAttributedString(string: string, attributes: [NSAttributedString.Key.font: Font.with(size: 14.0, design: .round), NSAttributedString.Key.foregroundColor: UIColor.white])
|
||||||
|
|
||||||
|
let line = CTLineCreateWithAttributedString(attributedString)
|
||||||
|
let lineBounds = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds)
|
||||||
|
|
||||||
|
let lineOffset = CGPoint(x: -1.0, y: 0.0)
|
||||||
|
let lineOrigin = CGPoint(x: floorToScreenPixels(-lineBounds.origin.x + (bounds.size.width - lineBounds.size.width) / 2.0) + lineOffset.x, y: floorToScreenPixels(-lineBounds.origin.y + (bounds.size.height - lineBounds.size.height) / 2.0))
|
||||||
|
|
||||||
|
context.translateBy(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0)
|
||||||
|
context.scaleBy(x: 1.0, y: -1.0)
|
||||||
|
context.translateBy(x: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0)
|
||||||
|
|
||||||
|
context.translateBy(x: lineOrigin.x, y: lineOrigin.y)
|
||||||
|
CTLineDraw(line, context)
|
||||||
|
context.translateBy(x: -lineOrigin.x, y: -lineOrigin.y)
|
||||||
|
}) {
|
||||||
|
icon = .image(image)
|
||||||
|
} else {
|
||||||
|
icon = .flame
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
icon = .flame
|
||||||
}
|
}
|
||||||
timeoutNode.transitionToState(.secretTimeout(color: .white, icon: iconImage, beginTime: beginTime, timeout: timeout, sparks: true), completion: {})
|
timeoutNode.transitionToState(.secretTimeout(color: .white, icon: icon, beginTime: beginTime, timeout: timeout, sparks: true), completion: {})
|
||||||
self.addSubnode(timeoutNode)
|
self.addSubnode(timeoutNode)
|
||||||
|
|
||||||
|
timeoutNode.addTarget(self, action: #selector(self.statusTapGesture), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
|
// let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.statusTapGesture))
|
||||||
|
// timeoutNode.view.addGestureRecognizer(tapGesture)
|
||||||
|
|
||||||
if let (layout, navigationHeight) = self.validLayout {
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
self.layoutTimeoutNode(layout, navigationBarHeight: navigationHeight, transition: .immediate)
|
self.layoutTimeoutNode(layout, navigationBarHeight: navigationHeight, transition: .immediate)
|
||||||
@ -86,6 +118,13 @@ private final class SecretMediaPreviewControllerNode: GalleryControllerNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var statusPressed: (UIView) -> Void = { _ in }
|
||||||
|
@objc private func statusTapGesture() {
|
||||||
|
if let sourceView = self.timeoutNode?.view {
|
||||||
|
self.statusPressed(sourceView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func animateIn(animateContent: Bool, useSimpleAnimation: Bool) {
|
override func animateIn(animateContent: Bool, useSimpleAnimation: Bool) {
|
||||||
super.animateIn(animateContent: animateContent, useSimpleAnimation: useSimpleAnimation)
|
super.animateIn(animateContent: animateContent, useSimpleAnimation: useSimpleAnimation)
|
||||||
|
|
||||||
@ -149,6 +188,8 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
|
|
||||||
private var screenCaptureEventsDisposable: Disposable?
|
private var screenCaptureEventsDisposable: Disposable?
|
||||||
|
|
||||||
|
private weak var tooltipController: TooltipScreen?
|
||||||
|
|
||||||
public init(context: AccountContext, messageId: MessageId) {
|
public init(context: AccountContext, messageId: MessageId) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.messageId = messageId
|
self.messageId = messageId
|
||||||
@ -214,6 +255,12 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
self.displayNode = SecretMediaPreviewControllerNode(controllerInteraction: controllerInteraction)
|
self.displayNode = SecretMediaPreviewControllerNode(controllerInteraction: controllerInteraction)
|
||||||
self.displayNodeDidLoad()
|
self.displayNodeDidLoad()
|
||||||
|
|
||||||
|
self.controllerNode.statusPressed = { [weak self] sourceView in
|
||||||
|
if let self {
|
||||||
|
self.presentViewOnceTooltip(sourceView: sourceView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.statusBar = self.statusBar
|
self.controllerNode.statusBar = self.statusBar
|
||||||
self.controllerNode.navigationBar = self.navigationBar
|
self.controllerNode.navigationBar = self.navigationBar
|
||||||
|
|
||||||
@ -497,6 +544,42 @@ public final class SecretMediaPreviewController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func presentViewOnceTooltip(sourceView: UIView) {
|
||||||
|
if let tooltipController = self.tooltipController {
|
||||||
|
self.tooltipController = nil
|
||||||
|
tooltipController.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil)
|
||||||
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 2.0), size: CGSize())
|
||||||
|
|
||||||
|
let iconName = "anim_autoremove_on"
|
||||||
|
let text: String
|
||||||
|
if self.currentNodeMessageIsVideo {
|
||||||
|
text = "This video can only be viewed once"
|
||||||
|
} else {
|
||||||
|
text = "This photo can only be viewed once"
|
||||||
|
}
|
||||||
|
|
||||||
|
let tooltipController = TooltipScreen(
|
||||||
|
account: self.context.account,
|
||||||
|
sharedContext: self.context.sharedContext,
|
||||||
|
text: .plain(text: text),
|
||||||
|
balancedTextLayout: true,
|
||||||
|
style: .customBlur(UIColor(rgb: 0x18181a), 0.0),
|
||||||
|
arrowStyle: .small,
|
||||||
|
icon: .animation(name: iconName, delay: 0.1, tintColor: nil),
|
||||||
|
location: .point(location, .top),
|
||||||
|
displayDuration: .default,
|
||||||
|
inset: 8.0,
|
||||||
|
shouldDismissOnTouch: { _, _ in
|
||||||
|
return .ignore
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.tooltipController = tooltipController
|
||||||
|
self.present(tooltipController, in: .window(.root))
|
||||||
|
}
|
||||||
|
|
||||||
public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
public override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
|
@ -4,6 +4,35 @@ import AsyncDisplayKit
|
|||||||
import Display
|
import Display
|
||||||
|
|
||||||
public enum RadialStatusNodeState: Equatable {
|
public enum RadialStatusNodeState: Equatable {
|
||||||
|
public enum SecretTimeoutIcon: Equatable {
|
||||||
|
case none
|
||||||
|
case image(UIImage)
|
||||||
|
case flame
|
||||||
|
|
||||||
|
public static func ==(lhs: SecretTimeoutIcon, rhs: SecretTimeoutIcon) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case .none:
|
||||||
|
if case .none = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .image(lhsImage):
|
||||||
|
if case let .image(rhsImage) = rhs, lhsImage === rhsImage {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case .flame:
|
||||||
|
if case .flame = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case none
|
case none
|
||||||
case download(UIColor)
|
case download(UIColor)
|
||||||
case play(UIColor)
|
case play(UIColor)
|
||||||
@ -13,7 +42,7 @@ public enum RadialStatusNodeState: Equatable {
|
|||||||
case check(UIColor)
|
case check(UIColor)
|
||||||
case customIcon(UIImage)
|
case customIcon(UIImage)
|
||||||
case staticTimeout
|
case staticTimeout
|
||||||
case secretTimeout(color: UIColor, icon: UIImage?, beginTime: Double, timeout: Double, sparks: Bool)
|
case secretTimeout(color: UIColor, icon: SecretTimeoutIcon, beginTime: Double, timeout: Double, sparks: Bool)
|
||||||
|
|
||||||
public static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool {
|
public static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
@ -72,7 +101,7 @@ public enum RadialStatusNodeState: Equatable {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks):
|
case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks):
|
||||||
if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon === rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks {
|
if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon == rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -137,7 +166,7 @@ public enum RadialStatusNodeState: Equatable {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks):
|
case let .secretTimeout(lhsColor, lhsIcon, lhsBeginTime, lhsTimeout, lhsSparks):
|
||||||
if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon === rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks {
|
if case let .secretTimeout(rhsColor, rhsIcon, rhsBeginTime, rhsTimeout, rhsSparks) = rhs, lhsColor.isEqual(rhsColor), lhsIcon == rhsIcon, lhsBeginTime.isEqual(to: rhsBeginTime), lhsTimeout.isEqual(to: rhsTimeout), lhsSparks == rhsSparks {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -25,12 +25,12 @@ private struct ContentParticle {
|
|||||||
|
|
||||||
private final class RadialStatusSecretTimeoutContentNodeParameters: NSObject {
|
private final class RadialStatusSecretTimeoutContentNodeParameters: NSObject {
|
||||||
let color: UIColor
|
let color: UIColor
|
||||||
let icon: UIImage?
|
let icon: RadialStatusNodeState.SecretTimeoutIcon
|
||||||
let progress: CGFloat
|
let progress: CGFloat
|
||||||
let sparks: Bool
|
let sparks: Bool
|
||||||
let particles: [ContentParticle]
|
let particles: [ContentParticle]
|
||||||
|
|
||||||
init(color: UIColor, icon: UIImage?, progress: CGFloat, sparks: Bool, particles: [ContentParticle]) {
|
init(color: UIColor, icon: RadialStatusNodeState.SecretTimeoutIcon, progress: CGFloat, sparks: Bool, particles: [ContentParticle]) {
|
||||||
self.color = color
|
self.color = color
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.progress = progress
|
self.progress = progress
|
||||||
@ -48,7 +48,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
|
|
||||||
private let beginTime: Double
|
private let beginTime: Double
|
||||||
private let timeout: Double
|
private let timeout: Double
|
||||||
private let icon: UIImage?
|
private let icon: RadialStatusNodeState.SecretTimeoutIcon
|
||||||
private let sparks: Bool
|
private let sparks: Bool
|
||||||
|
|
||||||
private var progress: CGFloat = 0.0
|
private var progress: CGFloat = 0.0
|
||||||
@ -58,7 +58,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
|
|
||||||
private var displayLink: CADisplayLink?
|
private var displayLink: CADisplayLink?
|
||||||
|
|
||||||
init(color: UIColor, beginTime: Double, timeout: Double, icon: UIImage?, sparks: Bool) {
|
init(color: UIColor, beginTime: Double, timeout: Double, icon: RadialStatusNodeState.SecretTimeoutIcon, sparks: Bool) {
|
||||||
self.color = color
|
self.color = color
|
||||||
self.beginTime = beginTime
|
self.beginTime = beginTime
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
@ -84,7 +84,7 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
self.displayLink?.isPaused = true
|
self.displayLink?.isPaused = true
|
||||||
self.displayLink?.add(to: RunLoop.main, forMode: .common)
|
self.displayLink?.add(to: RunLoop.main, forMode: .common)
|
||||||
|
|
||||||
if icon != nil {
|
if case .flame = icon {
|
||||||
self.addSubnode(self.animationNode)
|
self.addSubnode(self.animationNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,15 +202,15 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let parameters = parameters as? RadialStatusSecretTimeoutContentNodeParameters {
|
if let parameters = parameters as? RadialStatusSecretTimeoutContentNodeParameters {
|
||||||
// if let icon = parameters.icon, let _ = icon.cgImage {
|
if case let .image(icon) = parameters.icon, let iconImage = icon.cgImage {
|
||||||
// let imageRect = CGRect(origin: CGPoint(x: floor((bounds.size.width - icon.size.width) / 2.0), y: floor((bounds.size.height - icon.size.height) / 2.0)), size: icon.size)
|
let imageRect = CGRect(origin: CGPoint(x: floor((bounds.size.width - icon.size.width) / 2.0), y: floor((bounds.size.height - icon.size.height) / 2.0)), size: icon.size)
|
||||||
// context.saveGState()
|
context.saveGState()
|
||||||
// context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
||||||
// context.scaleBy(x: 1.0, y: -1.0)
|
context.scaleBy(x: 1.0, y: -1.0)
|
||||||
// context.translateBy(x: -imageRect.midX, y: -imageRect.midY)
|
context.translateBy(x: -imageRect.midX, y: -imageRect.midY)
|
||||||
// context.draw(iconImage, in: imageRect)
|
context.draw(iconImage, in: imageRect)
|
||||||
// context.restoreGState()
|
context.restoreGState()
|
||||||
// }
|
}
|
||||||
|
|
||||||
let lineWidth: CGFloat
|
let lineWidth: CGFloat
|
||||||
if parameters.sparks {
|
if parameters.sparks {
|
||||||
|
@ -95,7 +95,7 @@ enum AccountStateMutationOperation {
|
|||||||
case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation)
|
case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation)
|
||||||
case UpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool)
|
case UpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool)
|
||||||
case UpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64])
|
case UpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64])
|
||||||
case ReadMessageContents((PeerId?, [Int32]))
|
case ReadMessageContents(peerIdsAndMessageIds: (PeerId?, [Int32]), date: Int32?)
|
||||||
case UpdateMessageImpressionCount(MessageId, Int32)
|
case UpdateMessageImpressionCount(MessageId, Int32)
|
||||||
case UpdateMessageForwardsCount(MessageId, Int32)
|
case UpdateMessageForwardsCount(MessageId, Int32)
|
||||||
case UpdateInstalledStickerPacks(AccountStateUpdateStickerPacksOperation)
|
case UpdateInstalledStickerPacks(AccountStateUpdateStickerPacksOperation)
|
||||||
@ -574,8 +574,8 @@ struct AccountMutableState {
|
|||||||
self.addOperation(.UpdatePinnedTopicOrder(peerId: peerId, threadIds: threadIds))
|
self.addOperation(.UpdatePinnedTopicOrder(peerId: peerId, threadIds: threadIds))
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func addReadMessagesContents(_ peerIdsAndMessageIds: (PeerId?, [Int32])) {
|
mutating func addReadMessagesContents(_ peerIdsAndMessageIds: (PeerId?, [Int32]), date: Int32?) {
|
||||||
self.addOperation(.ReadMessageContents(peerIdsAndMessageIds))
|
self.addOperation(.ReadMessageContents(peerIdsAndMessageIds: peerIdsAndMessageIds, date: date))
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func addUpdateMessageImpressionCount(id: MessageId, count: Int32) {
|
mutating func addUpdateMessageImpressionCount(id: MessageId, count: Int32) {
|
||||||
|
@ -1479,11 +1479,11 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
|
|||||||
case let .updateChannelPinnedTopic(flags, channelId, topicId):
|
case let .updateChannelPinnedTopic(flags, channelId, topicId):
|
||||||
let isPinned = (flags & (1 << 0)) != 0
|
let isPinned = (flags & (1 << 0)) != 0
|
||||||
updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: Int64(topicId), isPinned: isPinned)
|
updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: Int64(topicId), isPinned: isPinned)
|
||||||
case let .updateReadMessagesContents(_, messages, _, _, _):
|
case let .updateReadMessagesContents(_, messages, _, _, date):
|
||||||
updatedState.addReadMessagesContents((nil, messages))
|
updatedState.addReadMessagesContents((nil, messages), date: date)
|
||||||
case let .updateChannelReadMessagesContents(_, channelId, topMsgId, messages):
|
case let .updateChannelReadMessagesContents(_, channelId, topMsgId, messages):
|
||||||
let _ = topMsgId
|
let _ = topMsgId
|
||||||
updatedState.addReadMessagesContents((PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), messages))
|
updatedState.addReadMessagesContents((PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), messages), date: nil)
|
||||||
case let .updateChannelMessageViews(channelId, id, views):
|
case let .updateChannelMessageViews(channelId, id, views):
|
||||||
updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), namespace: Namespaces.Message.Cloud, id: id), count: views)
|
updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), namespace: Namespaces.Message.Cloud, id: id), count: views)
|
||||||
/*case let .updateChannelMessageForwards(channelId, id, forwards):
|
/*case let .updateChannelMessageForwards(channelId, id, forwards):
|
||||||
@ -2929,7 +2929,7 @@ private func pollChannel(accountPeerId: PeerId, postbox: Postbox, network: Netwo
|
|||||||
}, pinned: (flags & (1 << 0)) != 0)
|
}, pinned: (flags & (1 << 0)) != 0)
|
||||||
case let .updateChannelReadMessagesContents(_, _, topMsgId, messages):
|
case let .updateChannelReadMessagesContents(_, _, topMsgId, messages):
|
||||||
let _ = topMsgId
|
let _ = topMsgId
|
||||||
updatedState.addReadMessagesContents((peer.id, messages))
|
updatedState.addReadMessagesContents((peer.id, messages), date: nil)
|
||||||
case let .updateChannelMessageViews(_, id, views):
|
case let .updateChannelMessageViews(_, id, views):
|
||||||
updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views)
|
updatedState.addUpdateMessageImpressionCount(id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id), count: views)
|
||||||
case let .updateChannelWebPage(_, apiWebpage, _, _):
|
case let .updateChannelWebPage(_, apiWebpage, _, _):
|
||||||
@ -4181,16 +4181,16 @@ func replayFinalState(
|
|||||||
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: currentThreadIds)
|
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: currentThreadIds)
|
||||||
case let .UpdatePinnedTopicOrder(peerId, threadIds):
|
case let .UpdatePinnedTopicOrder(peerId, threadIds):
|
||||||
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: threadIds)
|
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: threadIds)
|
||||||
case let .ReadMessageContents(peerIdAndMessageIds):
|
case let .ReadMessageContents(peerIdAndMessageIds, date):
|
||||||
let (peerId, messageIds) = peerIdAndMessageIds
|
let (peerId, messageIds) = peerIdAndMessageIds
|
||||||
|
|
||||||
if let peerId = peerId {
|
if let peerId = peerId {
|
||||||
for id in messageIds {
|
for id in messageIds {
|
||||||
markMessageContentAsConsumedRemotely(transaction: transaction, messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id))
|
markMessageContentAsConsumedRemotely(transaction: transaction, messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), consumeDate: date)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for messageId in transaction.messageIdsForGlobalIds(messageIds) {
|
for messageId in transaction.messageIdsForGlobalIds(messageIds) {
|
||||||
markMessageContentAsConsumedRemotely(transaction: transaction, messageId: messageId)
|
markMessageContentAsConsumedRemotely(transaction: transaction, messageId: messageId, consumeDate: date)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .UpdateMessageImpressionCount(id, count):
|
case let .UpdateMessageImpressionCount(id, count):
|
||||||
|
@ -307,7 +307,7 @@ func processSecretChatIncomingDecryptedOperations(encryptionProvider: Encryption
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for messageId in messageIds {
|
for messageId in messageIds {
|
||||||
markMessageContentAsConsumedRemotely(transaction: transaction, messageId: messageId)
|
markMessageContentAsConsumedRemotely(transaction: transaction, messageId: messageId, consumeDate: nil)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -160,7 +160,7 @@ func _internal_markReactionsAsSeenInteractively(postbox: Postbox, messageId: Mes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func markMessageContentAsConsumedRemotely(transaction: Transaction, messageId: MessageId) {
|
func markMessageContentAsConsumedRemotely(transaction: Transaction, messageId: MessageId, consumeDate: Int32?) {
|
||||||
if let message = transaction.getMessage(messageId) {
|
if let message = transaction.getMessage(messageId) {
|
||||||
var updateMessage = false
|
var updateMessage = false
|
||||||
var updatedAttributes = message.attributes
|
var updatedAttributes = message.attributes
|
||||||
@ -184,35 +184,41 @@ func markMessageContentAsConsumedRemotely(transaction: Transaction, messageId: M
|
|||||||
}
|
}
|
||||||
|
|
||||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||||
|
let countdownBeginTime = consumeDate ?? timestamp
|
||||||
|
|
||||||
for i in 0 ..< updatedAttributes.count {
|
for i in 0 ..< updatedAttributes.count {
|
||||||
if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute {
|
if let attribute = updatedAttributes[i] as? AutoremoveTimeoutMessageAttribute {
|
||||||
if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia {
|
if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia {
|
||||||
updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp)
|
updatedAttributes[i] = AutoremoveTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: countdownBeginTime)
|
||||||
updateMessage = true
|
updateMessage = true
|
||||||
|
|
||||||
if message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
if message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
} else {
|
} else {
|
||||||
for i in 0 ..< updatedMedia.count {
|
if attribute.timeout == viewOnceTimeout || timestamp >= countdownBeginTime + attribute.timeout {
|
||||||
if let _ = updatedMedia[i] as? TelegramMediaImage {
|
for i in 0 ..< updatedMedia.count {
|
||||||
updatedMedia[i] = TelegramMediaExpiredContent(data: .image)
|
if let _ = updatedMedia[i] as? TelegramMediaImage {
|
||||||
} else if let _ = updatedMedia[i] as? TelegramMediaFile {
|
updatedMedia[i] = TelegramMediaExpiredContent(data: .image)
|
||||||
updatedMedia[i] = TelegramMediaExpiredContent(data: .file)
|
} else if let _ = updatedMedia[i] as? TelegramMediaFile {
|
||||||
|
updatedMedia[i] = TelegramMediaExpiredContent(data: .file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let attribute = updatedAttributes[i] as? AutoclearTimeoutMessageAttribute {
|
} else if let attribute = updatedAttributes[i] as? AutoclearTimeoutMessageAttribute {
|
||||||
if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia {
|
if (attribute.countdownBeginTime == nil || attribute.countdownBeginTime == 0) && message.containsSecretMedia {
|
||||||
updatedAttributes[i] = AutoclearTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: timestamp)
|
updatedAttributes[i] = AutoclearTimeoutMessageAttribute(timeout: attribute.timeout, countdownBeginTime: countdownBeginTime)
|
||||||
updateMessage = true
|
updateMessage = true
|
||||||
|
|
||||||
if message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
if message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
} else {
|
} else {
|
||||||
for i in 0 ..< updatedMedia.count {
|
for i in 0 ..< updatedMedia.count {
|
||||||
if let _ = updatedMedia[i] as? TelegramMediaImage {
|
if attribute.timeout == viewOnceTimeout || timestamp >= countdownBeginTime + attribute.timeout {
|
||||||
updatedMedia[i] = TelegramMediaExpiredContent(data: .image)
|
if let _ = updatedMedia[i] as? TelegramMediaImage {
|
||||||
} else if let _ = updatedMedia[i] as? TelegramMediaFile {
|
updatedMedia[i] = TelegramMediaExpiredContent(data: .image)
|
||||||
updatedMedia[i] = TelegramMediaExpiredContent(data: .file)
|
} else if let _ = updatedMedia[i] as? TelegramMediaFile {
|
||||||
|
updatedMedia[i] = TelegramMediaExpiredContent(data: .file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4111,6 +4111,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func presentReactionPremiumSuggestion() {
|
fileprivate func presentReactionPremiumSuggestion() {
|
||||||
|
self.hapticFeedback.impact(.light)
|
||||||
|
|
||||||
self.dismissAllTooltips()
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
let context = self.context
|
let context = self.context
|
||||||
@ -4142,7 +4144,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: true, position: .bottom, animateInAsReplacement: false, action: { [weak self] action in
|
let controller = UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: true, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
||||||
if case .info = action, let self {
|
if case .info = action, let self {
|
||||||
if let stickerScreen = self.node.stickerScreen {
|
if let stickerScreen = self.node.stickerScreen {
|
||||||
self.node.stickerScreen = nil
|
self.node.stickerScreen = nil
|
||||||
|
@ -1157,9 +1157,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
case .Local:
|
case .Local:
|
||||||
if isSecretMedia && self.secretProgressIcon != nil {
|
if isSecretMedia && self.secretProgressIcon != nil {
|
||||||
if let (beginTime, timeout) = secretBeginTimeAndTimeout {
|
if let (beginTime, timeout) = secretBeginTimeAndTimeout {
|
||||||
state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: secretProgressIcon, beginTime: beginTime, timeout: timeout, sparks: true)
|
state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: .flame, beginTime: beginTime, timeout: timeout, sparks: true)
|
||||||
} else {
|
} else {
|
||||||
state = .customIcon(secretProgressIcon!)
|
state = .staticTimeout
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state = .none
|
state = .none
|
||||||
|
@ -1796,6 +1796,10 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
var badgeContent: ChatMessageInteractiveMediaBadgeContent?
|
var badgeContent: ChatMessageInteractiveMediaBadgeContent?
|
||||||
var mediaDownloadState: ChatMessageInteractiveMediaDownloadState?
|
var mediaDownloadState: ChatMessageInteractiveMediaDownloadState?
|
||||||
|
|
||||||
|
if isSecretMedia {
|
||||||
|
backgroundColor = messageTheme.mediaDateAndStatusFillColor
|
||||||
|
}
|
||||||
|
|
||||||
if let invoice = invoice {
|
if let invoice = invoice {
|
||||||
if let extendedMedia = invoice.extendedMedia {
|
if let extendedMedia = invoice.extendedMedia {
|
||||||
if case let .preview(_, _, maybeVideoDuration) = extendedMedia, let videoDuration = maybeVideoDuration {
|
if case let .preview(_, _, maybeVideoDuration) = extendedMedia, let videoDuration = maybeVideoDuration {
|
||||||
@ -1989,11 +1993,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
|||||||
secretProgressIcon = PresentationResourcesChat.chatBubbleSecretMediaCompactIcon(theme)
|
secretProgressIcon = PresentationResourcesChat.chatBubbleSecretMediaCompactIcon(theme)
|
||||||
}
|
}
|
||||||
if isSecretMedia, let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout, let beginTime = maybeBeginTime, Int32(timeout) != viewOnceTimeout {
|
if isSecretMedia, let (maybeBeginTime, timeout) = secretBeginTimeAndTimeout, let beginTime = maybeBeginTime, Int32(timeout) != viewOnceTimeout {
|
||||||
state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: secretProgressIcon, beginTime: beginTime, timeout: timeout, sparks: true)
|
state = .secretTimeout(color: messageTheme.mediaOverlayControlColors.foregroundColor, icon: .flame, beginTime: beginTime, timeout: timeout, sparks: true)
|
||||||
backgroundColor = messageTheme.mediaDateAndStatusFillColor
|
|
||||||
} else if isSecretMedia, let _ = secretProgressIcon {
|
} else if isSecretMedia, let _ = secretProgressIcon {
|
||||||
state = .staticTimeout
|
state = .staticTimeout
|
||||||
backgroundColor = messageTheme.mediaDateAndStatusFillColor
|
|
||||||
} else if let file = media as? TelegramMediaFile, !file.isVideoSticker {
|
} else if let file = media as? TelegramMediaFile, !file.isVideoSticker {
|
||||||
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false)
|
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && (self.automaticPlayback ?? false)
|
||||||
if (!isInlinePlayableVideo || isStory) && file.isVideo {
|
if (!isInlinePlayableVideo || isStory) && file.isVideo {
|
||||||
|
@ -1347,8 +1347,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
|||||||
var panelWrapperFrame = CGRect(origin: CGPoint(x: leftMargin + layout.safeInsets.left, y: layout.size.height - contentHeight - insets.bottom - margin), size: CGSize(width: layout.size.width - leftMargin * 2.0 - layout.safeInsets.left - layout.safeInsets.right, height: contentHeight))
|
var panelWrapperFrame = CGRect(origin: CGPoint(x: leftMargin + layout.safeInsets.left, y: layout.size.height - contentHeight - insets.bottom - margin), size: CGSize(width: layout.size.width - leftMargin * 2.0 - layout.safeInsets.left - layout.safeInsets.right, height: contentHeight))
|
||||||
|
|
||||||
if case .top = self.placementPosition {
|
if case .top = self.placementPosition {
|
||||||
panelFrame.origin.y = insets.top + margin
|
var topInset = insets.top
|
||||||
panelWrapperFrame.origin.y = insets.top + margin
|
if topInset.isZero {
|
||||||
|
topInset = layout.statusBarHeight ?? 44.0
|
||||||
|
}
|
||||||
|
panelFrame.origin.y = topInset + margin
|
||||||
|
panelWrapperFrame.origin.y = topInset + margin
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.panelNode, frame: panelFrame)
|
transition.updateFrame(node: self.panelNode, frame: panelFrame)
|
||||||
@ -1441,7 +1445,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
|||||||
let statusSize: CGFloat = 30.0
|
let statusSize: CGFloat = 30.0
|
||||||
transition.updateFrame(node: statusNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - statusSize) / 2.0), y: floor((contentHeight - statusSize) / 2.0)), size: CGSize(width: statusSize, height: statusSize)))
|
transition.updateFrame(node: statusNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - statusSize) / 2.0), y: floor((contentHeight - statusSize) / 2.0)), size: CGSize(width: statusSize, height: statusSize)))
|
||||||
if firstLayout {
|
if firstLayout {
|
||||||
statusNode.transitionToState(.secretTimeout(color: .white, icon: nil, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
|
statusNode.transitionToState(.secretTimeout(color: .white, icon: .none, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user