mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Temp
This commit is contained in:
parent
430ea53ed8
commit
976c2de599
14 changed files with 125 additions and 26 deletions
|
|
@ -67,6 +67,8 @@ private extension ComponentTransition.Animation.Curve {
|
|||
switch self {
|
||||
case .easeInOut:
|
||||
return CAMediaTimingFunction(name: .easeInEaseOut)
|
||||
case .easeIn:
|
||||
return CAMediaTimingFunction(name: .easeIn)
|
||||
case .linear:
|
||||
return CAMediaTimingFunction(name: .linear)
|
||||
case let .custom(a, b, c, d):
|
||||
|
|
@ -82,6 +84,8 @@ private extension ComponentTransition.Animation.Curve {
|
|||
return [.curveLinear]
|
||||
case .easeInOut:
|
||||
return [.curveEaseInOut]
|
||||
case .easeIn:
|
||||
return [.curveEaseIn]
|
||||
case .spring:
|
||||
return UIView.AnimationOptions(rawValue: 7 << 16)
|
||||
case .custom:
|
||||
|
|
@ -141,6 +145,7 @@ public struct ComponentTransition {
|
|||
public enum Animation {
|
||||
public enum Curve {
|
||||
case easeInOut
|
||||
case easeIn
|
||||
case spring
|
||||
case linear
|
||||
case custom(Float, Float, Float, Float)
|
||||
|
|
@ -150,6 +155,8 @@ public struct ComponentTransition {
|
|||
switch self {
|
||||
case .easeInOut:
|
||||
return listViewAnimationCurveEaseInOut(offset)
|
||||
case .easeIn:
|
||||
return listViewAnimationCurveEaseIn(offset)
|
||||
case .spring:
|
||||
return listViewAnimationCurveSystem(offset)
|
||||
case .linear:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ public extension ComponentTransition.Animation.Curve {
|
|||
self = .linear
|
||||
case .easeInOut:
|
||||
self = .easeInOut
|
||||
case .easeIn:
|
||||
self = .easeIn
|
||||
case let .custom(a, b, c, d):
|
||||
self = .custom(a, b, c, d)
|
||||
case .customSpring:
|
||||
|
|
@ -25,6 +27,8 @@ public extension ComponentTransition.Animation.Curve {
|
|||
return .linear
|
||||
case .easeInOut:
|
||||
return .easeInOut
|
||||
case .easeIn:
|
||||
return .easeIn
|
||||
case .spring:
|
||||
return .spring
|
||||
case let .custom(a, b, c, d):
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ extension CGRect {
|
|||
public enum ContainedViewLayoutTransitionCurve: Equatable, Hashable {
|
||||
case linear
|
||||
case easeInOut
|
||||
case easeIn
|
||||
case spring
|
||||
case customSpring(damping: CGFloat, initialVelocity: CGFloat)
|
||||
case custom(Float, Float, Float, Float)
|
||||
|
|
@ -28,6 +29,8 @@ public extension ContainedViewLayoutTransitionCurve {
|
|||
return offset
|
||||
case .easeInOut:
|
||||
return listViewAnimationCurveEaseInOut(offset)
|
||||
case .easeIn:
|
||||
return listViewAnimationCurveEaseIn(offset)
|
||||
case .spring:
|
||||
return listViewAnimationCurveSystem(offset)
|
||||
case .customSpring:
|
||||
|
|
@ -45,6 +48,8 @@ public extension ContainedViewLayoutTransitionCurve {
|
|||
return CAMediaTimingFunctionName.linear.rawValue
|
||||
case .easeInOut:
|
||||
return CAMediaTimingFunctionName.easeInEaseOut.rawValue
|
||||
case .easeIn:
|
||||
return CAMediaTimingFunctionName.easeIn.rawValue
|
||||
case .spring:
|
||||
return kCAMediaTimingFunctionSpring
|
||||
case let .customSpring(damping, initialVelocity):
|
||||
|
|
@ -60,6 +65,8 @@ public extension ContainedViewLayoutTransitionCurve {
|
|||
return nil
|
||||
case .easeInOut:
|
||||
return nil
|
||||
case .easeIn:
|
||||
return nil
|
||||
case .spring:
|
||||
return nil
|
||||
case .customSpring:
|
||||
|
|
@ -75,6 +82,8 @@ public extension ContainedViewLayoutTransitionCurve {
|
|||
return [.curveLinear]
|
||||
case .easeInOut:
|
||||
return [.curveEaseInOut]
|
||||
case .easeIn:
|
||||
return [.curveEaseIn]
|
||||
case .spring:
|
||||
return UIView.AnimationOptions(rawValue: 7 << 16)
|
||||
case .customSpring:
|
||||
|
|
|
|||
|
|
@ -3981,6 +3981,12 @@ open class ListViewImpl: ASDisplayNode, ListView, ASScrollViewDelegate, ASGestur
|
|||
} else {
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut))
|
||||
}
|
||||
case .easeIn:
|
||||
if transition.1 {
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: ContainedViewLayoutTransitionCurve.slide.mediaTimingFunction)
|
||||
} else {
|
||||
headerNode.layer.animateBoundsOriginAdditive(from: offset, to: CGPoint(), duration: duration, mediaTimingFunction: CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ public func listViewAnimationDurationAndCurve(transition: ContainedViewLayoutTra
|
|||
return (animationDuration, .Default(duration: animationDuration))
|
||||
case .easeInOut:
|
||||
return (animationDuration, .Default(duration: animationDuration))
|
||||
case .easeIn:
|
||||
return (animationDuration, .Default(duration: animationDuration))
|
||||
case .spring, .customSpring:
|
||||
return (animationDuration, .Spring(duration: animationDuration))
|
||||
case let .custom(c1x, c1y, c2x, c2y):
|
||||
|
|
|
|||
|
|
@ -100,11 +100,13 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
|
|||
|
||||
for (_, index) in readMessageIndexByNamespace {
|
||||
if let threadId {
|
||||
var newCountIsZero = false
|
||||
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
|
||||
if index.id.id >= data.maxIncomingReadId {
|
||||
if let count = transaction.getThreadMessageCount(peerId: peerId, threadId: threadId, namespace: Namespaces.Message.Cloud, fromIdExclusive: data.maxIncomingReadId, toIndex: index) {
|
||||
data.incomingUnreadCount = max(0, data.incomingUnreadCount - Int32(count))
|
||||
data.maxIncomingReadId = index.id.id
|
||||
newCountIsZero = data.incomingUnreadCount == 0
|
||||
}
|
||||
|
||||
if let topMessageIndex = transaction.getMessageHistoryThreadTopMessage(peerId: peerId, threadId: threadId, namespaces: Set([Namespaces.Message.Cloud])) {
|
||||
|
|
@ -124,6 +126,23 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if newCountIsZero, let peer = transaction.getPeer(peerId), peer.isForumOrMonoForum {
|
||||
var allTopicsAreRead = true
|
||||
for item in transaction.getMessageHistoryThreadIndex(peerId: peer.id, limit: 100) {
|
||||
guard let data = transaction.getMessageHistoryThreadInfo(peerId: index.id.peerId, threadId: item.threadId)?.data.get(MessageHistoryThreadData.self) else {
|
||||
continue
|
||||
}
|
||||
if data.incomingUnreadCount != 0 {
|
||||
allTopicsAreRead = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allTopicsAreRead {
|
||||
_internal_applyMaxReadIndexInteractively(transaction: transaction, stateManager: stateManager, index: index)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_internal_applyMaxReadIndexInteractively(transaction: transaction, stateManager: stateManager, index: index)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -339,7 +339,6 @@ private class ReplyThreadHistoryContextImpl {
|
|||
}
|
||||
|
||||
var markMainAsRead = false
|
||||
markMainAsRead = !"".isEmpty
|
||||
|
||||
if var data = transaction.getMessageHistoryThreadInfo(peerId: peerId, threadId: threadId)?.data.get(MessageHistoryThreadData.self) {
|
||||
if messageIndex.id.id >= data.maxIncomingReadId {
|
||||
|
|
@ -348,6 +347,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||
data.maxIncomingReadId = messageIndex.id.id
|
||||
}
|
||||
|
||||
var newCountIsZero = false
|
||||
if let topMessageIndex = transaction.getMessageHistoryThreadTopMessage(peerId: peerId, threadId: threadId, namespaces: Set([Namespaces.Message.Cloud])) {
|
||||
if messageIndex.id.id >= topMessageIndex.id.id {
|
||||
let containingHole = transaction.getThreadIndexHole(peerId: peerId, threadId: threadId, namespace: topMessageIndex.id.namespace, containing: topMessageIndex.id.id)
|
||||
|
|
@ -357,6 +357,24 @@ private class ReplyThreadHistoryContextImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
newCountIsZero = data.incomingUnreadCount == 0
|
||||
|
||||
if newCountIsZero, let peer = transaction.getPeer(peerId), peer.isForumOrMonoForum {
|
||||
var allTopicsAreRead = true
|
||||
for item in transaction.getMessageHistoryThreadIndex(peerId: peer.id, limit: 100) {
|
||||
guard let data = transaction.getMessageHistoryThreadInfo(peerId: messageIndex.id.peerId, threadId: item.threadId)?.data.get(MessageHistoryThreadData.self) else {
|
||||
continue
|
||||
}
|
||||
if data.incomingUnreadCount != 0 {
|
||||
allTopicsAreRead = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allTopicsAreRead {
|
||||
markMainAsRead = true
|
||||
}
|
||||
}
|
||||
|
||||
data.maxKnownMessageId = max(data.maxKnownMessageId, messageIndex.id.id)
|
||||
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ public final class AsyncListComponent: Component {
|
|||
case let .curve(duration, curve):
|
||||
updateSizeAndInsets.duration = duration
|
||||
switch curve {
|
||||
case .linear, .easeInOut:
|
||||
case .linear, .easeInOut, .easeIn:
|
||||
updateSizeAndInsets.curve = .Default(duration: duration)
|
||||
case .spring:
|
||||
updateSizeAndInsets.curve = .Spring(duration: duration)
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
} else {
|
||||
currentMaxGlyphCount = nil
|
||||
}
|
||||
let previousGlyphCount = self.textNode.textNode.getCharacterToGlyphMapping().count
|
||||
let previousGlyphCount = self.textNode.textNode.cachedLayout?.attributedString?.length ?? 0
|
||||
|
||||
return { item, layoutConstants, _, _, _, _ in
|
||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||
|
|
@ -711,7 +711,8 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
lineColor: messageTheme.accentControlColor,
|
||||
displayContentsUnderSpoilers: displayContentsUnderSpoilers.value,
|
||||
customTruncationToken: customTruncationToken,
|
||||
expandedBlocks: expandedBlockIds
|
||||
expandedBlocks: expandedBlockIds,
|
||||
computeCharacterRects: true
|
||||
))
|
||||
|
||||
var hasDraft = false
|
||||
|
|
@ -729,7 +730,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
var clippedGlyphCountLayout: TextNodeLayout.LayoutInfo?
|
||||
if let maxGlyphCount {
|
||||
clippedGlyphCountLayout = textLayout.layoutForGlyphCount(glyphCount: maxGlyphCount)
|
||||
clippedGlyphCountLayout = textLayout.layoutForCharacterCount(characterCount: maxGlyphCount)
|
||||
}
|
||||
|
||||
var statusSuggestedWidthAndContinue: (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageDateAndStatusNode))?
|
||||
|
|
@ -826,7 +827,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
|
||||
var previousAnimateGlyphCount: Int?
|
||||
if hasDraft || hadDraft {
|
||||
previousAnimateGlyphCount = strongSelf.textNode.textNode.getCharacterToGlyphMapping().count
|
||||
previousAnimateGlyphCount = strongSelf.textNode.textNode.cachedLayout?.attributedString?.length ?? 0
|
||||
}
|
||||
|
||||
strongSelf.textNode.textNode.displaysAsynchronously = !item.presentationData.isPreview
|
||||
|
|
@ -1052,8 +1053,8 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
|
||||
if previousAnimateGlyphCount != nil || strongSelf.textRevealAnimationState != nil || hasDraft || hadDraft {
|
||||
if strongSelf.textNode.textNode.revealGlyphCount == nil {
|
||||
strongSelf.textNode.textNode.updateRevealGlyphCount(count: previousAnimateGlyphCount ?? 0)
|
||||
if strongSelf.textNode.textNode.revealCharacterCount == nil {
|
||||
strongSelf.textNode.textNode.updateRevealCharacterCount(count: previousAnimateGlyphCount ?? 0, animated: false)
|
||||
}
|
||||
strongSelf.updateTextRevealAnimation(previousGlyphCount: previousAnimateGlyphCount ?? 0)
|
||||
}
|
||||
|
|
@ -1066,7 +1067,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
|
||||
private func updateTextRevealAnimation(previousGlyphCount: Int) {
|
||||
var fromCount = previousGlyphCount
|
||||
let toCount = self.textNode.textNode.getCharacterToGlyphMapping().count
|
||||
let toCount = self.textNode.textNode.cachedLayout?.attributedString?.length ?? 0
|
||||
let timestamp = CACurrentMediaTime()
|
||||
if let textRevealAnimationState = self.textRevealAnimationState {
|
||||
if textRevealAnimationState.toCount == toCount {
|
||||
|
|
@ -1078,7 +1079,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
if self.textRevealAnimationState != nil {
|
||||
self.textRevealAnimationState = nil
|
||||
self.textRevealLink = nil
|
||||
self.textNode.textNode.updateRevealGlyphCount(count: nil)
|
||||
self.textNode.textNode.updateRevealCharacterCount(count: nil, animated: false)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -1106,14 +1107,14 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
self.textRevealAnimationState = nil
|
||||
self.textRevealLink = nil
|
||||
|
||||
self.textNode.textNode.updateRevealGlyphCount(count: nil)
|
||||
self.textNode.textNode.updateRevealCharacterCount(count: nil, animated: false)
|
||||
self.requestFullUpdate?()
|
||||
} else {
|
||||
var requestUpdate = false
|
||||
let glyphCount = textRevealAnimationState.glyphCount(timestamp: timestamp)
|
||||
if let previousRevealGlyphCount = self.textNode.textNode.revealGlyphCount, previousRevealGlyphCount != glyphCount {
|
||||
if let previousRevealGlyphCount = self.textNode.textNode.revealCharacterCount, previousRevealGlyphCount != glyphCount {
|
||||
if let cachedLayout = self.textNode.textNode.cachedLayout {
|
||||
if cachedLayout.sizeForGlyphCount(glyphCount: previousRevealGlyphCount) != cachedLayout.sizeForGlyphCount(glyphCount: glyphCount) {
|
||||
if cachedLayout.sizeForCharacterCount(characterCount: previousRevealGlyphCount) != cachedLayout.sizeForCharacterCount(characterCount: glyphCount) {
|
||||
requestUpdate = true
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1123,7 +1124,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
//print("glyphCount: request update")
|
||||
}
|
||||
|
||||
self.textNode.textNode.updateRevealGlyphCount(count: glyphCount)
|
||||
self.textNode.textNode.updateRevealCharacterCount(count: glyphCount, animated: true)
|
||||
}
|
||||
|
||||
if requestUpdate {
|
||||
|
|
|
|||
|
|
@ -2985,15 +2985,40 @@ final class TextContentItemLayer: SimpleLayer {
|
|||
self.addSublayer(snippetLayer)
|
||||
self.animatingSnippetLayers.append(snippetLayer)
|
||||
|
||||
snippetLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
snippetLayer.animateSpring(from: 0.001, to: 1.0, keyPath: "transform.scale", duration: 0.5, completion: { [weak self, weak snippetLayer] _ in
|
||||
guard let self, let snippetLayer else {
|
||||
return
|
||||
}
|
||||
snippetLayer.removeFromSuperlayer()
|
||||
self.animatingSnippetLayers.removeAll(where: { $0 === snippetLayer })
|
||||
self.updateRevealMask(animateNewSegments: false)
|
||||
})
|
||||
if !"".isEmpty {
|
||||
//ComponentTransition(animation: .curve(duration: 0.3, curve: .easeInOut)).animateBlur(layer: snippetLayer, fromRadius: 10.0, toRadius: 0.0)
|
||||
|
||||
snippetLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
snippetLayer.animateScale(from: 0.1, to: 1.0, duration: 0.2, completion: { [weak self, weak snippetLayer] _ in
|
||||
guard let self, let snippetLayer else {
|
||||
return
|
||||
}
|
||||
snippetLayer.removeFromSuperlayer()
|
||||
self.animatingSnippetLayers.removeAll(where: { $0 === snippetLayer })
|
||||
self.updateRevealMask(animateNewSegments: false)
|
||||
})
|
||||
} else if "".isEmpty {
|
||||
ComponentTransition(animation: .curve(duration: 0.25, curve: .easeInOut)).animateBlur(layer: snippetLayer, fromRadius: 8.0, toRadius: 0.0)
|
||||
snippetLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
snippetLayer.animatePosition(from: CGPoint(x: 0.0, y: 10.0), to: CGPoint(), duration: 0.2, additive: true)
|
||||
snippetLayer.animateScale(from: 0.5, to: 1.0, duration: 0.2, completion: { [weak self, weak snippetLayer] _ in
|
||||
guard let self, let snippetLayer else {
|
||||
return
|
||||
}
|
||||
snippetLayer.removeFromSuperlayer()
|
||||
self.animatingSnippetLayers.removeAll(where: { $0 === snippetLayer })
|
||||
self.updateRevealMask(animateNewSegments: false)
|
||||
})
|
||||
} else {
|
||||
snippetLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, completion: { [weak self, weak snippetLayer] _ in
|
||||
guard let self, let snippetLayer else {
|
||||
return
|
||||
}
|
||||
snippetLayer.removeFromSuperlayer()
|
||||
self.animatingSnippetLayers.removeAll(where: { $0 === snippetLayer })
|
||||
self.updateRevealMask(animateNewSegments: false)
|
||||
})
|
||||
}
|
||||
}
|
||||
globalCharIndex += lineCharCount
|
||||
}
|
||||
|
|
|
|||
|
|
@ -504,7 +504,9 @@ final class MiniAppListScreenComponent: Component {
|
|||
let timingFunction: String
|
||||
switch curve {
|
||||
case .easeInOut:
|
||||
timingFunction = CAMediaTimingFunctionName.easeOut.rawValue
|
||||
timingFunction = CAMediaTimingFunctionName.easeInEaseOut.rawValue
|
||||
case .easeIn:
|
||||
timingFunction = CAMediaTimingFunctionName.easeIn.rawValue
|
||||
case .linear:
|
||||
timingFunction = CAMediaTimingFunctionName.linear.rawValue
|
||||
case .spring:
|
||||
|
|
|
|||
|
|
@ -1064,7 +1064,9 @@ final class QuickReplySetupScreenComponent: Component {
|
|||
let timingFunction: String
|
||||
switch curve {
|
||||
case .easeInOut:
|
||||
timingFunction = CAMediaTimingFunctionName.easeOut.rawValue
|
||||
timingFunction = CAMediaTimingFunctionName.easeInEaseOut.rawValue
|
||||
case .easeIn:
|
||||
timingFunction = CAMediaTimingFunctionName.easeIn.rawValue
|
||||
case .linear:
|
||||
timingFunction = CAMediaTimingFunctionName.linear.rawValue
|
||||
case .spring:
|
||||
|
|
|
|||
|
|
@ -522,7 +522,9 @@ final class PeerSelectionScreenComponent: Component {
|
|||
let timingFunction: String
|
||||
switch curve {
|
||||
case .easeInOut:
|
||||
timingFunction = CAMediaTimingFunctionName.easeOut.rawValue
|
||||
timingFunction = CAMediaTimingFunctionName.easeInEaseOut.rawValue
|
||||
case .easeIn:
|
||||
timingFunction = CAMediaTimingFunctionName.easeIn.rawValue
|
||||
case .linear:
|
||||
timingFunction = CAMediaTimingFunctionName.linear.rawValue
|
||||
case .spring:
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ public final class AnimatableProperty<T: Interpolatable> {
|
|||
break
|
||||
case .easeInOut:
|
||||
t = listViewAnimationCurveEaseInOut(t)
|
||||
case .easeIn:
|
||||
t = listViewAnimationCurveEaseIn(t)
|
||||
case .spring:
|
||||
t = lookupSpringValue(t)
|
||||
case let .custom(x1, y1, x2, y2):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue