Various fixes

This commit is contained in:
Ilya Laktyushin 2025-12-27 21:50:29 +04:00
parent 9d6518a738
commit 54ec998186
9 changed files with 117 additions and 55 deletions

View file

@ -15647,3 +15647,22 @@ Error: %8$@";
"CocoonInfo.Understood" = "Understood";
"Conversation.Translation.CocoonInfo" = "Translations are powered by\n**#Cocoon**. [How does it work?]()";
"Conversation.EmojiStake.Won" = "%1$@ won %2$@";
"Conversation.EmojiStake.WonYou" = "You won %@";
"Conversation.EmojiStake.Lost" = "%1$@ lost %2$@";
"Conversation.EmojiStake.LostYou" = "You lost %@";
"Conversation.Dice.Stake" = "Stake:";
"Conversation.Dice.Change" = "change";
"EmojiStake.Title" = "Emoji Stake";
"EmojiStake.Description" = "An experimental feature for Telegram Premium users.";
"EmojiStake.ResultsTitle" = "RESULTS AND RETURNS";
"EmojiStake.StreakInfo" = "A streak resets after 3 # or a stake change.";
"EmojiStake.StakeTitle" = "STAKE";
"EmojiStake.StakePlaceholder" = "Amount";
"EmojiStake.Roll" = "Save and Roll";
"Conversation.Summary.Title" = "AI Summary";
"Conversation.Summary.Text" = "Tap to see original text";

View file

@ -1651,7 +1651,7 @@ private class ImageRecognitionOverlayContentNode: GalleryOverlayContentNode {
if isHidden && !self.buttonNode.isSelected {
buttonPosition = CGPoint(x: size.width - insets.right - buttonSize.width - 59.0, y: -50.0)
} else {
buttonPosition = CGPoint(x: size.width - insets.right - buttonSize.width - (self.buttonNode.isSelected ? 24.0 : 59.0), y: insets.top - 50.0)
buttonPosition = CGPoint(x: size.width - insets.right - buttonSize.width - (self.buttonNode.isSelected ? 24.0 : 59.0), y: insets.top - 58.0)
}
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: buttonPosition, size: CGSize(width: buttonSize.width + 24.0, height: buttonSize.height + 24.0)))

View file

