diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 39a607c37e..84d31a91ec 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10150,3 +10150,5 @@ Sorry for the inconvenience."; "Chat.ErrorQuoteOutdatedTitle" = "Quote Outdated"; "Chat.ErrorQuoteOutdatedText" = "**%@** updated the message you are quoting. Edit your quote to make it up-to-date."; "Chat.ErrorQuoteOutdatedActionEdit" = "Edit"; + +"Premium.BoostByGiftDescription" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()"; diff --git a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift index 9782c7e54e..eaf1617170 100644 --- a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift @@ -1471,7 +1471,7 @@ private final class LimitSheetContent: CombinedComponent { state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, environment.theme) } - let giftString = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()" + let giftString = environment.strings.Premium_BoostByGiftDescription let giftAttributedString = parseMarkdownIntoAttributedString(giftString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift index a5acfc25b6..d5426b3767 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdatePeerInfo.swift @@ -91,6 +91,7 @@ func _internal_updatePeerDescription(account: Account, peerId: PeerId, descripti public enum UpdatePeerNameColorAndEmojiError { case generic + case channelBoostRequired } func _internal_updatePeerNameColorAndEmoji(account: Account, peerId: EnginePeer.Id, nameColor: PeerNameColor, backgroundEmojiId: Int64?) -> Signal { @@ -111,7 +112,10 @@ func _internal_updatePeerNameColorAndEmoji(account: Account, peerId: EnginePeer. if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) { let flags: Int32 = (1 << 0) return account.network.request(Api.functions.channels.updateColor(flags: flags, channel: inputChannel, color: nameColor.rawValue, backgroundEmojiId: backgroundEmojiId ?? 0)) - |> mapError { _ -> UpdatePeerNameColorAndEmojiError in + |> mapError { error -> UpdatePeerNameColorAndEmojiError in + if error.errorDescription.hasPrefix("BOOSTS_REQUIRED") { + return .channelBoostRequired + } return .generic } |> mapToSignal { result -> Signal in diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index 63f6416e56..00dbfccf2f 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -302,9 +302,6 @@ public enum PresentationResourceKey: Int32 { case chatReplyBackgroundTemplateOutgoingDashedImage case chatReplyServiceBackgroundTemplateImage - case chatReplyLineDashTemplateIncomingImage - case chatReplyLineDashTemplateOutgoingImage - case chatBubbleCloseIcon } diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift index e5a44c1fb9..041ad859be 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesChat.swift @@ -1319,38 +1319,6 @@ public struct PresentationResourcesChat { }) } - public static func chatReplyLineDashTemplateImage(_ theme: PresentationTheme, incoming: Bool) -> UIImage? { - let key: PresentationResourceKey = incoming ? .chatReplyLineDashTemplateIncomingImage : .chatReplyLineDashTemplateOutgoingImage - return theme.image(key.rawValue, { theme in - let radius: CGFloat = 3.0 - let offset: CGFloat = incoming ? 5.0 : -3.0 - - return generateImage(CGSize(width: 12.0, height: radius * 6.0), rotatedContext: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - - context.move(to: CGPoint(x: radius, y: offset)) - context.addLine(to: CGPoint(x: radius, y: offset + radius * 3.0)) - context.addLine(to: CGPoint(x: 0.0, y: offset + radius * 4.0)) - context.addLine(to: CGPoint(x: 0.0, y: offset + radius)) - context.closePath() - - context.setFillColor(UIColor.white.cgColor) - context.fillPath() - - if !incoming { - context.move(to: CGPoint(x: radius, y: size.height + offset)) - context.addLine(to: CGPoint(x: radius, y: size.height + offset + radius * 3.0)) - context.addLine(to: CGPoint(x: 0.0, y: size.height + offset + radius * 4.0)) - context.addLine(to: CGPoint(x: 0.0, y: size.height + offset + radius)) - context.closePath() - - context.setFillColor(UIColor.white.cgColor) - context.fillPath() - } - })?.resizableImage(withCapInsets: .zero, resizingMode: .tile).withRenderingMode(.alwaysTemplate) - }) - } - public static func chatBubbleCloseIcon(_ theme: PresentationTheme) -> UIImage? { return theme.image(PresentationResourceKey.chatBubbleCloseIcon.rawValue, { theme in return generateImage(CGSize(width: 12.0, height: 12.0), rotatedContext: { size, context in diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift index 7abcd20972..acfa010dda 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift @@ -748,31 +748,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { pattern: pattern, animation: animation ) - - let _ = secondaryColor - /*if let secondaryColor { - let lineDashView: UIImageView - if let current = node.lineDashView { - lineDashView = current - } else { - lineDashView = UIImageView(image: PresentationResourcesChat.chatReplyLineDashTemplateImage(arguments.presentationData.theme.theme, incoming: isIncoming)) - lineDashView.clipsToBounds = true - node.lineDashView = lineDashView - node.contentNode.view.addSubview(lineDashView) - } - lineDashView.tintColor = secondaryColor - lineDashView.frame = CGRect(origin: .zero, size: CGSize(width: 12.0, height: backgroundFrame.height)) - lineDashView.layer.cornerRadius = 6.0 - if #available(iOS 13.0, *) { - lineDashView.layer.cornerCurve = .continuous - } - } else { - if let lineDashView = node.lineDashView { - node.lineDashView = nil - lineDashView.removeFromSuperview() - } - }*/ - + if arguments.quote != nil || arguments.replyForward?.quote != nil { let quoteIconView: UIImageView if let current = node.quoteIconView { diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD index 62d50a0c84..2dc1c20ba1 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD @@ -25,6 +25,7 @@ swift_library( "//submodules/TelegramUI/Components/EntityKeyboard", "//submodules/SolidRoundedButtonNode", "//submodules/AppBundle", + "//submodules/PremiumUI", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ApplyColorFooterItem.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ApplyColorFooterItem.swift index ad232e351f..6b8c2eec29 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ApplyColorFooterItem.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ApplyColorFooterItem.swift @@ -12,18 +12,20 @@ final class ApplyColorFooterItem: ItemListControllerFooterItem { let theme: PresentationTheme let title: String let locked: Bool + let inProgress: Bool let action: () -> Void - init(theme: PresentationTheme, title: String, locked: Bool, action: @escaping () -> Void) { + init(theme: PresentationTheme, title: String, locked: Bool, inProgress: Bool, action: @escaping () -> Void) { self.theme = theme self.title = title self.locked = locked + self.inProgress = inProgress self.action = action } func isEqual(to: ItemListControllerFooterItem) -> Bool { if let item = to as? ApplyColorFooterItem { - return self.theme === item.theme && self.title == item.title && self.locked == item.locked + return self.theme === item.theme && self.title == item.title && self.locked == item.locked && self.inProgress == item.inProgress } else { return false } @@ -63,6 +65,7 @@ final class ApplyColorFooterItemNode: ItemListControllerFooterItemNode { self.buttonNode = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: .black, foregroundColor: .white), height: 50.0, cornerRadius: 11.0) self.buttonNode.icon = item.locked ? UIImage(bundleImageName: "Chat/Stickers/Lock") : nil + self.buttonNode.progressType = .embedded super.init() @@ -73,6 +76,7 @@ final class ApplyColorFooterItemNode: ItemListControllerFooterItemNode { self.updateItem() } + private var inProgress = false private func updateItem() { self.backgroundNode.updateColor(color: self.item.theme.rootController.tabBar.backgroundColor, transition: .immediate) self.separatorNode.backgroundColor = self.item.theme.rootController.tabBar.separatorColor @@ -87,6 +91,16 @@ final class ApplyColorFooterItemNode: ItemListControllerFooterItemNode { self.buttonNode.pressed = { [weak self] in self?.item.action() } + + if self.inProgress != self.item.inProgress { + self.inProgress = true + + if self.item.inProgress { + self.buttonNode.transitionToProgress() + } else { + self.buttonNode.transitionFromProgress() + } + } } override func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) { diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift index 393d6e172e..375a200043 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift @@ -12,6 +12,7 @@ import PresentationDataUtils import AccountContext import UndoUI import EntityKeyboard +import PremiumUI private final class PeerNameColorScreenArguments { let context: AccountContext @@ -180,6 +181,7 @@ private enum PeerNameColorScreenEntry: ItemListNodeEntry { private struct PeerNameColorScreenState: Equatable { var updatedNameColor: PeerNameColor? var updatedBackgroundEmojiId: Int64? + var inProgress: Bool = false } private func peerNameColorScreenEntries( @@ -392,6 +394,7 @@ public func PeerNameColorScreen( theme: presentationData.theme, title: buttonTitle, locked: isLocked, + inProgress: state.inProgress, action: { if !isLocked { let state = stateValue.with { $0 } @@ -402,13 +405,52 @@ public func PeerNameColorScreen( switch subject { case .account: let _ = context.engine.accountData.updateNameColorAndEmoji(nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone() + dismissImpl?() case let .channel(peerId): - let _ = context.engine.peers.updatePeerNameColorAndEmoji(peerId: peerId, nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone() + updateState { state in + var updatedState = state + updatedState.inProgress = true + return updatedState + } + let _ = context.engine.peers.updatePeerNameColorAndEmoji(peerId: peerId, nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone(next: { + }, error: { error in + if case .channelBoostRequired = error { + let _ = combineLatest( + queue: Queue.mainQueue(), + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)), + context.engine.peers.getChannelBoostStatus(peerId: peerId) + ).startStandalone(next: { peer, status in + guard let peer, let status else { + return + } + + let link = status.url + let controller = PremiumLimitScreen(context: context, subject: .storiesChannelBoost(peer: peer, isCurrent: true, level: Int32(status.level), currentLevelBoosts: Int32(status.currentLevelBoosts), nextLevelBoosts: status.nextLevelBoosts.flatMap(Int32.init), link: link, myBoostCount: 0), count: Int32(status.boosts), action: { + UIPasteboard.general.string = link + presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })) + return true + }, openStats: nil, openGift: { + let controller = createGiveawayController(context: context, peerId: peerId, subject: .generic) + pushImpl?(controller) + }) + pushImpl?(controller) + + HapticFeedback().impact(.light) + }) + } else { + + } + updateState { state in + var updatedState = state + updatedState.inProgress = true + return updatedState + } + }, completed: { + dismissImpl?() + }) } - - dismissImpl?() } else { - HapticFeedback().error() + HapticFeedback().impact(.light) let controller = UndoOverlayController( presentationData: presentationData, content: .premiumPaywall( diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 6e7a508d67..7112dcbb90 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -8387,6 +8387,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro if let self { self.openStats(boosts: true, boostStatus: status) } + }, openGift: { [weak self] in + if let self { + let controller = createGiveawayController(context: self.context, peerId: self.peerId, subject: .generic) + self.controller?.push(controller) + } }) navigationController.pushViewController(controller) }