From fe81be793121b8051cd274f98ebadcffe23606ca Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 14 Feb 2025 05:10:07 +0400 Subject: [PATCH] Various fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 3 + .../StickerPaneSearchContentNode.swift | 20 +++-- .../Sources/GiftSetupScreen.swift | 48 +++++----- .../Sources/MediaEditorScreen.swift | 34 ++++++-- .../Sources/StarsTransferScreen.swift | 87 ++++++++++--------- 5 files changed, 112 insertions(+), 80 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index b87a9e3f50..c93eb4a2ab 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -13838,3 +13838,6 @@ Sorry for the inconvenience."; "Notification.PaidMessage" = "%1$@ paid %2$@ to send a message"; "Notification.PaidMessageYou" = "You paid %1$@ to send a message"; + +"Stars.Transfer.Terms" = "By purchasing you agree to the [Terms of Service]()."; +"Stars.Transfer.Terms_URL" = "https://telegram.org/tos/stars"; diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/StickerPaneSearchContentNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/StickerPaneSearchContentNode.swift index 23230d48ba..ef37c0f7d8 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/StickerPaneSearchContentNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/StickerPaneSearchContentNode.swift @@ -355,13 +355,13 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode { let signal: Signal<([(String?, FoundStickerItem)], FoundStickerSets, Bool, FoundStickerSets?)?, NoError> if !text.isEmpty { let context = self.context - let stickers: Signal<[(String?, FoundStickerItem)], NoError> = Signal { subscriber in - var signals: Signal<[Signal<(String?, [FoundStickerItem]), NoError>], NoError> = .single([]) + let stickers: Signal<([(String?, FoundStickerItem)], Bool), NoError> = Signal { subscriber in + var signals: Signal<[Signal<(String?, [FoundStickerItem], Bool), NoError>], NoError> = .single([]) let query = text.trimmingCharacters(in: .whitespacesAndNewlines) if query.isSingleEmoji { 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" { var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3) if !languageCode.lowercased().hasPrefix("en") { @@ -377,10 +377,10 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode { } } 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 } 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) }).start(next: { results in var result: [(String?, FoundStickerItem)] = [] - for (emoji, stickers) in results { + var allAreFinal = true + for (emoji, stickers, isFinal) in results { for sticker in stickers { result.append((emoji, sticker)) } + if !isFinal { + allAreFinal = false + } } - subscriber.putNext(result) + subscriber.putNext((result, allAreFinal)) }, completed: { // subscriber.putCompletion() }) @@ -456,7 +460,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode { signal = combineLatest(stickers, packs) |> 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) } else { diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index 04b0378c1f..d0144399a3 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -382,7 +382,11 @@ final class GiftSetupScreenComponent: Component { } let _ = (component.context.engine.payments.sendStarsPaymentForm(formId: inputData.form.id, source: source) |> deliverOnMainQueue).start(next: { [weak self] result in - if let self, peerId.namespace == Namespaces.Peer.CloudChannel, let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController { + 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 controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) } navigationController.setViewControllers(controllers, animated: true) @@ -403,37 +407,31 @@ final class GiftSetupScreenComponent: Component { (navigationController.viewControllers.last as? ViewController)?.present(tooltipController, in: .current) navigationController.view.addSubview(ConfettiView(frame: navigationController.view.bounds)) + } else if peerId.namespace == Namespaces.Peer.CloudUser { + var controllers = navigationController.viewControllers + controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) } + var foundController = false + for controller in controllers.reversed() { + if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation { + chatController.hintPlayNextOutgoingGift() + foundController = true + break + } + } + if !foundController { + let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil) + chatController.hintPlayNextOutgoingGift() + controllers.append(chatController) + } + navigationController.setViewControllers(controllers, animated: true) } if let completion { completion() - if let self, let controller = self.environment?.controller() { + if 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 - controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) } - var foundController = false - for controller in controllers.reversed() { - if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation { - chatController.hintPlayNextOutgoingGift() - foundController = true - break - } - } - if !foundController { - let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil) - chatController.hintPlayNextOutgoingGift() - controllers.append(chatController) - } - navigationController.setViewControllers(controllers, animated: true) - } } starsContext.load(force: true) diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index ed70d21472..62f71b1247 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -3112,10 +3112,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID } self.entitiesView.canInteract = { [weak self] in if let self, let controller = self.controller { - return !controller.node.recording.isActive - } else { - return true + if controller.node.recording.isActive { + return false + } else if case .avatarEditor = controller.mode, self.drawingScreen == nil { + return false + } } + return true } self.availableReactionsDisposable = (allowedStoryReactions(context: controller.context) @@ -3252,11 +3255,12 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID if let mediaEntityView = self.entitiesView.add(mediaEntity, announce: false) as? DrawingMediaEntityView { self.entitiesView.sendSubviewToBack(mediaEntityView) 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 position = CGPoint(x: mediaEntity.position.x - initialPosition.x, y: mediaEntity.position.y - initialPosition.y) 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) } @@ -3465,6 +3469,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID } return false }) 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 let messageEntity = existingEntityView.entity as! DrawingStickerEntity messageEntity.renderImage = result.dayImage @@ -5613,6 +5624,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID self.previousDrawingData = self.drawingView.drawingData self.previousDrawingEntities = self.entitiesView.entities + self.cropScrollView?.isUserInteractionEnabled = false + self.interaction?.deactivate() let controller = DrawingScreen( context: self.context, @@ -5668,6 +5681,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID self.previousDrawingData = nil self.previousDrawingEntities = nil + + self.cropScrollView?.isUserInteractionEnabled = true } controller.requestApply = { [weak controller, weak self] in guard let self else { @@ -5690,6 +5705,8 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID self.interaction?.activate() self.entitiesView.selectEntity(nil) + + self.cropScrollView?.isUserInteractionEnabled = true } self.controller?.present(controller, in: .current) self.animateOutToTool(tool: mode) @@ -7594,6 +7611,13 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID 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 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?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.dismiss() diff --git a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift index faa93b6892..46cbbfaf0a 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransferScreen/Sources/StarsTransferScreen.swift @@ -294,9 +294,11 @@ private final class SheetContent: CombinedComponent { .position(CGPoint(x: context.availableSize.width / 2.0, y: background.size.height / 2.0)) ) + var isExtendedMedia = false let subject: StarsImageComponent.Subject if !component.extendedMedia.isEmpty { subject = .extendedMedia(component.extendedMedia) + isExtendedMedia = true } else if let peer = state.botPeer { if let photo = component.invoice.photo { subject = .photo(photo) @@ -382,7 +384,7 @@ private final class SheetContent: CombinedComponent { contentSize.height += title.size.height contentSize.height += 13.0 - if isBot, let peer = state.botPeer { + if isBot && !isExtendedMedia, let peer = state.botPeer { contentSize.height -= 3.0 let peerShortcut = peerShortcut.update( component: PremiumPeerShortcutComponent( @@ -651,48 +653,49 @@ private final class SheetContent: CombinedComponent { .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0)) ) contentSize.height += button.size.height - if isSubscription { - contentSize.height += 14.0 - - let termsTextFont = Font.regular(13.0) - let termsTextColor = theme.actionSheet.secondaryTextColor - let termsLinkColor = theme.actionSheet.controlAccentColor - let termsMarkdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: termsTextFont, textColor: termsTextColor), bold: MarkdownAttributeSet(font: termsTextFont, textColor: termsTextColor), link: MarkdownAttributeSet(font: termsTextFont, textColor: termsLinkColor), linkAttribute: { contents in - return (TelegramTextAttributes.URL, contents) - }) - let info = info.update( - component: BalancedTextComponent( - text: .markdown( - text: strings.Stars_Subscription_Terms, - attributes: termsMarkdownAttributes - ), - horizontalAlignment: .center, - maximumNumberOfLines: 0, - lineSpacing: 0.2, - highlightColor: linkColor.withAlphaComponent(0.2), - highlightAction: { attributes in - if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { - return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) - } else { - return nil - } - }, - tapAction: { [weak controller] attributes, _ in - if let controller, let navigationController = controller.navigationController as? NavigationController { - 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: {}) - } - } + + 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 + + let termsTextFont = Font.regular(13.0) + let termsTextColor = theme.actionSheet.secondaryTextColor + let termsLinkColor = theme.actionSheet.controlAccentColor + let termsMarkdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: termsTextFont, textColor: termsTextColor), bold: MarkdownAttributeSet(font: termsTextFont, textColor: termsTextColor), link: MarkdownAttributeSet(font: termsTextFont, textColor: termsLinkColor), linkAttribute: { contents in + return (TelegramTextAttributes.URL, contents) + }) + let info = info.update( + component: BalancedTextComponent( + text: .markdown( + text: termsText, + attributes: termsMarkdownAttributes ), - availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height), - transition: .immediate - ) - context.add(info - .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + info.size.height / 2.0)) - ) - contentSize.height += info.size.height - - } + horizontalAlignment: .center, + maximumNumberOfLines: 0, + lineSpacing: 0.2, + highlightColor: linkColor.withAlphaComponent(0.2), + highlightAction: { attributes in + if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { + return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) + } else { + return nil + } + }, + tapAction: { [weak controller] attributes, _ in + if let controller, let navigationController = controller.navigationController as? NavigationController { + let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } + component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: termsURL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {}) + } + } + ), + availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height), + transition: .immediate + ) + context.add(info + .position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + info.size.height / 2.0)) + ) + contentSize.height += info.size.height contentSize.height += 48.0