Various fixes

This commit is contained in:
Ilya Laktyushin 2026-01-05 15:14:19 +04:00
parent c93e02a58e
commit c654227b83
15 changed files with 167 additions and 19 deletions

View file

@ -1218,7 +1218,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
if !data.includePeers.peers.isEmpty && data.categories.isEmpty && !data.excludeRead && !data.excludeMuted && !data.excludeArchived && data.excludePeers.isEmpty {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.ChatList_ContextMenuShare, textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: self.presentationData.strings.ChatList_ContextMenuBadgeNew, color: .accent, style: .label), icon: { theme in
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.ChatList_ContextMenuShare, textColor: .primary, badge: nil, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, f in
c?.dismiss(completion: {

View file

@ -236,12 +236,11 @@ public final class ShimmerEffectForegroundNode: ASDisplayNode {
let image: UIImage?
if horizontal {
let baseAlpha: CGFloat = 0.1
//let baseAlpha: CGFloat = 0.1
image = generateImage(CGSize(width: effectSize ?? 200.0, height: 16.0), opaque: false, scale: 1.0, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let foregroundColor = UIColor(white: 1.0, alpha: min(1.0, baseAlpha * 4.0))
//let foregroundColor = foregroundColor //.withAlphaComponent(min(1.0, baseAlpha * 3.0))
if let shadowImage {
UIGraphicsPushContext(context)

View file

@ -9,6 +9,7 @@ public enum SummarizeError {
case invalidMessageId
case limitExceeded
case invalidLanguage
case limitExceededPremium
}
func _internal_summarizeMessage(account: Account, messageId: EngineMessage.Id, translateToLang: String?) -> Signal<Never, SummarizeError> {
@ -35,6 +36,8 @@ func _internal_summarizeMessage(account: Account, messageId: EngineMessage.Id, t
return .invalidMessageId
} else if error.errorDescription == "TO_LANG_INVALID" {
return .invalidLanguage
} else if error.errorDescription == "SUMMARY_FLOOD_PREMIUM" {
return .limitExceededPremium
} else {
return .generic
}

View file

@ -84,6 +84,9 @@ import LottieMetal
import AvatarNode
import ChatMessageSuggestedPostInfoNode
import AlertComponent
import PremiumStarComponent
private struct BubbleItemAttributes {
var index: Int?
var isAttachment: Bool
@ -6994,7 +6997,19 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
if requestSummary {
let _ = (item.context.engine.messages.summarizeMessage(messageId: item.message.id, translateToLang: translateToLanguage)
|> deliverOnMainQueue).start()
|> deliverOnMainQueue).start(error: { error in
if case .limitExceededPremium = error, let parentController = item.controllerInteraction.navigationController()?.topViewController as? ViewController {
item.controllerInteraction.summarizedMessageIds.remove(item.message.id)
let _ = item.controllerInteraction.requestMessageUpdate(item.message.id, false)
let controller = premiumAlertController(
context: item.context,
parentController: parentController,
title: "AI Summary",
text: "Summarize large messages with AI unlimited with Telegram Premium."
)
parentController.present(controller, in: .window(.root))
}
})
}
}
}
@ -7221,3 +7236,115 @@ public final class NameNavigateButton: HighlightableButton {
}
}
}
private func premiumAlertController(
context: AccountContext,
parentController: ViewController,
title: String? = nil,
text: String
) -> ViewController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let strings = presentationData.strings
var content: [AnyComponentWithIdentity<AlertComponentEnvironment>] = []
content.append(AnyComponentWithIdentity(
id: "header",
component: AnyComponent(
AlertPremiumStarComponent()
)
))
let title = strings.PremiumNeeded_Title
content.append(AnyComponentWithIdentity(
id: "title",
component: AnyComponent(
AlertTitleComponent(title: title)
)
))
content.append(AnyComponentWithIdentity(
id: "text",
component: AnyComponent(
AlertTextComponent(content: .plain(text))
)
))
let alertController = AlertScreen(
context: context,
content: content,
actions: [
.init(title: strings.Common_Cancel),
.init(title: strings.PremiumNeeded_Subscribe, type: .default, action: { [weak parentController] in
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .nameColor, forceDark: false, dismissed: nil)
parentController?.push(controller)
})
]
)
return alertController
}
private final class AlertPremiumStarComponent: Component {
public typealias EnvironmentType = AlertComponentEnvironment
public init() {
}
public static func ==(lhs: AlertPremiumStarComponent, rhs: AlertPremiumStarComponent) -> Bool {
return true
}
public final class View: UIView {
private let clippingView = UIView()
private let icon = ComponentView<Empty>()
private var component: AlertPremiumStarComponent?
private weak var state: EmptyComponentState?
func update(component: AlertPremiumStarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<AlertComponentEnvironment>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
let environment = environment[AlertComponentEnvironment.self]
let starHeight: CGFloat = 105.0
let starSize = self.icon.update(
transition: .immediate,
component: AnyComponent(
PremiumStarComponent(
theme: environment.theme,
isIntro: false,
isVisible: true,
hasIdleAnimations: true,
colors: [
UIColor(rgb: 0x6a94ff),
UIColor(rgb: 0x9472fd),
UIColor(rgb: 0xe26bd3)
]
)
),
environment: {},
containerSize: CGSize(width: availableSize.width + 60.0, height: 200.0)
)
if let view = self.icon.view {
if view.superview == nil {
self.addSubview(self.clippingView)
self.clippingView.addSubview(view)
}
view.frame = CGRect(origin: CGPoint(x: 0.0, y: -24.0), size: starSize)
}
self.clippingView.clipsToBounds = true
self.clippingView.layer.cornerRadius = 35.0
self.clippingView.frame = CGRect(origin: CGPoint(x: -30.0, y: -22.0), size: CGSize(width: starSize.width, height: starSize.height))
return CGSize(width: availableSize.width, height: starHeight + 10.0)
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<AlertComponentEnvironment>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -1565,7 +1565,7 @@ public final class ChatMessageInteractiveFileNode: ASDisplayNode {
if isTranslating, !rects.isEmpty {
if self.shimmeringNodes.isEmpty {
for rects in rects {
let shimmeringNode = ShimmeringLinkNode(color: arguments.message.effectivelyIncoming(arguments.context.account.peerId) ? arguments.presentationData.theme.theme.chat.message.incoming.secondaryTextColor.withAlphaComponent(0.1) : arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
let shimmeringNode = ShimmeringLinkNode(color: arguments.message.effectivelyIncoming(arguments.context.account.peerId) ? arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor.withAlphaComponent(0.1) : arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
shimmeringNode.updateRects(rects)
shimmeringNode.frame = self.bounds
shimmeringNode.updateLayout(self.bounds.size)

View file

@ -1679,7 +1679,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
if isTranslating, !rects.isEmpty {
if self.shimmeringNodes.isEmpty {
for rects in rects {
let shimmeringNode = ShimmeringLinkNode(color: item.message.effectivelyIncoming(item.context.account.peerId) ? item.presentationData.theme.theme.chat.message.incoming.secondaryTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
let shimmeringNode = ShimmeringLinkNode(color: item.message.effectivelyIncoming(item.context.account.peerId) ? item.presentationData.theme.theme.chat.message.incoming.accentTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
shimmeringNode.updateRects(rects)
shimmeringNode.frame = self.bounds
shimmeringNode.updateLayout(self.bounds.size)

View file

@ -897,6 +897,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
}
strongSelf.textAccessibilityOverlayNode.frame = textFrame
isTranslating = true
strongSelf.updateIsTranslating(isTranslating)
if let statusSizeAndApply {
@ -1258,7 +1259,14 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
if let current = self.shimmeringNode {
shimmeringNode = current
} else {
shimmeringNode = ShimmeringLinkNode(color: item.message.effectivelyIncoming(item.context.account.peerId) ? item.presentationData.theme.theme.chat.message.incoming.secondaryTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
let color: UIColor
let isIncoming = item.message.effectivelyIncoming(item.context.account.peerId)
if item.presentationData.theme.theme.overallDarkAppearance {
color = isIncoming ? item.presentationData.theme.theme.chat.message.incoming.primaryTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.primaryTextColor.withAlphaComponent(0.1)
} else {
color = isIncoming ? item.presentationData.theme.theme.chat.message.incoming.accentTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1)
}
shimmeringNode = ShimmeringLinkNode(color: color)
shimmeringNode.updateRects(rects)
shimmeringNode.frame = self.textNode.textNode.frame
shimmeringNode.updateLayout(self.textNode.textNode.frame.size)

View file

@ -1481,8 +1481,8 @@ public class ChatMessageTodoBubbleContentNode: ChatMessageBubbleContentNode {
if isTranslating, !rects.isEmpty {
if self.shimmeringNodes.isEmpty {
for rects in rects {
let shimmeringNode = ShimmeringLinkNode(color: item.message.effectivelyIncoming(item.context.account.peerId) ? item.presentationData.theme.theme.chat.message.incoming.secondaryTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
for rects in rects {
let shimmeringNode = ShimmeringLinkNode(color: item.message.effectivelyIncoming(item.context.account.peerId) ? item.presentationData.theme.theme.chat.message.incoming.accentTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1))
shimmeringNode.updateRects(rects)
shimmeringNode.frame = self.bounds
shimmeringNode.updateLayout(self.bounds.size)

View file

@ -93,7 +93,7 @@ public final class ShimmeringLinkNode: ASDisplayNode {
self.shimmerEffectNode.updateAbsoluteRect(CGRect(origin: .zero, size: size), within: size)
self.borderShimmerEffectNode.updateAbsoluteRect(CGRect(origin: .zero, size: size), within: size)
self.shimmerEffectNode.update(backgroundColor: .clear, foregroundColor: self.color.withAlphaComponent(min(1.0, self.color.alpha * 1.2)), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil)
self.borderShimmerEffectNode.update(backgroundColor: .clear, foregroundColor: self.color.withAlphaComponent(min(1.0, self.color.alpha * 1.5)), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil)
self.shimmerEffectNode.update(backgroundColor: .clear, foregroundColor: self.color.withMultipliedAlpha(1.75), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil)
self.borderShimmerEffectNode.update(backgroundColor: .clear, foregroundColor: self.color.withMultipliedAlpha(2.0), horizontal: true, effectSize: nil, globalTimeOffset: false, duration: nil)
}
}

View file

@ -2551,6 +2551,7 @@ private final class GiftViewSheetContent: CombinedComponent {
let upgradePerks = Child(List<Empty>.self)
let upgradeKeepName = Child(PlainButtonComponent.self)
let upgradePriceButton = Child(PlainButtonComponent.self)
let variantsMeasureDescription = Child(MultilineTextComponent.self)
let spaceRegex = try? NSRegularExpression(pattern: "\\[(.*?)\\]", options: [])
@ -3076,6 +3077,16 @@ private final class GiftViewSheetContent: CombinedComponent {
if let previewPatternColor = giftCompositionExternalState.previewPatternColor {
buttonColor = previewPatternColor
}
let variantsMeasureDescription = variantsMeasureDescription.update(
component: MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_Upgrade_ViewAllVariants, font: Font.semibold(13.0), textColor: .clear))),
availableSize: context.availableSize,
transition: .immediate
)
context.add(variantsMeasureDescription
.position(CGPoint(x: -10000.0, y: -10000.0))
)
let upgradeDescription = upgradeDescription.update(
component: PlainButtonComponent(
content: AnyComponent(
@ -3131,7 +3142,7 @@ private final class GiftViewSheetContent: CombinedComponent {
},
animateScale: false
),
availableSize: CGSize(width: 280.0, height: 24.0),
availableSize: CGSize(width: variantsMeasureDescription.size.width + 87.0, height: 24.0),
transition: context.transition
)

View file

@ -2184,7 +2184,7 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt
} else {
programTitleValue = .text(presentationData.strings.PeerInfo_ItemAffiliateProgram_ValueOff)
}
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliateProgram, label: programTitleValue, additionalBadgeLabel: presentationData.strings.Settings_New, text: presentationData.strings.PeerInfo_ItemAffiliateProgram_Title, icon: PresentationResourcesSettings.affiliateProgram, action: {
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliateProgram, label: programTitleValue, additionalBadgeLabel: nil, text: presentationData.strings.PeerInfo_ItemAffiliateProgram_Title, icon: PresentationResourcesSettings.affiliateProgram, action: {
interaction.editingOpenAffiliateProgram()
}))
}
@ -2467,7 +2467,7 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt
labelString = NSAttributedString(string: presentationData.strings.PeerInfo_AllowChannelMessages_Off, font: labelFont, textColor: labelColor)
}
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPostSuggestionsSettings, label: .attributedText(labelString), additionalBadgeLabel: presentationData.strings.Settings_New, text: presentationData.strings.PeerInfo_AllowChannelMessages, icon: PresentationResourcesSettings.channelMessages, action: {
items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPostSuggestionsSettings, label: .attributedText(labelString), additionalBadgeLabel: nil, text: presentationData.strings.PeerInfo_AllowChannelMessages, icon: PresentationResourcesSettings.channelMessages, action: {
interaction.editingOpenPostSuggestionsSetup()
}))

View file

@ -372,7 +372,7 @@ public class ItemListReactionItemNode: ListViewItemNode, ItemListItemNode {
if let animationContent = animationContent {
let iconBoundingSize = CGSize(width: 28.0, height: 28.0)
let iconOffsetX: CGFloat = 0.0
let iconOffsetX: CGFloat = -6.0
let iconSize = strongSelf.iconView.update(
transition: .immediate,
component: AnyComponent(EmojiStatusComponent(

View file

@ -835,7 +835,7 @@ final class StarsTransactionsScreenComponent: Component {
footer: nil,
items: [
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor(
itemGenerator: ItemListDisclosureItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesSettings.earnStars, title: environment.strings.Monetization_EarnStarsInfo_Title, titleBadge: presentationData.strings.Settings_New, label: environment.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: 0, style: .blocks, action: {
itemGenerator: ItemListDisclosureItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesSettings.earnStars, title: environment.strings.Monetization_EarnStarsInfo_Title, titleBadge: nil, label: environment.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: 0, style: .blocks, action: {
}),
params: ListViewItemLayoutParams(width: availableSize.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true),
action: { [weak self] in

View file

@ -933,7 +933,7 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran
}
if itemNode == nil || itemNode === currentItemNode {
if let contextController = self.contextController {
contextController.addRelativeContentOffset(CGPoint(x: 0.0, y: offset), transition: transition)
contextController.addRelativeContentOffset(CGPoint(x: 0.0, y: -offset), transition: transition)
}
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
standaloneReactionAnimation.addRelativeContentOffset(CGPoint(x: 0.0, y: -offset), transition: transition)

View file

@ -176,7 +176,7 @@ final class HashtagChatInputContextPanelNode: ChatInputContextPanelNode {
peer: peer,
title: self.strings.Chat_HashtagSuggestion_UseLocal_Title("#\(query)@\(addressName)").string,
text: isGroup ? self.strings.Chat_HashtagSuggestion_UseLocal_Group_Text : self.strings.Chat_HashtagSuggestion_UseLocal_Channel_Text,
badge: self.strings.ChatList_ContextMenuBadgeNew,
badge: nil,
hashtag: "\(query)@\(addressName)",
revealed: false,
isAdditionalRecent: false