Various fixes

This commit is contained in:
Ilya Laktyushin 2025-02-14 21:44:19 +04:00
parent fd38d2ea9b
commit c0184d4114
7 changed files with 177 additions and 140 deletions

View File

@ -13801,3 +13801,10 @@ Sorry for the inconvenience.";
"Notification.StarsGift.TransferToChannel" = "%@ transferred a unique collectible to %@"; "Notification.StarsGift.TransferToChannel" = "%@ transferred a unique collectible to %@";
"Notification.StarsGift.TransferToChannelYou" = "You transferred a unique collectible to %@"; "Notification.StarsGift.TransferToChannelYou" = "You transferred a unique collectible to %@";
"Gift.Convert.Success.ChannelText" = "**%1$@** were sent to channel's balance.";
"Gift.Convert.Success.ChannelText.Stars_1" = "%@ Star";
"Gift.Convert.Success.ChannelText.Stars_any" = "%@ Stars";
"Stars.Transfer.Terms" = "By purchasing you agree to the [Terms of Service]().";
"Stars.Transfer.Terms_URL" = "https://telegram.org/tos/stars";

View File

@ -962,7 +962,11 @@
[_coverImageCache setImage:image forKey:itemId attributes:NULL]; [_coverImageCache setImage:image forKey:itemId attributes:NULL];
_coverImagePipe.sink([TGMediaImageUpdate imageUpdateWithItem:item representation:image]); _coverImagePipe.sink([TGMediaImageUpdate imageUpdateWithItem:item representation:image]);
if (position != nil) {
[_coverPositions setObject:position forKey:itemId]; [_coverPositions setObject:position forKey:itemId];
} else {
[_coverPositions removeObjectForKey:itemId];
}
} }
- (void)setFullSizeImage:(UIImage *)image forItem:(id<TGMediaEditableItem>)item - (void)setFullSizeImage:(UIImage *)image forItem:(id<TGMediaEditableItem>)item

View File