@ -2113,6 +2113,10 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
}
}
self.selectedButtonNode.action = { [weak self] in
self?.selectedPressed()
}
self.navigationItem.titleView = self.titleView
if case let .assets(collection, mode) = self.subject, mode != .default {
@ -2185,8 +2189,6 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
// }
// }
self.selectedButtonNode.addTarget(self, action: #selector(self.selectedPressed), forControlEvents: .touchUpInside)
self.scrollToTop = { [weak self] in
if let strongSelf = self {
if let webSearchController = strongSelf.webSearchController {
@ -4030,12 +4032,13 @@ public func coverMediaPickerController(
return controller
}
private class SelectedButtonNode: HighlightTrackingButtonNode {
private class SelectedButtonNode: ASDisplayNode {
private let containerView: UIView
private let backgroundView: GlassBackgroundView?
private let background: ASImageNode?
private let icon = ASImageNode()
private let label = ImmediateAnimatedCountLabelNode()
private let button = HighlightTrackingButton()
private let glass: Bool
@ -4051,6 +4054,8 @@ private class SelectedButtonNode: HighlightTrackingButtonNode {
private var count: Int32 = 0
var action: () -> Void = {}
init(theme: PresentationTheme, glass: Bool) {
self.theme = theme
self.glass = glass
@ -4076,6 +4081,9 @@ private class SelectedButtonNode: HighlightTrackingButtonNode {
self.view.addSubview(self.containerView)
if let backgroundView = self.backgroundView {
backgroundView.contentView.addSubnode(self.icon)
backgroundView.contentView.addSubnode(self.label)
backgroundView.contentView.addSubview(self.button)
self.containerView.addSubview(backgroundView)
}
if let background = self.background {
@ -4083,35 +4091,19 @@ private class SelectedButtonNode: HighlightTrackingButtonNode {
self.containerView.addSubnode(background)
}
self.containerView.addSubnode(self.icon)
self.containerView.addSubnode(self.label)
self.highligthedChanged = { [weak self] highlighted in
if let self {
if glass {
let transition = ComponentTransition(animation: .curve(duration: highlighted ? 0.25 : 0.35, curve: .spring))
if highlighted {
transition.setScale(view: self.containerView, scale: 1.2)
} else {
transition.setScale(view: self.containerView, scale: 1.0)
}
} else {
if highlighted {
self.containerView.layer.removeAnimation(forKey: "opacity")
self.containerView.alpha = 0.4
} else {
self.containerView.alpha = 1.0
self.containerView.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
}
self.button.addTarget(self, action: #selector(self.tapped), for: .touchUpInside)
}
@objc private func tapped() {
self.action()
}
func update(count: Int32) -> CGSize {
self.count = count
let diameter: CGFloat = self.glass ? 40.0 : 21.0
let diameter: CGFloat = self.glass ? 44.0 : 21.0
let font = self.glass ? Font.with(size: 17.0, weight: .medium, traits: [.monospacedNumbers]) : Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers])
let stringValue = "\(max(1, count))"
@ -4147,11 +4139,13 @@ private class SelectedButtonNode: HighlightTrackingButtonNode {
self.containerView.frame = backgroundFrame
if let backgroundView = self.backgroundView {
backgroundView.frame = backgroundFrame
backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.size.height * 0.5, isDark: false, tintColor: .init(kind: .custom, color: self.theme.list.itemCheckColors.fillColor), transition: .immediate)
backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.size.height * 0.5, isDark: false, tintColor: .init(kind: .custom, color: self.theme.list.itemCheckColors.fillColor), isInteractive: true, transition: .immediate)
}
if let background = self.background {
background.frame = backgroundFrame
}
self.button.frame = CGRect(origin: .zero, size: size)
return size
}

View file

@ -1766,15 +1766,24 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
} else if let dice = media as? TelegramMediaDice, let gameOutcome = dice.gameOutcome {
if let value = dice.value {
//TODO:localize
let rawString: String
if value == 1, let tonAmount = dice.tonAmount {
let value = formatTonAmountText(tonAmount, dateTimeFormat: dateTimeFormat)
rawString = "You lost $\(value)"
if message.author?.id == accountPeerId {
if value == 1, let tonAmount = dice.tonAmount {
let value = formatTonAmountText(tonAmount, dateTimeFormat: dateTimeFormat)
rawString = strings.Conversation_EmojiStake_LostYou(value).string
} else {
let value = formatTonAmountText(gameOutcome.tonAmount, dateTimeFormat: dateTimeFormat)
rawString = strings.Conversation_EmojiStake_WonYou(value).string
}
} else {
let value = formatTonAmountText(gameOutcome.tonAmount, dateTimeFormat: dateTimeFormat)
rawString = "You won $\(value)"
let compactPeerName = message.peers[message.id.peerId].flatMap(EnginePeer.init)?.compactDisplayTitle ?? ""
if value == 1, let tonAmount = dice.tonAmount {
let value = formatTonAmountText(tonAmount, dateTimeFormat: dateTimeFormat)
rawString = strings.Conversation_EmojiStake_Lost(compactPeerName, value).string
} else {
let value = formatTonAmountText(gameOutcome.tonAmount, dateTimeFormat: dateTimeFormat)
rawString = strings.Conversation_EmojiStake_Won(compactPeerName, value).string
}
}
let attributedText = NSMutableAttributedString(string: rawString, font: titleFont, textColor: primaryTextColor)

View file

@ -76,7 +76,7 @@ private final class SheetContent: CombinedComponent {
let controller = environment.controller
let theme = environment.theme.withModalBlocksBackground()
//let strings = environment.strings
let strings = environment.strings
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
@ -91,10 +91,9 @@ private final class SheetContent: CombinedComponent {
return (TelegramTextAttributes.URL, contents)
})
//TODO:localize
let description = description.update(
component: BalancedTextComponent(
text: .markdown(text: "An experimental feature for Telegram Premium users.", attributes: markdownAttributes),
text: .markdown(text: strings.EmojiStake_Description, attributes: markdownAttributes),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.2
@ -110,7 +109,7 @@ private final class SheetContent: CombinedComponent {
let resultsTitle = resultsTitle.update(
component: MultilineTextComponent(text: .plain(NSAttributedString(
string: "RESULTS AND RETURNS".uppercased(),
string: strings.EmojiStake_ResultsTitle.uppercased(),
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: theme.list.freeTextColor
))),
@ -186,14 +185,14 @@ private final class SheetContent: CombinedComponent {
contentSize.height += 7.0
let resultsFooterAttributedText = NSMutableAttributedString(
string: "A streak resets after 3 # or a stake change.",
string: strings.EmojiStake_StreakInfo,
font: Font.regular(13.0),
textColor: theme.list.freeTextColor
)
if let emojiFile = state.emojiFiles?[6] {
let range = (resultsFooterAttributedText.string as NSString).range(of: "#")
if range.location != NSNotFound {
resultsFooterAttributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: emojiFile.fileId.id, file: emojiFile), range: range)
resultsFooterAttributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: emojiFile, custom: .dice, enableAnimation: false), range: range)
}
}
@ -240,7 +239,7 @@ private final class SheetContent: CombinedComponent {
forceMinValue: false,
allowZero: true,
maxValue: nil,
placeholderText: "Amount",
placeholderText: strings.EmojiStake_StakePlaceholder,
labelText: amountLabel,
currency: .ton,
dateTimeFormat: presentationData.dateTimeFormat,
@ -272,14 +271,13 @@ private final class SheetContent: CombinedComponent {
))
]
//TODO:localize
let amountSection = amountSection.update(
component: ListSectionComponent(
theme: theme,
style: .glass,
header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "STAKE".uppercased(),
string: strings.EmojiStake_StakeTitle.uppercased(),
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: theme.list.freeTextColor
)),
@ -301,10 +299,9 @@ private final class SheetContent: CombinedComponent {
contentSize.height += 24.0
//TODO:localize
var buttonItems: [AnyComponentWithIdentity<Empty>] = []
buttonItems.append(AnyComponentWithIdentity(id: "icon", component: AnyComponent(BundleIconComponent(name: "Premium/Dice", tintColor: theme.list.itemCheckColors.foregroundColor))))
buttonItems.append(AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: "Save and Roll", font: Font.semibold(17.0), color: theme.list.itemCheckColors.foregroundColor))))
buttonItems.append(AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: environment.strings.EmojiStake_Roll, font: Font.semibold(17.0), color: theme.list.itemCheckColors.foregroundColor))))
let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let button = button.update(
@ -449,7 +446,7 @@ private final class EmojiGameStakeSheetComponent: CombinedComponent {
var buttonItems: [AnyComponentWithIdentity<Empty>] = []
buttonItems.append(AnyComponentWithIdentity(id: "icon", component: AnyComponent(Image(image: PresentationResourcesItemList.itemListRoundTopupIcon(environment.theme), tintColor: theme.list.itemCheckColors.foregroundColor, size: CGSize(width: 16.0, height: 18.0)))))
buttonItems.append(AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: "Save and Roll", font: Font.semibold(17.0), color: theme.list.itemCheckColors.foregroundColor))))
buttonItems.append(AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: environment.strings.EmojiStake_Roll, font: Font.semibold(17.0), color: theme.list.itemCheckColors.foregroundColor))))
let sheet = sheet.update(
component: ResizableSheetComponent<EnvironmentType>(
@ -464,7 +461,7 @@ private final class EmojiGameStakeSheetComponent: CombinedComponent {
}
)),
titleItem: AnyComponent(
Text(text: "Emoji Stake", font: Font.bold(17.0), color: theme.list.itemPrimaryTextColor)
Text(text: environment.strings.EmojiStake_Title, font: Font.bold(17.0), color: theme.list.itemPrimaryTextColor)
),
leftItem: AnyComponent(
GlassBarButtonComponent(

View file

@ -19,6 +19,8 @@ import TelegramUIPreferences
import GenerateStickerPlaceholderImage
import UIKitRuntimeUtils
import ComponentFlow
import RLottieBinding
import GZip
public func generateTopicIcon(title: String, backgroundColors: [UIColor], strokeColors: [UIColor], size: CGSize) -> UIImage? {
let realSize = size
@ -497,6 +499,10 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
case .verification:
self.updateVerification()
self.updateTintColor()
case .dice:
if let file {
self.updateDice(file: file, attemptSynchronousLoad: attemptSynchronousLoad)
}
}
} else if let file = file {
self.updateFile(file: file, attemptSynchronousLoad: attemptSynchronousLoad)
@ -720,6 +726,44 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
}
}
private func updateDice(file: TelegramMediaFile, attemptSynchronousLoad: Bool) {
guard let arguments = self.arguments else {
return
}
let _ = (arguments.context.postbox.mediaBox.resourceData(file.resource)
|> filter { resource in
return resource.complete
}
|> map { resource -> UIImage? in
guard var data = try? Data(contentsOf: URL(fileURLWithPath: resource.path)) else {
return nil
}
if let unpackedData = TGGUnzipData(data, 5 * 1024 * 1024) {
data = unpackedData
}
guard let instance = LottieInstance(data: data, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
return nil
}
let size = CGSize(width: 128.0, height: 128.0)
if let diceContext = DrawingContext(size: size, scale: 1.0, opaque: false, clear: true) {
instance.renderFrame(with: instance.frameCount - 1, into: diceContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(diceContext.scaledSize.width), height: Int32(diceContext.scaledSize.height), bytesPerRow: Int32(diceContext.bytesPerRow))
if let diceImage = diceContext.generateImage() {
let drawingContext = DrawingContext(size: size, scale: 1.0, opaque: false, clear: true)
drawingContext?.withFlippedContext { context in
if let cgImage = diceImage.cgImage {
context.draw(cgImage, in: CGRect(origin: CGPoint(x: -30.0, y: 5.0), size: CGSize(width: 180.0, height: 180.0)))
}
}
return drawingContext?.generateImage()
}
}
return nil
}
|> deliverOnMainQueue).start(next: { image in
self.contents = image?.cgImage
})
}
private func loadLocalAnimation() {
guard let arguments = self.arguments else {
return

View file

@ -632,7 +632,7 @@ private final class PeerInfoScreenBusinessHoursItemNode: PeerInfoScreenItemNode
topOffset += dayHeights
}
topOffset += 11.0
topOffset += 15.0
transition.updateFrame(node: self.labelNode, frame: labelFrame)

View file

@ -484,18 +484,18 @@ private final class FilterHeaderButton: HighlightableButtonNode {
component: AnyComponent(
BundleIconComponent(
name: "Peer Info/SortIcon",
tintColor: theme.rootController.navigationBar.accentTextColor
tintColor: theme.chat.inputPanel.panelControlColor
)
),
environment: {},
containerSize: CGSize(width: 30.0, height: 30.0)
containerSize: CGSize(width: 44.0, height: 44.0)
)
if let view = self.icon.view {
if view.superview == nil {
view.isUserInteractionEnabled = false
self.referenceNode.view.addSubview(view)
}
view.frame = CGRect(origin: CGPoint(x: 14.0, y: 7.0), size: iconSize)
view.frame = CGRect(origin: CGPoint(x: 7.0, y: 7.0), size: iconSize)
}
self.containerNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 44.0, height: 44.0))

View file

@ -67,10 +67,9 @@ extension ChatControllerImpl {
var changeAction: String?
var tonAmount: Int64?
if canSendMessages, emoji == "🎲", case let .available(info) = gameInfo {
//TODO:localize
let currentStake = info.previousStake
value = "Stake: $ \(formatTonAmountText(currentStake, dateTimeFormat: self.presentationData.dateTimeFormat))"
changeAction = "change"
value = "\(self.presentationData.strings.Conversation_Dice_Stake) $ \(formatTonAmountText(currentStake, dateTimeFormat: self.presentationData.dateTimeFormat))"
changeAction = self.presentationData.strings.Conversation_Dice_Change
tonAmount = info.previousStake
} else {
switch emoji {