This commit is contained in:
Isaac 2025-12-30 14:04:36 +08:00
commit 1c91b37b6f
9 changed files with 116 additions and 36 deletions

View file

@ -1 +1 @@
c796824aa8245ce7309426caa3c4816024abd71d21f3805988aa953a4e826168
c796824aa8245ce7309426caa3c4816024abd71d21f3805988aa953a4e826169

View file

@ -3,30 +3,63 @@ import Postbox
import TelegramApi
public final class SummarizationMessageAttribute: Equatable, MessageAttribute {
public struct Summary: Equatable, Codable {
public struct Summary: Equatable, Codable, PostboxCoding {
public let text: String
public let entities: [MessageTextEntity]
public init(
text: String,
entities: [MessageTextEntity]
) {
self.text = text
self.entities = entities
}
public init(decoder: PostboxDecoder) {
self.text = decoder.decodeStringForKey("text", orElse: "")
self.entities = decoder.decodeObjectArrayWithDecoderForKey("entities")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeString(self.text, forKey: "text")
encoder.encodeObjectArray(self.entities, forKey: "entities")
}
}
public let fromLang: String
public let summary: Summary?
public let translated: [String: Summary]
public init(
fromLang: String,
summary: Summary? = nil
summary: Summary? = nil,
translated: [String: Summary] = [:]
) {
self.fromLang = fromLang
self.summary = summary
self.translated = translated
}
required public init(decoder: PostboxDecoder) {
self.fromLang = decoder.decodeStringForKey("fl", orElse: "")
self.summary = decoder.decodeCodable(Summary.self, forKey: "sum")
self.summary = decoder.decodeObjectForKey("s", decoder: { Summary(decoder: $0) }) as? Summary
self.translated = decoder.decodeObjectDictionaryForKey("t", keyDecoder: { decoder in
return decoder.decodeStringForKey("k", orElse: "")
}, valueDecoder: { decoder in
return Summary(decoder: decoder)
})
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeString(self.fromLang, forKey: "fl")
encoder.encodeCodable(self.summary, forKey: "sum")
if let summary = self.summary {
encoder.encodeObject(summary, forKey: "s")
} else {
encoder.encodeNil(forKey: "s")
}
encoder.encodeObjectDictionary(self.translated, forKey: "t", keyEncoder: { k, e in
e.encodeString(k, forKey: "k")
})
}
public static func ==(lhs: SummarizationMessageAttribute, rhs: SummarizationMessageAttribute) -> Bool {
@ -36,6 +69,19 @@ public final class SummarizationMessageAttribute: Equatable, MessageAttribute {
if lhs.summary != rhs.summary {
return false
}
if lhs.translated != rhs.translated {
return false
}
return true
}
}
public extension SummarizationMessageAttribute {
func summaryForLang(_ lang: String?) -> Summary? {
if let lang {
return self.translated[lang]
} else {
return self.summary
}
}
}

View file

@ -47,14 +47,23 @@ func _internal_summarizeMessage(account: Account, messageId: EngineMessage.Id, t
let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init)
var attributes = currentMessage.attributes
var fromLang = ""
if let attribute = attributes.first(where: { $0 is SummarizationMessageAttribute }) as? SummarizationMessageAttribute {
fromLang = attribute.fromLang
let currentAttribute = attributes.first(where: { $0 is SummarizationMessageAttribute }) as? SummarizationMessageAttribute
let updatedAttribute: SummarizationMessageAttribute
if let translateToLang {
var translated = currentAttribute?.translated ?? [:]
translated[translateToLang] = SummarizationMessageAttribute.Summary(text: text, entities: messageTextEntitiesFromApiEntities(entities))
updatedAttribute = SummarizationMessageAttribute(
fromLang: currentAttribute?.fromLang ?? "",
summary: currentAttribute?.summary,
translated: translated
)
} else {
updatedAttribute = SummarizationMessageAttribute(
fromLang: currentAttribute?.fromLang ?? "",
summary: .init(text: text, entities: messageTextEntitiesFromApiEntities(entities)),
translated: currentAttribute?.translated ?? [:]
)
}
let updatedAttribute = SummarizationMessageAttribute(
fromLang: fromLang,
summary: .init(text: text, entities: messageTextEntitiesFromApiEntities(entities))
)
attributes = attributes.filter { !($0 is SummarizationMessageAttribute) }
attributes.append(updatedAttribute)

View file

@ -2326,10 +2326,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
}
let translateToLanguage = item.associatedData.translateToLanguage
var isSummarized = false
if item.controllerInteraction.summarizedMessageIds.contains(item.message.id) {
for attribute in item.message.attributes {
if let attribute = attribute as? SummarizationMessageAttribute, attribute.summary != nil {
if let attribute = attribute as? SummarizationMessageAttribute, attribute.summaryForLang(translateToLanguage) != nil {
isSummarized = true
}
}
@ -6982,15 +6983,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
item.controllerInteraction.summarizedMessageIds.insert(item.message.id)
let _ = item.controllerInteraction.requestMessageUpdate(item.message.id, false)
var needsSummarization = true
let translateToLanguage = item.associatedData.translateToLanguage
var requestSummary = true
for attribute in item.message.attributes {
if let attribute = attribute as? SummarizationMessageAttribute, attribute.summary != nil {
needsSummarization = false
if let attribute = attribute as? SummarizationMessageAttribute, attribute.summaryForLang(translateToLanguage) != nil {
requestSummary = false
break
}
}
if needsSummarization {
let _ = (item.context.engine.messages.summarizeMessage(messageId: item.message.id, translateToLang: nil)
if requestSummary {
let _ = (item.context.engine.messages.summarizeMessage(messageId: item.message.id, translateToLang: translateToLanguage)
|> deliverOnMainQueue).start()
}
}

View file

@ -444,26 +444,29 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
messageEntities = updatingMedia.entities?.entities ?? []
}
var translateToLanguage = item.associatedData.translateToLanguage
let translateToLanguage = item.associatedData.translateToLanguage
var isSummarized = false
if item.controllerInteraction.summarizedMessageIds.contains(item.message.id) {
translateToLanguage = "sum"
isSummarized = true
}
if let subject = item.associatedData.subject, case .messageOptions = subject {
} else if let translateToLanguage, !item.message.text.isEmpty && incoming {
isTranslating = true
for attribute in item.message.attributes {
if translateToLanguage == "sum", let attribute = attribute as? SummarizationMessageAttribute, let summary = attribute.summary {
} else if !item.message.text.isEmpty && incoming {
if translateToLanguage != nil || isSummarized {
isTranslating = true
}
if isTranslating {
if isSummarized, let attribute = item.message.attributes.first(where: { $0 is SummarizationMessageAttribute }) as? SummarizationMessageAttribute, let summary = attribute.summaryForLang(translateToLanguage) {
rawText = summary.text
messageEntities = summary.entities
isTranslating = false
isSummaryApplied = true
break
} else if let attribute = attribute as? TranslationMessageAttribute, !attribute.text.isEmpty, attribute.toLang == translateToLanguage {
} else if let attribute = item.message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, !attribute.text.isEmpty, attribute.toLang == translateToLanguage {
rawText = attribute.text
messageEntities = attribute.entities
isTranslating = false
break
if !isSummarized {
isTranslating = false
}
}
}
}

View file

@ -957,7 +957,14 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
self.currentParams = (size, sideInset, bottomInset, deviceMetrics, visibleHeight, expansionFraction, presentationData, data, areTabsHidden, disableTabSwitching, navigationHeight)
self.backgroundColor = presentationData.theme.list.blocksBackgroundColor.mixedWith(presentationData.theme.list.plainBackgroundColor, alpha: expansionFraction)
let backgroundColor: UIColor
if self.currentPaneKey == .gifts {
backgroundColor = presentationData.theme.list.blocksBackgroundColor
} else {
backgroundColor = presentationData.theme.list.blocksBackgroundColor.mixedWith(presentationData.theme.list.plainBackgroundColor, alpha: expansionFraction)
}
self.backgroundColor = backgroundColor
let isScrollingLockedAtTop = expansionFraction < 1.0 - CGFloat.ulpOfOne
@ -1189,7 +1196,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
} else {
let isAnimatingOut = pane.isAnimatingOut
pane.isAnimatingOut = true
paneTransition.updateFrame(node: pane.node, frame: adjustedFrame, completion: isAnimatingOut ? nil : { _ in
paneTransition.updateFrame(node: pane.node, frame: adjustedFrame, completion: isAnimatingOut ? nil : { _ in
paneCompletion()
})
}
@ -1220,7 +1227,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
let edgeEffectHeight: CGFloat = 60.0
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: 60.0 + 6.0))
transition.updateFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
self.edgeEffectView.update(content: presentationData.theme.list.blocksBackgroundColor.mixedWith(presentationData.theme.list.plainBackgroundColor, alpha: expansionFraction), blur: true, alpha: 1.0, rect: edgeEffectFrame, edge: .top, edgeSize: edgeEffectHeight, transition: ComponentTransition(transition))
self.edgeEffectView.update(content: backgroundColor, blur: true, alpha: 1.0, rect: edgeEffectFrame, edge: .top, edgeSize: edgeEffectHeight, transition: ComponentTransition(transition))
ComponentTransition(transition).setAlpha(view: self.edgeEffectView, alpha: tabsAlpha)
var canManageTabs = false

View file

@ -12531,7 +12531,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
func updatePresentationData(_ presentationData: PresentationData) {
self.presentationData = presentationData
self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor.mixedWith(self.presentationData.theme.list.plainBackgroundColor, alpha: self.effectiveAreaExpansionFraction)
self.updateBackgroundColor()
self.updateNavigationExpansionPresentation(isExpanded: self.headerNode.isAvatarExpanded, animated: false)
@ -12950,6 +12950,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|> take(1))
}
}
private func updateBackgroundColor() {
let color: UIColor
if self.paneContainerNode.currentPaneKey == .gifts {
color = self.presentationData.theme.list.blocksBackgroundColor
} else {
color = self.presentationData.theme.list.blocksBackgroundColor.mixedWith(self.presentationData.theme.list.plainBackgroundColor, alpha: self.effectiveAreaExpansionFraction)
}
self.backgroundColor = color
}
private var hasQrButton = false
fileprivate func updateNavigation(transition: ContainedViewLayoutTransition, additive: Bool, animateHeader: Bool) {
@ -13008,7 +13018,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
}
self.effectiveAreaExpansionFraction = effectiveAreaExpansionFraction
self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor.mixedWith(self.presentationData.theme.list.plainBackgroundColor, alpha: self.effectiveAreaExpansionFraction)
self.updateBackgroundColor()
let visibleHeight = self.scrollNode.view.contentOffset.y + self.scrollNode.view.bounds.height - self.paneContainerNode.frame.minY

View file

@ -931,7 +931,9 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
let bottomContentOffset = max(0.0, self.scrollNode.view.contentSize.height - self.scrollNode.view.contentOffset.y - self.scrollNode.view.frame.height)
if bottomContentOffset < 200.0 {
self.giftsListView.loadMore()
Queue.mainQueue().justDispatch {
self.giftsListView.loadMore()
}
}
}

View file

@ -77,13 +77,13 @@ final class NotificationItemContainerNode: ASDisplayNode {
func animateIn() {
if let _ = self.validLayout {
self.layer.animatePosition(from: CGPoint(x: 0.0, y: -self.backgroundView.bounds.size.height), to: CGPoint(), duration: 0.4, additive: true)
self.layer.animatePosition(from: CGPoint(x: 0.0, y: -self.backgroundView.frame.maxY), to: CGPoint(), duration: 0.4, additive: true)
}
}
func animateOut(completion: @escaping () -> Void) {
if let _ = self.validLayout {
self.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -self.backgroundView.bounds.size.height), duration: 0.4, removeOnCompletion: false, additive: true, completion: { _ in
self.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -self.backgroundView.frame.maxY), duration: 0.4, removeOnCompletion: false, additive: true, completion: { _ in
completion()
})
} else {