@ -355,13 +355,13 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
let signal: Signal<([(String?, FoundStickerItem)], FoundStickerSets, Bool, FoundStickerSets?)?, NoError> let signal: Signal<([(String?, FoundStickerItem)], FoundStickerSets, Bool, FoundStickerSets?)?, NoError>
if !text.isEmpty { if !text.isEmpty {
let context = self.context let context = self.context
let stickers: Signal<[(String?, FoundStickerItem)], NoError> = Signal { subscriber in let stickers: Signal<([(String?, FoundStickerItem)], Bool), NoError> = Signal { subscriber in
var signals: Signal<[Signal<(String?, [FoundStickerItem]), NoError>], NoError> = .single([]) var signals: Signal<[Signal<(String?, [FoundStickerItem], Bool), NoError>], NoError> = .single([])
let query = text.trimmingCharacters(in: .whitespacesAndNewlines) let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
if query.isSingleEmoji { if query.isSingleEmoji {
signals = .single([context.engine.stickers.searchStickers(query: nil, emoticon: [text.basicEmoji.0]) signals = .single([context.engine.stickers.searchStickers(query: nil, emoticon: [text.basicEmoji.0])
|> map { (nil, $0.items) }]) |> map { (nil, $0.items, $0.isFinalResult) }])
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" { } else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3) var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
if !languageCode.lowercased().hasPrefix("en") { if !languageCode.lowercased().hasPrefix("en") {
@ -377,10 +377,10 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
} }
} }
signals = signal signals = signal
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in |> map { keywords -> [Signal<(String?, [FoundStickerItem], Bool), NoError>] in
let emoticon = keywords.flatMap { $0.emoticons }.map { $0.basicEmoji.0 } let emoticon = keywords.flatMap { $0.emoticons }.map { $0.basicEmoji.0 }
return [context.engine.stickers.searchStickers(query: query, emoticon: emoticon, inputLanguageCode: languageCode) return [context.engine.stickers.searchStickers(query: query, emoticon: emoticon, inputLanguageCode: languageCode)
|> map { (nil, $0.items) }] |> map { (nil, $0.items, $0.isFinalResult) }]
} }
} }
@ -389,12 +389,16 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
return combineLatest(signals) return combineLatest(signals)
}).start(next: { results in }).start(next: { results in
var result: [(String?, FoundStickerItem)] = [] var result: [(String?, FoundStickerItem)] = []
for (emoji, stickers) in results { var allAreFinal = true
for (emoji, stickers, isFinal) in results {
for sticker in stickers { for sticker in stickers {
result.append((emoji, sticker)) result.append((emoji, sticker))
} }
if !isFinal {
allAreFinal = false
} }
subscriber.putNext(result) }
subscriber.putNext((result, allAreFinal))
}, completed: { }, completed: {
// subscriber.putCompletion() // subscriber.putCompletion()
}) })
@ -456,7 +460,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
signal = combineLatest(stickers, packs) signal = combineLatest(stickers, packs)
|> map { stickers, packs -> ([(String?, FoundStickerItem)], FoundStickerSets, Bool, FoundStickerSets?)? in |> map { stickers, packs -> ([(String?, FoundStickerItem)], FoundStickerSets, Bool, FoundStickerSets?)? in
return (stickers, packs.0, packs.1, packs.2) return (stickers.0, packs.0, packs.1 && stickers.1, packs.2)
} }
self.updateActivity?(true) self.updateActivity?(true)
} else { } else {

View File

@ -344,22 +344,24 @@ final class GiftSetupScreenComponent: Component {
let entities = generateChatInputTextEntities(self.textInputState.text) let entities = generateChatInputTextEntities(self.textInputState.text)
let source: BotPaymentInvoiceSource = .starGift(hideName: self.hideName, includeUpgrade: self.includeUpgrade, peerId: peerId, giftId: starGift.id, text: self.textInputState.text.string, entities: entities) let source: BotPaymentInvoiceSource = .starGift(hideName: self.hideName, includeUpgrade: self.includeUpgrade, peerId: peerId, giftId: starGift.id, text: self.textInputState.text.string, entities: entities)
let inputData = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|> map(Optional.init)
|> `catch` { _ -> Signal<BotCheckoutController.InputData?, NoError> in
return .single(nil)
}
let completion = component.completion let completion = component.completion
let _ = (inputData let signal = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|> deliverOnMainQueue).startStandalone(next: { [weak self] inputData in |> `catch` { _ -> Signal<BotCheckoutController.InputData, SendBotPaymentFormError> in
guard let inputData else { return .fail(.generic)
}
|> mapToSignal { inputData -> Signal<SendBotPaymentResult, SendBotPaymentFormError> in
return component.context.engine.payments.sendStarsPaymentForm(formId: inputData.form.id, source: source)
}
|> deliverOnMainQueue
let _ = signal.start(next: { [weak self] result in
guard let self, let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController else {
return return
} }
let _ = (component.context.engine.payments.sendStarsPaymentForm(formId: inputData.form.id, source: source)
|> deliverOnMainQueue).start(next: { [weak self] result in if peerId.namespace == Namespaces.Peer.CloudChannel {
if let self, peerId.namespace == Namespaces.Peer.CloudChannel, let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController {
var controllers = navigationController.viewControllers var controllers = navigationController.viewControllers
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) } controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) }
navigationController.setViewControllers(controllers, animated: true) navigationController.setViewControllers(controllers, animated: true)
@ -380,20 +382,7 @@ final class GiftSetupScreenComponent: Component {
(navigationController.viewControllers.last as? ViewController)?.present(tooltipController, in: .current) (navigationController.viewControllers.last as? ViewController)?.present(tooltipController, in: .current)
navigationController.view.addSubview(ConfettiView(frame: navigationController.view.bounds)) navigationController.view.addSubview(ConfettiView(frame: navigationController.view.bounds))
} } else if peerId.namespace == Namespaces.Peer.CloudUser {
if let completion {
completion()
if let self, let controller = self.environment?.controller() {
controller.dismiss()
}
} else {
guard let self, let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController else {
return
}
if peerId.namespace != Namespaces.Peer.CloudChannel {
var controllers = navigationController.viewControllers var controllers = navigationController.viewControllers
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) } controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) }
var foundController = false var foundController = false
@ -411,6 +400,13 @@ final class GiftSetupScreenComponent: Component {
} }
navigationController.setViewControllers(controllers, animated: true) navigationController.setViewControllers(controllers, animated: true)
} }
if let completion {
completion()
if let controller = self.environment?.controller() {
controller.dismiss()
}
} }
starsContext.load(force: true) starsContext.load(force: true)
@ -436,7 +432,6 @@ final class GiftSetupScreenComponent: Component {
controller.present(alertController, in: .window(.root)) controller.present(alertController, in: .window(.root))
} }
}) })
})
} }
if starsState.balance < StarsAmount(value: finalPrice, nanos: 0) { if starsState.balance < StarsAmount(value: finalPrice, nanos: 0) {

View File

@ -3112,11 +3112,14 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
} }
self.entitiesView.canInteract = { [weak self] in self.entitiesView.canInteract = { [weak self] in
if let self, let controller = self.controller { if let self, let controller = self.controller {
return !controller.node.recording.isActive if controller.node.recording.isActive {
} else { return false
return true } else if case .avatarEditor = controller.mode, self.drawingScreen == nil {
return false
} }
} }
return true
}
self.availableReactionsDisposable = (allowedStoryReactions(context: controller.context) self.availableReactionsDisposable = (allowedStoryReactions(context: controller.context)
|> deliverOnMainQueue).start(next: { [weak self] reactions in |> deliverOnMainQueue).start(next: { [weak self] reactions in
@ -3252,11 +3255,12 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
if let mediaEntityView = self.entitiesView.add(mediaEntity, announce: false) as? DrawingMediaEntityView { if let mediaEntityView = self.entitiesView.add(mediaEntity, announce: false) as? DrawingMediaEntityView {
self.entitiesView.sendSubviewToBack(mediaEntityView) self.entitiesView.sendSubviewToBack(mediaEntityView)
mediaEntityView.updated = { [weak self, weak mediaEntity] in mediaEntityView.updated = { [weak self, weak mediaEntity] in
if let self, let mediaEntity { if let self, let mediaEditor = self.mediaEditor, let mediaEntity {
let rotation = mediaEntity.rotation - initialRotation let rotation = mediaEntity.rotation - initialRotation
let position = CGPoint(x: mediaEntity.position.x - initialPosition.x, y: mediaEntity.position.y - initialPosition.y) let position = CGPoint(x: mediaEntity.position.x - initialPosition.x, y: mediaEntity.position.y - initialPosition.y)
let scale = mediaEntity.scale / initialScale let scale = mediaEntity.scale / initialScale
self.mediaEditor?.setCrop(offset: position, scale: scale, rotation: rotation, mirroring: false) let mirroring = mediaEditor.values.cropMirroring
mediaEditor.setCrop(offset: position, scale: scale, rotation: rotation, mirroring: mirroring)
self.updateMaskDrawingView(position: position, scale: scale, rotation: rotation) self.updateMaskDrawingView(position: position, scale: scale, rotation: rotation)
} }
@ -3465,6 +3469,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
} }
return false return false
}) as? DrawingStickerEntityView { }) as? DrawingStickerEntityView {
#if DEBUG
if let data = result.dayImage.pngData() {
let path = NSTemporaryDirectory() + "\(Int(Date().timeIntervalSince1970)).png"
try? data.write(to: URL(fileURLWithPath: path))
}
#endif
existingEntityView.isNightTheme = isNightTheme existingEntityView.isNightTheme = isNightTheme
let messageEntity = existingEntityView.entity as! DrawingStickerEntity let messageEntity = existingEntityView.entity as! DrawingStickerEntity
messageEntity.renderImage = result.dayImage messageEntity.renderImage = result.dayImage
@ -5613,6 +5624,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
self.previousDrawingData = self.drawingView.drawingData self.previousDrawingData = self.drawingView.drawingData
self.previousDrawingEntities = self.entitiesView.entities self.previousDrawingEntities = self.entitiesView.entities
self.cropScrollView?.isUserInteractionEnabled = false
self.interaction?.deactivate() self.interaction?.deactivate()
let controller = DrawingScreen( let controller = DrawingScreen(
context: self.context, context: self.context,
@ -5668,6 +5681,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
self.previousDrawingData = nil self.previousDrawingData = nil
self.previousDrawingEntities = nil self.previousDrawingEntities = nil
self.cropScrollView?.isUserInteractionEnabled = true
} }
controller.requestApply = { [weak controller, weak self] in controller.requestApply = { [weak controller, weak self] in
guard let self else { guard let self else {
@ -5690,6 +5705,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
self.interaction?.activate() self.interaction?.activate()
self.entitiesView.selectEntity(nil) self.entitiesView.selectEntity(nil)
self.cropScrollView?.isUserInteractionEnabled = true
} }
self.controller?.present(controller, in: .current) self.controller?.present(controller, in: .current)
self.animateOutToTool(tool: mode) self.animateOutToTool(tool: mode)
@ -7594,6 +7611,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
let values = mediaEditor.values.withUpdatedCoverDimensions(dimensions) let values = mediaEditor.values.withUpdatedCoverDimensions(dimensions)
makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, outputDimensions: dimensions.aspectFitted(CGSize(width: 1080, height: 1080)), values: values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in makeEditorImageComposition(context: self.node.ciContext, postbox: self.context.account.postbox, inputImage: image, dimensions: storyDimensions, outputDimensions: dimensions.aspectFitted(CGSize(width: 1080, height: 1080)), values: values, time: .zero, textScale: 2.0, completion: { [weak self] resultImage in
if let self, let resultImage { if let self, let resultImage {
#if DEBUG
if let data = resultImage.jpegData(compressionQuality: 0.7) {
let path = NSTemporaryDirectory() + "\(Int(Date().timeIntervalSince1970)).jpg"
try? data.write(to: URL(fileURLWithPath: path))
}
#endif
self.completion(MediaEditorScreenImpl.Result(media: .image(image: resultImage, dimensions: PixelDimensions(resultImage.size))), { [weak self] finished in self.completion(MediaEditorScreenImpl.Result(media: .image(image: resultImage, dimensions: PixelDimensions(resultImage.size))), { [weak self] finished in
self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in
self?.dismiss() self?.dismiss()

View File

@ -141,11 +141,11 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
} }
public func scrollViewDidScroll(_ scrollView: UIScrollView) { public func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.updateScrolling(transition: .immediate) self.updateScrolling(interactive: true, transition: .immediate)
} }
private var notify = false private var notify = false
func updateScrolling(transition: ComponentTransition) { func updateScrolling(interactive: Bool = false, transition: ComponentTransition) {
if let starsProducts = self.starsProducts, let params = self.currentParams { if let starsProducts = self.starsProducts, let params = self.currentParams {
let optionSpacing: CGFloat = 10.0 let optionSpacing: CGFloat = 10.0
let itemsSideInset = params.sideInset + 16.0 let itemsSideInset = params.sideInset + 16.0
@ -644,7 +644,7 @@ 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) let bottomContentOffset = max(0.0, self.scrollNode.view.contentSize.height - self.scrollNode.view.contentOffset.y - self.scrollNode.view.frame.height)
if bottomContentOffset < 200.0 { if interactive, bottomContentOffset < 200.0 {
self.profileGifts.loadMore() self.profileGifts.loadMore()
} }
} }

View File

@ -293,9 +293,11 @@ private final class SheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: background.size.height / 2.0)) .position(CGPoint(x: context.availableSize.width / 2.0, y: background.size.height / 2.0))
) )
var isExtendedMedia = false
let subject: StarsImageComponent.Subject let subject: StarsImageComponent.Subject
if !component.extendedMedia.isEmpty { if !component.extendedMedia.isEmpty {
subject = .extendedMedia(component.extendedMedia) subject = .extendedMedia(component.extendedMedia)
isExtendedMedia = true
} else if let peer = state.botPeer { } else if let peer = state.botPeer {
if let photo = component.invoice.photo { if let photo = component.invoice.photo {
subject = .photo(photo) subject = .photo(photo)
@ -381,7 +383,7 @@ private final class SheetContent: CombinedComponent {
contentSize.height += title.size.height contentSize.height += title.size.height
contentSize.height += 13.0 contentSize.height += 13.0
if isBot, let peer = state.botPeer { if isBot && !isExtendedMedia, let peer = state.botPeer {
contentSize.height -= 3.0 contentSize.height -= 3.0
let peerShortcut = peerShortcut.update( let peerShortcut = peerShortcut.update(
component: PremiumPeerShortcutComponent( component: PremiumPeerShortcutComponent(
@ -650,7 +652,10 @@ private final class SheetContent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0)) .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0))
) )
contentSize.height += button.size.height contentSize.height += button.size.height
if isSubscription {
let termsText = isSubscription ? strings.Stars_Subscription_Terms : strings.Stars_Transfer_Terms
let termsURL = isSubscription ? strings.Stars_Subscription_Terms_URL : strings.Stars_Transfer_Terms_URL
contentSize.height += 14.0 contentSize.height += 14.0
let termsTextFont = Font.regular(13.0) let termsTextFont = Font.regular(13.0)
@ -662,7 +667,7 @@ private final class SheetContent: CombinedComponent {
let info = info.update( let info = info.update(
component: BalancedTextComponent( component: BalancedTextComponent(
text: .markdown( text: .markdown(
text: strings.Stars_Subscription_Terms, text: termsText,
attributes: termsMarkdownAttributes attributes: termsMarkdownAttributes
), ),
horizontalAlignment: .center, horizontalAlignment: .center,
@ -679,7 +684,7 @@ private final class SheetContent: CombinedComponent {
tapAction: { [weak controller] attributes, _ in tapAction: { [weak controller] attributes, _ in
if let controller, let navigationController = controller.navigationController as? NavigationController { if let controller, let navigationController = controller.navigationController as? NavigationController {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_Subscription_Terms_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {}) component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: termsURL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
} }
} }
), ),
@ -691,8 +696,6 @@ private final class SheetContent: CombinedComponent {
) )
contentSize.height += info.size.height contentSize.height += info.size.height
}
contentSize.height += 48.0 contentSize.height += 48.0
return contentSize return contentSize