diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index f7b9e72e03..333ddbb20a 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7615,3 +7615,6 @@ Sorry for the inconvenience."; "Settings.Terms_URL" = "https://telegram.org/tos"; "Settings.PrivacyPolicy_URL" = "https://telegram.org/privacy"; + +"Stickers.PremiumPackInfoText" = "This pack contains premium stickers like this one."; +"Stickers.PremiumPackView" = "View"; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 4d79b0f308..2deba07c1e 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -258,6 +258,7 @@ public enum ResolvedUrl { case importStickers case startAttach(peerId: PeerId, payload: String?) case invoice(slug: String, invoice: TelegramMediaInvoice) + case premiumOffer(reference: String?) } public enum NavigateToChatKeepStack { diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 04ef073a42..484eb934b5 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -569,7 +569,7 @@ public class AttachmentController: ViewController { ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear).updateAlpha(node: self.dim, alpha: 1.0) let targetPosition = self.container.position - let startPosition = targetPosition.offsetBy(dx: 0.0, dy: self.bounds.height) + let startPosition = targetPosition.offsetBy(dx: 0.0, dy: layout.size.height) self.container.position = startPosition let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) @@ -785,7 +785,9 @@ public class AttachmentController: ViewController { } let controllers = self.currentControllers - containerTransition.updateFrame(node: self.container, frame: CGRect(origin: CGPoint(), size: containerRect.size)) + if !self.animating { + containerTransition.updateFrame(node: self.container, frame: CGRect(origin: CGPoint(), size: containerRect.size)) + } let containerLayout = containerLayout.withUpdatedIntrinsicInsets(containerInsets) diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index 3de098e3ac..11289d6b63 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -331,7 +331,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch var replaceImpl: ((ViewController) -> Void)? let controller = PremiumLimitScreen(context: context, subject: .pins, count: Int32(count), action: { - let premiumScreen = PremiumIntroScreen(context: context) + let premiumScreen = PremiumIntroScreen(context: context, source: .pinnedChats) replaceImpl?(premiumScreen) }) chatListController?.push(controller) diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index c2e351b421..babb43440c 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -1349,7 +1349,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController if data.includePeers.peers.count >= limit { var replaceImpl: ((ViewController) -> Void)? let controller = PremiumLimitScreen(context: context, subject: .chatsInFolder, count: Int32(data.includePeers.peers.count), action: { - let controller = PremiumIntroScreen(context: context) + let controller = PremiumIntroScreen(context: context, source: .chatsPerFolder) replaceImpl?(controller) }) replaceImpl = { [weak controller] c in diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift index 2c2a3f0fe9..e5af1b03e1 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListController.swift @@ -299,7 +299,7 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch if filters.count >= limit { var replaceImpl: ((ViewController) -> Void)? let controller = PremiumLimitScreen(context: context, subject: .folders, count: Int32(filters.count), action: { - let controller = PremiumIntroScreen(context: context) + let controller = PremiumIntroScreen(context: context, source: .folders) replaceImpl?(controller) }) replaceImpl = { [weak controller] c in diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index c57f9f9272..95258e6e61 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -830,30 +830,44 @@ public final class ChatListNode: ListView { } } }, setItemPinned: { [weak self] itemId, _ in - let location: TogglePeerChatPinnedLocation - if let chatListFilter = chatListFilter { - location = .filter(chatListFilter.id) - } else { - location = .group(groupId._asGroup()) - } - let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: itemId) - |> deliverOnMainQueue).start(next: { result in - if let strongSelf = self { - switch result { - case .done: - break - case let .limitExceeded(count, _): - var replaceImpl: ((ViewController) -> Void)? - let controller = PremiumLimitScreen(context: context, subject: .pins, count: Int32(count), action: { - let premiumScreen = PremiumIntroScreen(context: context) - replaceImpl?(premiumScreen) - }) - replaceImpl = { [weak controller] c in - controller?.replace(with: c) - } - strongSelf.push?(controller) - } + let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + let isPremium = peer?.isPremium ?? false + let location: TogglePeerChatPinnedLocation + if let chatListFilter = chatListFilter { + location = .filter(chatListFilter.id) + } else { + location = .group(groupId._asGroup()) } + let _ = (context.engine.peers.toggleItemPinned(location: location, itemId: itemId) + |> deliverOnMainQueue).start(next: { result in + if let strongSelf = self { + switch result { + case .done: + break + case let .limitExceeded(count, limit): + if isPremium { + let text: String + if chatListFilter != nil { + text = strongSelf.currentState.presentationData.strings.DialogList_UnknownPinLimitError + } else { + text = strongSelf.currentState.presentationData.strings.DialogList_PinLimitError("\(limit)").string + } + strongSelf.presentAlert?(text) + } else { + var replaceImpl: ((ViewController) -> Void)? + let controller = PremiumLimitScreen(context: context, subject: .pins, count: Int32(count), action: { + let premiumScreen = PremiumIntroScreen(context: context, source: .pinnedChats) + replaceImpl?(premiumScreen) + }) + replaceImpl = { [weak controller] c in + controller?.replace(with: c) + } + strongSelf.push?(controller) + } + } + } + }) }) }, setPeerMuted: { [weak self] peerId, _ in guard let strongSelf = self else { diff --git a/submodules/Display/Source/HapticFeedback.swift b/submodules/Display/Source/HapticFeedback.swift index bff1e5489c..bad8b9c59b 100644 --- a/submodules/Display/Source/HapticFeedback.swift +++ b/submodules/Display/Source/HapticFeedback.swift @@ -121,6 +121,14 @@ private final class HapticFeedbackImpl { } } + func warning() { + if let notificationGenerator = self.notificationGenerator { + notificationGenerator.notificationOccurred(.warning) + } else { + + } + } + @objc dynamic func f() { } } @@ -205,6 +213,14 @@ public final class HapticFeedback { } } } + + public func warning() { + if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { + self.withImpl { impl in + impl.warning() + } + } + } } @available(iOS 13.0, *) diff --git a/submodules/Display/Source/Navigation/NavigationController.swift b/submodules/Display/Source/Navigation/NavigationController.swift index b7a9f8bd23..1717cde87b 100644 --- a/submodules/Display/Source/Navigation/NavigationController.swift +++ b/submodules/Display/Source/Navigation/NavigationController.swift @@ -361,6 +361,18 @@ open class NavigationController: UINavigationController, ContainableController, private func updateContainers(layout rawLayout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { self.isUpdatingContainers = true + if let badgeNode = self.badgeNode, let image = badgeNode.image { + let badgeIsHidden = !rawLayout.deviceMetrics.hasTopNotch || rawLayout.size.width > rawLayout.size.height + if badgeIsHidden != badgeNode.isHidden && !badgeIsHidden { + Queue.mainQueue().after(0.3) { + badgeNode.isHidden = badgeIsHidden + } + } else { + badgeNode.isHidden = badgeIsHidden + } + badgeNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((rawLayout.size.width - image.size.width) / 2.0), y: 6.0), size: image.size) + } + var layout = rawLayout if self.ignoreInputHeight { @@ -631,6 +643,7 @@ open class NavigationController: UINavigationController, ContainableController, var topVisibleModalContainerWithStatusBar: NavigationModalContainer? var visibleModalCount = 0 var topModalIsFlat = false + var topFlatModalHasProgress = false let isLandscape = layout.orientation == .landscape var hasVisibleStandaloneModal = false var topModalDismissProgress: CGFloat = 0.0 @@ -659,6 +672,17 @@ open class NavigationController: UINavigationController, ContainableController, effectiveModalTransition = 1.0 } + if navigationLayout.modal[i].isFlat, let lastController = navigationLayout.modal[i].controllers.last { + lastController.modalStyleOverlayTransitionFactorUpdated = { [weak self] transition in + guard let strongSelf = self else { + return + } + strongSelf.updateContainersNonReentrant(transition: transition) + } + modalStyleOverlayTransitionFactor = max(modalStyleOverlayTransitionFactor, lastController.modalStyleOverlayTransitionFactor) + topFlatModalHasProgress = modalStyleOverlayTransitionFactor > 0.0 + } + containerTransition.updateFrame(node: modalContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) modalContainer.update(layout: modalContainer.isFlat ? overlayLayout : layout, controllers: navigationLayout.modal[i].controllers, coveredByModalTransition: effectiveModalTransition, transition: containerTransition) @@ -862,9 +886,15 @@ open class NavigationController: UINavigationController, ContainableController, let visibleRootModalDismissProgress: CGFloat var additionalModalFrameProgress: CGFloat if visibleModalCount == 1 { - effectiveRootModalDismissProgress = (topModalIsFlat || isLandscape) ? 1.0 : topModalDismissProgress - visibleRootModalDismissProgress = effectiveRootModalDismissProgress - additionalModalFrameProgress = 0.0 + if topFlatModalHasProgress { + effectiveRootModalDismissProgress = 0.0 + visibleRootModalDismissProgress = effectiveRootModalDismissProgress + additionalModalFrameProgress = 1.0 - topModalDismissProgress + } else { + effectiveRootModalDismissProgress = ((topModalIsFlat && !topFlatModalHasProgress) || isLandscape) ? 1.0 : topModalDismissProgress + visibleRootModalDismissProgress = effectiveRootModalDismissProgress + additionalModalFrameProgress = 0.0 + } } else if visibleModalCount >= 2 { effectiveRootModalDismissProgress = 0.0 visibleRootModalDismissProgress = topModalDismissProgress @@ -929,7 +959,7 @@ open class NavigationController: UINavigationController, ContainableController, } let maxScale: CGFloat let maxOffset: CGFloat - if topModalIsFlat || isLandscape { + if (topModalIsFlat && !topFlatModalHasProgress) || isLandscape { maxScale = 1.0 maxOffset = 0.0 } else if visibleModalCount <= 1 { @@ -1219,8 +1249,16 @@ open class NavigationController: UINavigationController, ContainableController, self.displayNode.addSubnode(inCallStatusBar) } } + + let badgeNode = ASImageNode() + badgeNode.displaysAsynchronously = false + badgeNode.image = UIImage(bundleImageName: "Components/BadgeTest") + self.badgeNode = badgeNode + self.displayNode.addSubnode(badgeNode) } + private var badgeNode: ASImageNode? + public func pushViewController(_ controller: ViewController) { self.pushViewController(controller, completion: {}) } diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index f23892fc47..6d2f0128e4 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -1256,8 +1256,12 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: nil, text: presentationData.strings.Gallery_GifSaved), elevatedLayout: true, animateInAsReplacement: true, action: { _ in return false }), nil) } })) - } else if file.mimeType.hasPrefix("image/") || file.mimeType.hasPrefix("video/") { + } else if file.mimeType.hasPrefix("image/") { preferredAction = .saveToCameraRoll + actionCompletionText = strongSelf.presentationData.strings.Gallery_ImageSaved + } else if file.mimeType.hasPrefix("video/") { + preferredAction = .saveToCameraRoll + actionCompletionText = strongSelf.presentationData.strings.Gallery_VideoSaved } } } @@ -1335,6 +1339,12 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll shareController.dismissed = { [weak self] _ in self?.interacting?(false) } + shareController.actionCompleted = { [weak self, weak shareController] in + if let strongSelf = self, let shareController = shareController, shareController.actionIsMediaSaving { + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: presentationData.strings.Gallery_ImageSaved), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil) + } + } shareController.completed = { [weak self] peerIds in if let strongSelf = self { let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in diff --git a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift index 1a54b7c61d..b0b5242ae6 100644 --- a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift @@ -356,6 +356,13 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { case .translate: if let parentController = strongSelf.baseNavigationController()?.topViewController as? ViewController { let controller = TranslateScreen(context: strongSelf.context, text: string, fromLanguage: nil) + controller.pushController = { [weak parentController] c in + (parentController?.navigationController as? NavigationController)?._keepModalDismissProgress = true + parentController?.push(c) + } + controller.presentController = { [weak parentController] c in + parentController?.present(c, in: .window(.root)) + } parentController.present(controller, in: .window(.root)) } } diff --git a/submodules/InstantPageCache/Sources/CachedInternalInstantPages.swift b/submodules/InstantPageCache/Sources/CachedInternalInstantPages.swift index 07d32a5e33..5b468626b6 100644 --- a/submodules/InstantPageCache/Sources/CachedInternalInstantPages.swift +++ b/submodules/InstantPageCache/Sources/CachedInternalInstantPages.swift @@ -3,7 +3,6 @@ import SwiftSignalKit import Postbox import TelegramCore import AccountContext -//import InstantPageUI import UrlHandling public func extractAnchor(string: String) -> (String, String?) { diff --git a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift index 89f2642a16..7cfb25ff52 100644 --- a/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageControllerNode.swift @@ -1096,6 +1096,13 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { if canTranslate { actions.append(ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuTranslate, accessibilityLabel: strings.Conversation_ContextMenuTranslate), action: { [weak self] in let controller = TranslateScreen(context: context, text: text, fromLanguage: language) + controller.pushController = { [weak self] c in + (self?.controller?.navigationController as? NavigationController)?._keepModalDismissProgress = true + self?.controller?.push(c) + } + controller.presentController = { [weak self] c in + self?.controller?.present(c, in: .window(.root)) + } self?.present(controller, nil) })) } diff --git a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift index 6f2fbef360..601d3ae87a 100644 --- a/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelVisibilityController.swift @@ -1630,7 +1630,7 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta if hasNamesToRevoke && selectedType == .publicChannel { footerItem = IncreaseLimitFooterItem(theme: presentationData.theme, title: presentationData.strings.Premium_IncreaseLimit, colorful: true, action: { - let controller = PremiumIntroScreen(context: context) + let controller = PremiumIntroScreen(context: context, source: .publicLinks) pushControllerImpl?(controller) }) } diff --git a/submodules/PeerInfoUI/Sources/OldChannelsController.swift b/submodules/PeerInfoUI/Sources/OldChannelsController.swift index 32ae339284..c344f0991a 100644 --- a/submodules/PeerInfoUI/Sources/OldChannelsController.swift +++ b/submodules/PeerInfoUI/Sources/OldChannelsController.swift @@ -326,7 +326,7 @@ public func oldChannelsController(context: AccountContext, updatedPresentationDa if state.selectedPeers.count > 0 { leaveActionImpl?() } else { - let controller = PremiumIntroScreen(context: context) + let controller = PremiumIntroScreen(context: context, source: .groupsAndChannels) pushImpl?(controller) } }) diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index e7cc10b0ef..2f6d2b64e9 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -3,11 +3,13 @@ import UIKit import Display import ComponentFlow import SwiftSignalKit +import TelegramCore +import TelegramPresentationData +import PresentationDataUtils import ViewControllerComponent import AccountContext import SolidRoundedButtonComponent import MultilineTextComponent -import PresentationDataUtils import PrefixSectionGroupComponent import BundleIconComponent import SolidRoundedButtonComponent @@ -17,6 +19,236 @@ import ConfettiEffect import TextFormat import InstantPageCache +public enum PremiumSource { + case settings + case stickers + case reactions + case ads + case groupsAndChannels + case pinnedChats + case publicLinks + case savedGifs + case savedStickers + case folders + case chatsPerFolder + case accounts + + var identifier: String { + switch self { + case .settings: + return "settings" + case .stickers: + return "premium_stickers" + case .reactions: + return "unique_reactions" + case .ads: + return "no_ads" + case .groupsAndChannels: + return "double_limits__channels" + case .pinnedChats: + return "double_limits__dialog_pinned" + case .publicLinks: + return "double_limits__channels_public" + case .savedGifs: + return "double_limits__saved_gifs" + case .savedStickers: + return "double_limits__stickers_faved" + case .folders: + return "double_limits__dialog_filters" + case .chatsPerFolder: + return "double_limits__dialog_filters_chats" + case .accounts: + return "double_limits__accounts" + } + } +} + +private enum PremiumPerk: CaseIterable { + case doubleLimits + case moreUpload + case fasterDownload + case voiceToText + case noAds + case uniqueReactions + case premiumStickers + case advancedChatManagement + case profileBadge + case animatedUserpics + + static var allCases: [PremiumPerk] { + return [ + .doubleLimits, + .moreUpload, + .fasterDownload, + .voiceToText, + .noAds, + .uniqueReactions, + .premiumStickers, + .advancedChatManagement, + .profileBadge, + .animatedUserpics + ] + } + + init?(identifier: String) { + for perk in PremiumPerk.allCases { + if perk.identifier == identifier { + self = perk + return + } + } + return nil + } + + var identifier: String { + switch self { + case .doubleLimits: + return "double_limits" + case .moreUpload: + return "more_upload" + case .fasterDownload: + return "faster_download" + case .voiceToText: + return "voice_to_text" + case .noAds: + return "no_ads" + case .uniqueReactions: + return "unique_reactions" + case .premiumStickers: + return "premium_stickers" + case .advancedChatManagement: + return "advanced_chat_management" + case .profileBadge: + return "profile_badge" + case .animatedUserpics: + return "animated_userpics" + } + } + + func title(strings: PresentationStrings) -> String { + switch self { + case .doubleLimits: + return strings.Premium_DoubledLimits + case .moreUpload: + return strings.Premium_UploadSize + case .fasterDownload: + return strings.Premium_FasterSpeed + case .voiceToText: + return strings.Premium_VoiceToText + case .noAds: + return strings.Premium_NoAds + case .uniqueReactions: + return strings.Premium_Reactions + case .premiumStickers: + return strings.Premium_Stickers + case .advancedChatManagement: + return strings.Premium_ChatManagement + case .profileBadge: + return strings.Premium_Badge + case .animatedUserpics: + return strings.Premium_Avatar + } + } + + func subtitle(strings: PresentationStrings) -> String { + switch self { + case .doubleLimits: + return strings.Premium_DoubledLimitsInfo + case .moreUpload: + return strings.Premium_UploadSizeInfo + case .fasterDownload: + return strings.Premium_FasterSpeedInfo + case .voiceToText: + return strings.Premium_VoiceToTextInfo + case .noAds: + return strings.Premium_NoAdsInfo + case .uniqueReactions: + return strings.Premium_ReactionsInfo + case .premiumStickers: + return strings.Premium_StickersInfo + case .advancedChatManagement: + return strings.Premium_ChatManagementInfo + case .profileBadge: + return strings.Premium_BadgeInfo + case .animatedUserpics: + return strings.Premium_AvatarInfo + } + } + + var iconName: String { + switch self { + case .doubleLimits: + return "Premium/Perk/Limits" + case .moreUpload: + return "Premium/Perk/Upload" + case .fasterDownload: + return "Premium/Perk/Speed" + case .voiceToText: + return "Premium/Perk/Voice" + case .noAds: + return "Premium/Perk/NoAds" + case .uniqueReactions: + return "Premium/Perk/Reactions" + case .premiumStickers: + return "Premium/Perk/Stickers" + case .advancedChatManagement: + return "Premium/Perk/Chat" + case .profileBadge: + return "Premium/Perk/Badge" + case .animatedUserpics: + return "Premium/Perk/Avatar" + } + } +} + +private struct PremiumIntroConfiguration { + static var defaultValue: PremiumIntroConfiguration { + return PremiumIntroConfiguration(perks: [ + .doubleLimits, + .moreUpload, + .fasterDownload, + .voiceToText, + .noAds, + .uniqueReactions, + .premiumStickers, + .advancedChatManagement, + .profileBadge, + .animatedUserpics + ]) + } + + let perks: [PremiumPerk] + + fileprivate init(perks: [PremiumPerk]) { + self.perks = perks + } + + public static func with(appConfiguration: AppConfiguration) -> PremiumIntroConfiguration { + if let data = appConfiguration.data, let values = data["premium_promo_order"] as? [String] { + var perks: [PremiumPerk] = [] + for value in values { + if let perk = PremiumPerk(identifier: value) { + if !perks.contains(perk) { + perks.append(perk) + } else { + perks = [] + break + } + } else { + perks = [] + break + } + } + if perks.count < 4 { + perks = PremiumIntroConfiguration.defaultValue.perks + } + return PremiumIntroConfiguration(perks: perks) + } else { + return .defaultValue + } + } +} + private final class SectionGroupComponent: Component { public final class Item: Equatable { public let content: AnyComponentWithIdentity @@ -495,6 +727,40 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { return true } + final class State: ComponentState { + private let context: AccountContext + + private var disposable: Disposable? + var configuration = PremiumIntroConfiguration.defaultValue + + init(context: AccountContext) { + self.context = context + + super.init() + + self.disposable = (context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) + |> map { view -> AppConfiguration in + let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue + return appConfiguration + } + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] appConfiguration in + if let strongSelf = self { + strongSelf.configuration = PremiumIntroConfiguration.with(appConfiguration: appConfiguration) + strongSelf.updated(transition: .immediate) + } + }) + } + + deinit { + self.disposable?.dispose() + } + } + + func makeState() -> State { + return State(context: self.context) + } + static var body: Body { let overscroll = Child(Rectangle.self) let fade = Child(RoundedRectangle.self) @@ -510,6 +776,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { let scrollEnvironment = context.environment[ScrollChildEnvironment.self].value let environment = context.environment[ViewControllerComponentContainer.Environment.self].value + let state = context.state let theme = environment.theme let strings = environment.strings @@ -576,230 +843,52 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { size.height += text.size.height size.height += 21.0 + let gradientColors: [(UIColor, UIColor)] = [ + (UIColor(rgb: 0xF28528), UIColor(rgb: 0xEF7633)), + (UIColor(rgb: 0xEA5F43), UIColor(rgb: 0xE7504E)), + (UIColor(rgb: 0xDE4768), UIColor(rgb: 0xD54D82)), + (UIColor(rgb: 0xDE4768), UIColor(rgb: 0xD54D82)), + (UIColor(rgb: 0xC654A8), UIColor(rgb: 0xBE5AC2)), + (UIColor(rgb: 0xAF62E9), UIColor(rgb: 0xA668FF)), + (UIColor(rgb: 0x9674FF), UIColor(rgb: 0x8C7DFF)), + (UIColor(rgb: 0x9674FF), UIColor(rgb: 0x8C7DFF)), + (UIColor(rgb: 0x7B88FF), UIColor(rgb: 0x7091FF)), + (UIColor(rgb: 0x609DFF), UIColor(rgb: 0x56A5FF)) + ] + + var items: [SectionGroupComponent.Item] = [] + + var i = 0 + for perk in state.configuration.perks { + let iconBackgroundColors = gradientColors[i] + items.append(SectionGroupComponent.Item( + AnyComponentWithIdentity( + id: perk.identifier, + component: AnyComponent( + PerkComponent( + iconName: perk.iconName, + iconBackgroundColors: [ + iconBackgroundColors.0, + iconBackgroundColors.1 + ], + title: perk.title(strings: strings), + titleColor: titleColor, + subtitle: perk.subtitle(strings: strings), + subtitleColor: subtitleColor, + arrowColor: arrowColor + ) + ) + ), + action: { + + } + )) + i += 1 + } + let section = section.update( component: SectionGroupComponent( - items: [ - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "limits", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Limits", - iconBackgroundColors: [ - UIColor(rgb: 0xF28528), - UIColor(rgb: 0xEF7633) - ], - title: strings.Premium_DoubledLimits, - titleColor: titleColor, - subtitle: strings.Premium_DoubledLimitsInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "upload", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Upload", - iconBackgroundColors: [ - UIColor(rgb: 0xEA5F43), - UIColor(rgb: 0xE7504E) - ], - title: strings.Premium_UploadSize, - titleColor: titleColor, - subtitle: strings.Premium_UploadSizeInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "speed", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Speed", - iconBackgroundColors: [ - UIColor(rgb: 0xDE4768), - UIColor(rgb: 0xD54D82) - ], - title: strings.Premium_FasterSpeed, - titleColor: titleColor, - subtitle: strings.Premium_FasterSpeedInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "voice", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Voice", - iconBackgroundColors: [ - UIColor(rgb: 0xDE4768), - UIColor(rgb: 0xD54D82) - ], - title: strings.Premium_VoiceToText, - titleColor: titleColor, - subtitle: strings.Premium_VoiceToTextInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "noAds", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/NoAds", - iconBackgroundColors: [ - UIColor(rgb: 0xC654A8), - UIColor(rgb: 0xBE5AC2) - ], - title: strings.Premium_NoAds, - titleColor: titleColor, - subtitle: strings.Premium_NoAdsInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "reactions", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Reactions", - iconBackgroundColors: [ - UIColor(rgb: 0xAF62E9), - UIColor(rgb: 0xA668FF) - ], - title: strings.Premium_Reactions, - titleColor: titleColor, - subtitle: strings.Premium_ReactionsInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "stickers", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Stickers", - iconBackgroundColors: [ - UIColor(rgb: 0x9674FF), - UIColor(rgb: 0x8C7DFF) - ], - title: strings.Premium_Stickers, - titleColor: titleColor, - subtitle: strings.Premium_StickersInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "chat", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Chat", - iconBackgroundColors: [ - UIColor(rgb: 0x9674FF), - UIColor(rgb: 0x8C7DFF) - ], - title: strings.Premium_ChatManagement, - titleColor: titleColor, - subtitle: strings.Premium_ChatManagementInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "badge", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Badge", - iconBackgroundColors: [ - UIColor(rgb: 0x7B88FF), - UIColor(rgb: 0x7091FF) - ], - title: strings.Premium_Badge, - titleColor: titleColor, - subtitle: strings.Premium_BadgeInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - SectionGroupComponent.Item( - AnyComponentWithIdentity( - id: "avatar", - component: AnyComponent( - PerkComponent( - iconName: "Premium/Perk/Avatar", - iconBackgroundColors: [ - UIColor(rgb: 0x609DFF), - UIColor(rgb: 0x56A5FF) - ], - title: strings.Premium_Avatar, - titleColor: titleColor, - subtitle: strings.Premium_AvatarInfo, - subtitleColor: subtitleColor, - arrowColor: arrowColor - ) - ) - ), - action: { - - } - ), - ], + items: items, backgroundColor: environment.theme.list.itemBlocksBackgroundColor, selectionColor: environment.theme.list.itemHighlightedBackgroundColor, separatorColor: environment.theme.list.itemBlocksSeparatorColor @@ -808,6 +897,241 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { availableSize: CGSize(width: availableWidth - sideInsets, height: .greatestFiniteMagnitude), transition: context.transition ) + +// + +// let section = section.update( +// component: SectionGroupComponent( +// items: [ +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "limits", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Limits", +// iconBackgroundColors: [ +// UIColor(rgb: 0xF28528), +// UIColor(rgb: 0xEF7633) +// ], +// title: strings.Premium_DoubledLimits, +// titleColor: titleColor, +// subtitle: strings.Premium_DoubledLimitsInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "upload", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Upload", +// iconBackgroundColors: [ +// UIColor(rgb: 0xEA5F43), +// UIColor(rgb: 0xE7504E) +// ], +// title: strings.Premium_UploadSize, +// titleColor: titleColor, +// subtitle: strings.Premium_UploadSizeInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "speed", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Speed", +// iconBackgroundColors: [ +// UIColor(rgb: 0xDE4768), +// UIColor(rgb: 0xD54D82) +// ], +// title: strings.Premium_FasterSpeed, +// titleColor: titleColor, +// subtitle: strings.Premium_FasterSpeedInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "voice", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Voice", +// iconBackgroundColors: [ +// UIColor(rgb: 0xDE4768), +// UIColor(rgb: 0xD54D82) +// ], +// title: strings.Premium_VoiceToText, +// titleColor: titleColor, +// subtitle: strings.Premium_VoiceToTextInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "noAds", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/NoAds", +// iconBackgroundColors: [ +// UIColor(rgb: 0xC654A8), +// UIColor(rgb: 0xBE5AC2) +// ], +// title: strings.Premium_NoAds, +// titleColor: titleColor, +// subtitle: strings.Premium_NoAdsInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "reactions", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Reactions", +// iconBackgroundColors: [ +// UIColor(rgb: 0xAF62E9), +// UIColor(rgb: 0xA668FF) +// ], +// title: strings.Premium_Reactions, +// titleColor: titleColor, +// subtitle: strings.Premium_ReactionsInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "stickers", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Stickers", +// iconBackgroundColors: [ +// UIColor(rgb: 0x9674FF), +// UIColor(rgb: 0x8C7DFF) +// ], +// title: strings.Premium_Stickers, +// titleColor: titleColor, +// subtitle: strings.Premium_StickersInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "chat", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Chat", +// iconBackgroundColors: [ +// UIColor(rgb: 0x9674FF), +// UIColor(rgb: 0x8C7DFF) +// ], +// title: strings.Premium_ChatManagement, +// titleColor: titleColor, +// subtitle: strings.Premium_ChatManagementInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "badge", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Badge", +// iconBackgroundColors: [ +// UIColor(rgb: 0x7B88FF), +// UIColor(rgb: 0x7091FF) +// ], +// title: strings.Premium_Badge, +// titleColor: titleColor, +// subtitle: strings.Premium_BadgeInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// SectionGroupComponent.Item( +// AnyComponentWithIdentity( +// id: "avatar", +// component: AnyComponent( +// PerkComponent( +// iconName: "Premium/Perk/Avatar", +// iconBackgroundColors: [ +// UIColor(rgb: 0x609DFF), +// UIColor(rgb: 0x56A5FF) +// ], +// title: strings.Premium_Avatar, +// titleColor: titleColor, +// subtitle: strings.Premium_AvatarInfo, +// subtitleColor: subtitleColor, +// arrowColor: arrowColor +// ) +// ) +// ), +// action: { +// +// } +// ), +// ], +// backgroundColor: environment.theme.list.itemBlocksBackgroundColor, +// selectionColor: environment.theme.list.itemHighlightedBackgroundColor, +// separatorColor: environment.theme.list.itemBlocksSeparatorColor +// ), +// environment: {}, +// availableSize: CGSize(width: availableWidth - sideInsets, height: .greatestFiniteMagnitude), +// transition: context.transition +// ) context.add(section .position(CGPoint(x: availableWidth / 2.0, y: size.height + section.size.height / 2.0)) .clipsToBounds(true) @@ -1276,7 +1600,7 @@ public final class PremiumIntroScreen: ViewControllerComponentContainer { return self._ready } - public init(context: AccountContext, modal: Bool = true) { + public init(context: AccountContext, modal: Bool = true, reference: String? = nil, source: PremiumSource? = nil) { self.context = context var updateInProgressImpl: ((Bool) -> Void)? diff --git a/submodules/PremiumUI/Sources/PremiumReactionsScreen.swift b/submodules/PremiumUI/Sources/PremiumReactionsScreen.swift index 6fc1794441..79f2703b7d 100644 --- a/submodules/PremiumUI/Sources/PremiumReactionsScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumReactionsScreen.swift @@ -108,7 +108,7 @@ public final class PremiumReactionsScreen: ViewController { self.proceedButton.pressed = { [weak self] in if let strongSelf = self, let controller = strongSelf.controller, let navigationController = controller.navigationController { strongSelf.animateOut() - navigationController.pushViewController(PremiumIntroScreen(context: controller.context), animated: true) + navigationController.pushViewController(PremiumIntroScreen(context: controller.context, source: .reactions), animated: true) } } diff --git a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift index 0721e77e5c..e0548cae96 100644 --- a/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift +++ b/submodules/SettingsUI/Sources/Search/SettingsSearchableItems.swift @@ -16,6 +16,7 @@ import NotificationSoundSelectionUI import PresentationDataUtils import PhoneNumberFormat import AccountUtils +import InstantPageCache enum SettingsSearchableItemIcon { case profile diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index 1b16d8d81f..98e77d6752 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -317,6 +317,7 @@ public final class ShareController: ViewController { private let accountActiveDisposable = MetaDisposable() private var defaultAction: ShareControllerAction? + public private(set) var actionIsMediaSaving = false public var actionCompleted: (() -> Void)? public var dismissed: ((Bool) -> Void)? @@ -391,6 +392,7 @@ public final class ShareController: ViewController { break case let .image(representations): if case .saveToCameraRoll = preferredAction { + self.actionIsMediaSaving = true self.defaultAction = ShareControllerAction(title: self.presentationData.strings.Gallery_SaveImage, action: { [weak self] in self?.saveToCameraRoll(representations: representations) self?.actionCompleted?() @@ -406,6 +408,7 @@ public final class ShareController: ViewController { isVideo = file.isVideo } if case .saveToCameraRoll = preferredAction, canSave { + self.actionIsMediaSaving = true self.defaultAction = ShareControllerAction(title: isVideo ? self.presentationData.strings.Gallery_SaveVideo : self.presentationData.strings.Gallery_SaveImage, action: { [weak self] in self?.saveToCameraRoll(mediaReference: mediaReference) self?.actionCompleted?() @@ -413,6 +416,7 @@ public final class ShareController: ViewController { } case let .messages(messages): if case .saveToCameraRoll = preferredAction { + self.actionIsMediaSaving = true self.defaultAction = ShareControllerAction(title: self.presentationData.strings.Preview_SaveToCameraRoll, action: { [weak self] in self?.saveToCameraRoll(messages: messages) self?.actionCompleted?() diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift index cfa8936fa4..ebeb836cb3 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewGridItem.swift @@ -262,10 +262,14 @@ final class StickerPackPreviewGridItemNode: GridItemNode { let bounds = self.bounds let boundsSide = min(bounds.size.width - 14.0, bounds.size.height - 14.0) - let boundingSize = CGSize(width: boundsSide, height: boundsSide) + var boundingSize = CGSize(width: boundsSide, height: boundsSide) if let (_, item) = self.currentState { if let item = item, let dimensions = item.file.dimensions?.cgSize { + if item.file.isPremiumSticker { + boundingSize = CGSize(width: boundingSize.width * 1.1, height: boundingSize.width * 1.1) + } + let imageSize = dimensions.aspectFitted(boundingSize) let imageFrame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize) self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))() diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift index dd860b9ee5..6e8f290fbb 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift @@ -751,7 +751,7 @@ private final class StickerPackContainer: ASDisplayNode { let gridFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top + titleAreaInset), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - titleAreaInset)) - let itemsPerRow = 4 + let itemsPerRow = 5 let fillingWidth = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 0.0) let itemWidth = floor(fillingWidth / CGFloat(itemsPerRow)) let gridLeftInset = floor((layout.size.width - fillingWidth) / 2.0) diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift index eb199046f8..edbd9ee2aa 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift @@ -65,7 +65,25 @@ public struct PresentationResourcesItemList { public static func verifiedPeerIcon(_ theme: PresentationTheme) -> UIImage? { return theme.image(PresentationResourceKey.itemListVerifiedPeerIcon.rawValue, { theme in - return UIImage(bundleImageName: "Item List/PeerVerifiedIcon")?.precomposed() + if let backgroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconBackground"), let foregroundImage = UIImage(bundleImageName: "Chat List/PeerVerifiedIconForeground") { + return generateImage(backgroundImage.size, contextGenerator: { size, context in + if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage { + context.clear(CGRect(origin: CGPoint(), size: size)) + context.saveGState() + context.clip(to: CGRect(origin: .zero, size: size), mask: backgroundCgImage) + + context.setFillColor(theme.chatList.unreadBadgeActiveBackgroundColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + context.restoreGState() + + context.clip(to: CGRect(origin: .zero, size: size), mask: foregroundCgImage) + context.setFillColor(theme.chatList.unreadBadgeActiveTextColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + } + }, opaque: false) + } else { + return nil + } }) } diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/Contents.json index c7e09bc23e..a91ba24766 100644 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "premiumbadge_16 (1).pdf", + "filename" : "premiumbadge_16 (2).pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/premiumbadge_16 (1).pdf b/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/premiumbadge_16 (2).pdf similarity index 97% rename from submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/premiumbadge_16 (1).pdf rename to submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/premiumbadge_16 (2).pdf index 45d70d5dd0..f322941d39 100644 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/premiumbadge_16 (1).pdf +++ b/submodules/TelegramUI/Images.xcassets/Chat List/PeerPremiumIcon.imageset/premiumbadge_16 (2).pdf @@ -10,7 +10,7 @@ stream /DeviceRGB CS /DeviceRGB cs q -1.000000 0.000000 -0.000000 1.000000 1.050293 1.510986 cm +1.000000 0.000000 -0.000000 1.000000 1.050293 2.010986 cm 0.000000 0.000000 0.000000 scn 6.588397 2.211904 m 3.455913 0.292931 l diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/ChannelVerifiedIconSmall@2x.png b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/ChannelVerifiedIconSmall@2x.png deleted file mode 100644 index dc2867f503..0000000000 Binary files a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/ChannelVerifiedIconSmall@2x.png and /dev/null differ diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/ChannelVerifiedIconSmall@3x.png b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/ChannelVerifiedIconSmall@3x.png deleted file mode 100644 index 8bf75768bd..0000000000 Binary files a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/ChannelVerifiedIconSmall@3x.png and /dev/null differ diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/Contents.json index 64530da322..0b9329e460 100644 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "verifybadge1_16.pdf", + "filename" : "verifybadge1_16 (1).pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/verifybadge1_16 (1).pdf b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/verifybadge1_16 (1).pdf new file mode 100644 index 0000000000..f0c6ef9330 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/verifybadge1_16 (1).pdf @@ -0,0 +1,107 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 3.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 8.400000 m +0.000000 8.960052 0.000000 9.240079 0.108993 9.453991 c +0.204867 9.642153 0.357847 9.795134 0.546009 9.891006 c +0.759921 10.000000 1.039948 10.000000 1.600000 10.000000 c +8.400000 10.000000 l +8.960052 10.000000 9.240079 10.000000 9.453991 9.891006 c +9.642153 9.795134 9.795134 9.642153 9.891006 9.453991 c +10.000000 9.240079 10.000000 8.960052 10.000000 8.400000 c +10.000000 1.600000 l +10.000000 1.039948 10.000000 0.759921 9.891006 0.546009 c +9.795134 0.357847 9.642153 0.204866 9.453991 0.108994 c +9.240079 0.000000 8.960052 0.000000 8.400000 0.000000 c +1.600000 0.000000 l +1.039948 0.000000 0.759921 0.000000 0.546009 0.108994 c +0.357847 0.204866 0.204867 0.357847 0.108993 0.546009 c +0.000000 0.759921 0.000000 1.039948 0.000000 1.600000 c +0.000000 8.400000 l +h +f +n +Q +q +0.707107 0.707107 -0.707107 0.707107 10.928923 -1.999968 cm +0.000000 0.000000 0.000000 scn +0.000000 12.542089 m +0.000000 13.102142 0.000000 13.382169 0.108993 13.596081 c +0.204867 13.784243 0.357847 13.937223 0.546009 14.033096 c +0.759921 14.142090 1.039948 14.142090 1.600000 14.142090 c +8.400000 14.142090 l +8.960052 14.142090 9.240079 14.142090 9.453991 14.033096 c +9.642153 13.937223 9.795134 13.784243 9.891006 13.596081 c +10.000000 13.382169 10.000000 13.102142 10.000000 12.542089 c +10.000000 5.742090 l +10.000000 5.182037 10.000000 4.902011 9.891006 4.688099 c +9.795134 4.499937 9.642153 4.346956 9.453991 4.251083 c +9.240079 4.142090 8.960052 4.142090 8.400000 4.142090 c +1.600000 4.142090 l +1.039948 4.142090 0.759921 4.142090 0.546009 4.251083 c +0.357847 4.346956 0.204867 4.499937 0.108993 4.688099 c +0.000000 4.902011 0.000000 5.182037 0.000000 5.742090 c +0.000000 12.542089 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1811 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001901 00000 n +0000001924 00000 n +0000002097 00000 n +0000002171 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2230 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/verifybadge1_16.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/verifybadge1_16.pdf deleted file mode 100644 index 3c35d1707e..0000000000 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconBackground.imageset/verifybadge1_16.pdf +++ /dev/null @@ -1,111 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 1.300293 1.044312 cm -0.000000 0.000000 0.000000 scn --0.030118 6.492163 m -0.081165 6.149670 0.378177 5.852658 0.972203 5.258633 c -1.449829 4.781006 l -1.449829 4.105689 l -1.449829 3.265610 1.449829 2.845571 1.613319 2.524703 c -1.757129 2.242459 1.986600 2.012989 2.268843 1.869179 c -2.589711 1.705688 3.009750 1.705688 3.849829 1.705688 c -4.525146 1.705688 l -5.002711 1.228124 l -5.596736 0.634098 5.893749 0.337086 6.236242 0.225803 c -6.537507 0.127916 6.862028 0.127916 7.163293 0.225803 c -7.505786 0.337086 7.802798 0.634098 8.396824 1.228124 c -8.874389 1.705688 l -9.549829 1.705688 l -10.389908 1.705688 10.809947 1.705688 11.130815 1.869179 c -11.413058 2.012989 11.642529 2.242459 11.786339 2.524703 c -11.949829 2.845571 11.949829 3.265610 11.949829 4.105688 c -11.949829 4.781129 l -12.427332 5.258632 l -12.427341 5.258640 l -13.021361 5.852661 13.318372 6.149672 13.429653 6.492163 c -13.527540 6.793428 13.527540 7.117949 13.429653 7.419214 c -13.318372 7.761705 13.021361 8.058716 12.427344 8.652733 c -12.427333 8.652744 l -11.949829 9.130249 l -11.949829 9.805689 l -11.949829 10.645767 11.949829 11.065806 11.786339 11.386674 c -11.642529 11.668918 11.413058 11.898388 11.130815 12.042198 c -10.809947 12.205688 10.389908 12.205688 9.549829 12.205688 c -8.874389 12.205688 l -8.396824 12.683253 l -7.802798 13.277279 7.505786 13.574291 7.163293 13.685574 c -6.862028 13.783461 6.537507 13.783461 6.236242 13.685574 c -5.893750 13.574291 5.596738 13.277280 5.002716 12.683257 c -5.002711 12.683253 l -4.525146 12.205688 l -3.849829 12.205688 l -3.009750 12.205688 2.589711 12.205688 2.268843 12.042198 c -1.986600 11.898388 1.757129 11.668918 1.613319 11.386674 c -1.449829 11.065806 1.449829 10.645767 1.449829 9.805689 c -1.449829 9.130371 l -0.972203 8.652744 l -0.972199 8.652741 l -0.378176 8.058718 0.081164 7.761706 -0.030118 7.419214 c --0.128005 7.117949 -0.128005 6.793428 -0.030118 6.492163 c -h -f* -n -Q - -endstream -endobj - -3 0 obj - 1960 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000002050 00000 n -0000002073 00000 n -0000002246 00000 n -0000002320 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -2379 -%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/Contents.json index 14c81bae2c..72646a77ba 100644 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "verifybadge2_16.pdf", + "filename" : "verifybadge2_16 (1).pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/verifybadge2_16 (1).pdf b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/verifybadge2_16 (1).pdf new file mode 100644 index 0000000000..ab4397198e --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/verifybadge2_16 (1).pdf @@ -0,0 +1,76 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.625000 5.061890 cm +0.000000 0.000000 0.000000 scn +6.530330 4.926815 m +6.823223 4.633921 6.823223 4.159048 6.530330 3.866154 c +3.030330 0.366154 l +2.737437 0.073261 2.262563 0.073261 1.969670 0.366154 c +0.219670 2.116154 l +-0.073223 2.409048 -0.073223 2.883921 0.219670 3.176815 c +0.512563 3.469708 0.987437 3.469708 1.280330 3.176815 c +2.500000 1.957145 l +5.469670 4.926815 l +5.762563 5.219707 6.237437 5.219707 6.530330 4.926815 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 510 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000600 00000 n +0000000622 00000 n +0000000795 00000 n +0000000869 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +928 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/verifybadge2_16.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/verifybadge2_16.pdf deleted file mode 100644 index a71253cee3..0000000000 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIconForeground.imageset/verifybadge2_16.pdf +++ /dev/null @@ -1,92 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 5.375000 4.311890 cm -0.000000 0.000000 0.000000 scn -0.530330 3.926815 m -0.237437 4.219707 -0.237437 4.219707 -0.530330 3.926815 c --0.823223 3.633921 -0.823223 3.159048 -0.530330 2.866154 c -0.530330 3.926815 l -h -1.750000 1.646484 m -1.219670 1.116154 l -1.512563 0.823261 1.987437 0.823261 2.280330 1.116154 c -1.750000 1.646484 l -h -5.780330 4.616154 m -6.073223 4.909048 6.073223 5.383921 5.780330 5.676815 c -5.487437 5.969707 5.012563 5.969707 4.719670 5.676815 c -5.780330 4.616154 l -h --0.530330 2.866154 m -1.219670 1.116154 l -2.280330 2.176815 l -0.530330 3.926815 l --0.530330 2.866154 l -h -2.280330 1.116154 m -5.780330 4.616154 l -4.719670 5.676815 l -1.219670 2.176815 l -2.280330 1.116154 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 762 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Pages 5 0 R - /Type /Catalog - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000000852 00000 n -0000000874 00000 n -0000001047 00000 n -0000001121 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -1180 -%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/AppBadge@3x.png b/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/AppBadge@3x.png new file mode 100644 index 0000000000..d647852ab0 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/AppBadge@3x.png differ diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/Contents.json similarity index 60% rename from submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/Contents.json rename to submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/Contents.json index 1d988ca1c1..0d34b819a4 100644 --- a/submodules/TelegramUI/Images.xcassets/Chat List/PeerVerifiedIcon.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Components/BadgeTEst.imageset/Contents.json @@ -6,17 +6,16 @@ }, { "idiom" : "universal", - "filename" : "ChannelVerifiedIconSmall@2x.png", "scale" : "2x" }, { + "filename" : "AppBadge@3x.png", "idiom" : "universal", - "filename" : "ChannelVerifiedIconSmall@3x.png", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconBackground.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconBackground.imageset/Contents.json new file mode 100644 index 0000000000..33022f34d1 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconBackground.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "verifybadge1_20.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconBackground.imageset/verifybadge1_20.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconBackground.imageset/verifybadge1_20.pdf new file mode 100644 index 0000000000..0c2ce2a770 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconBackground.imageset/verifybadge1_20.pdf @@ -0,0 +1,107 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 1.625244 1.404785 cm +0.000000 0.000000 0.000000 scn +0.020125 7.977180 m +0.168502 7.520524 0.564519 7.124507 1.356553 6.332473 c +1.812012 5.877014 l +1.812012 5.232715 l +1.812012 4.112610 1.812012 3.552557 2.029999 3.124734 c +2.221745 2.748409 2.527707 2.442449 2.904031 2.250702 c +3.331854 2.032715 3.891907 2.032715 5.012012 2.032715 c +5.656311 2.032715 l +6.111846 1.577180 l +6.903880 0.785147 7.299897 0.389130 7.756554 0.240753 c +8.158240 0.110237 8.590935 0.110237 8.992621 0.240753 c +9.449278 0.389130 9.845295 0.785147 10.637329 1.577180 c +11.092864 2.032715 l +11.737012 2.032715 l +12.857117 2.032715 13.417170 2.032715 13.844993 2.250702 c +14.221317 2.442449 14.527278 2.748409 14.719025 3.124734 c +14.937012 3.552557 14.937012 4.112610 14.937012 5.232715 c +14.937012 5.876863 l +15.392622 6.332473 l +16.184656 7.124507 16.580673 7.520524 16.729050 7.977180 c +16.859566 8.378868 16.859566 8.811562 16.729050 9.213249 c +16.580673 9.669906 16.184656 10.065923 15.392622 10.857956 c +14.937012 11.313566 l +14.937012 11.957715 l +14.937012 13.077820 14.937012 13.637873 14.719025 14.065696 c +14.527278 14.442020 14.221317 14.747981 13.844993 14.939728 c +13.417170 15.157715 12.857117 15.157715 11.737012 15.157715 c +11.092864 15.157715 l +10.637329 15.613250 l +9.845295 16.405283 9.449278 16.801300 8.992621 16.949677 c +8.590935 17.080193 8.158240 17.080193 7.756554 16.949677 c +7.299897 16.801300 6.903880 16.405283 6.111846 15.613250 c +5.656311 15.157715 l +5.012012 15.157715 l +3.891907 15.157715 3.331854 15.157715 2.904031 14.939728 c +2.527707 14.747981 2.221745 14.442020 2.029999 14.065696 c +1.812012 13.637873 1.812012 13.077820 1.812012 11.957715 c +1.812012 11.313416 l +1.356553 10.857956 l +0.564519 10.065923 0.168502 9.669906 0.020125 9.213249 c +-0.110391 8.811562 -0.110391 8.378868 0.020125 7.977180 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1888 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.000000 20.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001978 00000 n +0000002001 00000 n +0000002174 00000 n +0000002248 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2307 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconForeground.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconForeground.imageset/Contents.json new file mode 100644 index 0000000000..235e74ff64 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconForeground.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "verifybadge2_20.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconForeground.imageset/verifybadge2_20.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconForeground.imageset/verifybadge2_20.pdf new file mode 100644 index 0000000000..4742f9c3f4 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/VerifiedIconForeground.imageset/verifybadge2_20.pdf @@ -0,0 +1,92 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 6.718750 5.801514 cm +0.000000 0.000000 0.000000 scn +0.530330 4.364315 m +0.237437 4.657207 -0.237437 4.657207 -0.530330 4.364315 c +-0.823223 4.071421 -0.823223 3.596547 -0.530330 3.303654 c +0.530330 4.364315 l +h +2.187500 1.646484 m +1.657170 1.116154 l +1.950063 0.823261 2.424937 0.823261 2.717830 1.116154 c +2.187500 1.646484 l +h +7.092830 5.491154 m +7.385724 5.784048 7.385724 6.258921 7.092830 6.551815 c +6.799937 6.844707 6.325063 6.844707 6.032170 6.551815 c +7.092830 5.491154 l +h +-0.530330 3.303654 m +1.657170 1.116154 l +2.717830 2.176814 l +0.530330 4.364315 l +-0.530330 3.303654 l +h +2.717830 1.116154 m +7.092830 5.491154 l +6.032170 6.551815 l +1.657170 2.176814 l +2.717830 1.116154 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 762 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 20.000000 20.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000852 00000 n +0000000874 00000 n +0000001047 00000 n +0000001121 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1180 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index bccdf1eaf2..0b21abf7ec 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3125,6 +3125,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if !onlyHaptic { strongSelf.chatDisplayNode.animateQuizCorrectOptionSelected() } + }, displayPremiumStickerTooltip: { [weak self] file, message in + self?.displayPremiumStickerTooltip(file: file, message: message) }, openPeerContextMenu: { [weak self] peer, messageId, node, rect, gesture in guard let strongSelf = self else { return @@ -3358,7 +3360,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(false))).start(next: { [weak self] responded in if let strongSelf = self { if !responded { - strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, title: nil, text: strongSelf.presentationData.strings.Conversation_InteractiveEmojiSyncTip(EnginePeer(peer).compactDisplayTitle).string), elevatedLayout: false, action: { _ in return false }), in: .current) + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, title: nil, text: strongSelf.presentationData.strings.Conversation_InteractiveEmojiSyncTip(EnginePeer(peer).compactDisplayTitle).string, undoText: nil), elevatedLayout: false, action: { _ in return false }), in: .current) let _ = ApplicationSpecificNotice.incrementInteractiveEmojiSyncTip(accountManager: strongSelf.context.sharedContext.accountManager, timestamp: currentTimestamp).start() } @@ -3486,7 +3488,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) controller.navigationPresentation = .flatModal strongSelf.push(controller) -// strongSelf.present(controller, in: .window(.root)) strongSelf.currentMenuWebAppController = controller } else if simple { strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestSimpleWebView(botId: peerId, url: url, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme)) @@ -7952,12 +7953,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self { switch result { case .generic: - strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: stickerFile, title: nil, text: added ? strongSelf.presentationData.strings.Conversation_StickerAddedToFavorites : strongSelf.presentationData.strings.Conversation_StickerRemovedFromFavorites), elevatedLayout: true, action: { _ in return false }), with: nil) + strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: stickerFile, title: nil, text: added ? strongSelf.presentationData.strings.Conversation_StickerAddedToFavorites : strongSelf.presentationData.strings.Conversation_StickerRemovedFromFavorites, undoText: nil), elevatedLayout: true, action: { _ in return false }), with: nil) case .limitExceeded: - strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: stickerFile, title: strongSelf.presentationData.strings.Premium_MaxFavedStickersTitle("5").string, text: strongSelf.presentationData.strings.Premium_MaxFavedStickersText("10").string), elevatedLayout: true, action: { [weak self] action in + strongSelf.presentInGlobalOverlay(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: stickerFile, title: strongSelf.presentationData.strings.Premium_MaxFavedStickersTitle("5").string, text: strongSelf.presentationData.strings.Premium_MaxFavedStickersText("10").string, undoText: nil), elevatedLayout: true, action: { [weak self] action in if let strongSelf = self { if case .info = action { - let controller = PremiumIntroScreen(context: strongSelf.context) + let controller = PremiumIntroScreen(context: strongSelf.context, source: .savedStickers) strongSelf.push(controller) return true } @@ -11176,7 +11177,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } let present = { - strongSelf.present(attachmentController, in: .window(.root)) + attachmentController.navigationPresentation = .flatModal + strongSelf.push(attachmentController) +// strongSelf.present(attachmentController, in: .window(.root)) strongSelf.attachmentController = attachmentController } @@ -12353,6 +12356,51 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return transformEnqueueMessages(messages, silentPosting: silentPosting) } + private func displayPremiumStickerTooltip(file: TelegramMediaFile, message: Message) { + var currentOverlayController: UndoOverlayController? + + self.window?.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + currentOverlayController = controller + } + }) + self.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + currentOverlayController = controller + } + return true + }) + + if let currentOverlayController = currentOverlayController { + if case .sticker = currentOverlayController.content { + return + } + currentOverlayController.dismissWithCommitAction() + } + + var stickerPackReference: StickerPackReference? + for attribute in file.attributes { + if case let .Sticker(_, packReference, _) = attribute, let packReference = packReference { + stickerPackReference = packReference + break + } + } + + if let stickerPackReference = stickerPackReference { + let _ = (self.context.engine.stickers.loadedStickerPack(reference: stickerPackReference, forceActualized: false) + |> deliverOnMainQueue).start(next: { [weak self] stickerPack in + if let strongSelf = self, case let .result(info, _, _) = stickerPack { + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .sticker(context: strongSelf.context, file: file, title: info.title, text: strongSelf.presentationData.strings.Stickers_PremiumPackInfoText, undoText: strongSelf.presentationData.strings.Stickers_PremiumPackView), elevatedLayout: false, action: { [weak self] action in + if let strongSelf = self, action == .undo { + let _ = strongSelf.controllerInteraction?.openMessage(message, .default) + } + return false + }), in: .current) + } + }) + } + } + private func displayDiceTooltip(dice: TelegramMediaDice) { guard let _ = dice.value else { return diff --git a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift index d40b4d9d30..2802633036 100644 --- a/submodules/TelegramUI/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Sources/ChatControllerInteraction.swift @@ -118,6 +118,7 @@ public final class ChatControllerInteraction { let displayPsa: (String, ASDisplayNode) -> Void let displayDiceTooltip: (TelegramMediaDice) -> Void let animateDiceSuccess: (Bool) -> Void + let displayPremiumStickerTooltip: (TelegramMediaFile, Message) -> Void let openPeerContextMenu: (Peer, MessageId?, ASDisplayNode, CGRect, ContextGesture?) -> Void let openMessageReplies: (MessageId, Bool, Bool) -> Void let openReplyThreadOriginalMessage: (Message) -> Void @@ -219,6 +220,7 @@ public final class ChatControllerInteraction { displayPsa: @escaping (String, ASDisplayNode) -> Void, displayDiceTooltip: @escaping (TelegramMediaDice) -> Void, animateDiceSuccess: @escaping (Bool) -> Void, + displayPremiumStickerTooltip: @escaping (TelegramMediaFile, Message) -> Void, openPeerContextMenu: @escaping (Peer, MessageId?, ASDisplayNode, CGRect, ContextGesture?) -> Void, openMessageReplies: @escaping (MessageId, Bool, Bool) -> Void, openReplyThreadOriginalMessage: @escaping (Message) -> Void, @@ -305,6 +307,7 @@ public final class ChatControllerInteraction { self.openMessagePollResults = openMessagePollResults self.displayDiceTooltip = displayDiceTooltip self.animateDiceSuccess = animateDiceSuccess + self.displayPremiumStickerTooltip = displayPremiumStickerTooltip self.openPeerContextMenu = openPeerContextMenu self.openMessageReplies = openMessageReplies self.openReplyThreadOriginalMessage = openReplyThreadOriginalMessage @@ -363,6 +366,7 @@ public final class ChatControllerInteraction { }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _ in + }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 9958364622..66f66f1be0 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1723,10 +1723,21 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } if let item = self.item, self.imageNode.frame.contains(location) { - if let _ = self.telegramFile { - return .optionalAction({ - let _ = item.controllerInteraction.openMessage(item.message, .default) - }) + if let file = self.telegramFile { + if file.isPremiumSticker { + return .optionalAction({ + if self.additionalAnimationNodes.isEmpty { + self.playedPremiumStickerAnimation = false + self.playPremiumStickerAnimation() + } else { + item.controllerInteraction.displayPremiumStickerTooltip(file, item.message) + } + }) + } else { + return .optionalAction({ + let _ = item.controllerInteraction.openMessage(item.message, .default) + }) + } } else if let dice = self.telegramDice { return .optionalAction({ item.controllerInteraction.displayDiceTooltip(dice) diff --git a/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift b/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift index 14e1e627f8..8a5bb06b7f 100644 --- a/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift +++ b/submodules/TelegramUI/Sources/ChatQrCodeScreen.swift @@ -570,7 +570,13 @@ final class ChatQrCodeScreen: ViewController { var fileName: String { switch self { case let .peer(peer): - return "t_me-\(peer.addressName ?? "")" + if let addressName = peer.addressName, !addressName.isEmpty { + return "t_me-\(peer.addressName ?? "")" + } else if let peer = peer as? TelegramUser { + return "t_me-\(peer.phone ?? "")" + } else { + return "t_me-\(Int32.random(in: 0 ..< Int32.max))" + } case let .messages(messages): if let message = messages.first, let chatPeer = message.peers[message.id.peerId] as? TelegramChannel, message.id.namespace == Namespaces.Message.Cloud, let addressName = chatPeer.addressName, !addressName.isEmpty { return "t_me-\(addressName)-\(message.id.id)" @@ -1510,9 +1516,16 @@ private class QrContentNode: ASDisplayNode, ContentNode { self.codeStaticIconNode = nil } + let codeText: String + if let addressName = peer.addressName, !addressName.isEmpty { + codeText = "@\(peer.addressName ?? "")".uppercased() + } else { + codeText = peer.debugDisplayTitle.uppercased() + } + self.codeTextNode = ImmediateTextNode() self.codeTextNode.displaysAsynchronously = false - self.codeTextNode.attributedText = NSAttributedString(string: "@\(peer.addressName ?? "")".uppercased(), font: Font.with(size: 23.0, design: .round, weight: .bold, traits: []), textColor: .black) + self.codeTextNode.attributedText = NSAttributedString(string: codeText, font: Font.with(size: 23.0, design: .round, weight: .bold, traits: []), textColor: .black) self.codeTextNode.truncationMode = .byCharWrapping self.codeTextNode.maximumNumberOfLines = 2 self.codeTextNode.textAlignment = .center @@ -1547,8 +1560,17 @@ private class QrContentNode: ASDisplayNode, ContentNode { self.addSubnode(codeAnimatedIconNode) } + let codeLink: String + if let addressName = peer.addressName, !addressName.isEmpty { + codeLink = "https://t.me/\(peer.addressName ?? "")" + } else if let peer = peer as? TelegramUser { + codeLink = "https://t.me/+\(peer.phone ?? "")" + } else { + codeLink = "" + } + let codeReadyPromise = ValuePromise() - self.codeImageNode.setSignal(qrCode(string: "https://t.me/\(peer.addressName ?? "")", color: .black, backgroundColor: nil, icon: .cutout, ecl: "Q") |> beforeNext { [weak self] size, _ in + self.codeImageNode.setSignal(qrCode(string: codeLink, color: .black, backgroundColor: nil, icon: .cutout, ecl: "Q") |> beforeNext { [weak self] size, _ in guard let strongSelf = self else { return } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index ab75c05e71..72b84b5d0c 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -518,6 +518,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _ in + }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in @@ -958,6 +959,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { #endif case .settings: break + case .premiumOffer: + break case let .joinVoiceChat(peerId, invite): strongSelf.presentController(VoiceChatJoinScreen(context: strongSelf.context, peerId: peerId, invite: invite, join: { call in }), .window(.root), nil) diff --git a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift index c8828279b8..09e7e183b9 100644 --- a/submodules/TelegramUI/Sources/DrawingStickersScreen.swift +++ b/submodules/TelegramUI/Sources/DrawingStickersScreen.swift @@ -144,6 +144,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode { }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _ in + }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/TelegramUI/Sources/InlineReactionSearchPanel.swift b/submodules/TelegramUI/Sources/InlineReactionSearchPanel.swift index 10ec47256d..b473dd3732 100644 --- a/submodules/TelegramUI/Sources/InlineReactionSearchPanel.swift +++ b/submodules/TelegramUI/Sources/InlineReactionSearchPanel.swift @@ -355,9 +355,9 @@ private final class InlineReactionSearchStickersNode: ASDisplayNode, UIScrollVie private func updateItemsLayout(width: CGFloat) { self.displayItems.removeAll() - let itemsPerRow = min(8, max(4, Int(width / 80))) - let sideInset: CGFloat = 4.0 - let itemSpacing: CGFloat = 4.0 + let itemsPerRow = min(8, max(5, Int(width / 80))) + let sideInset: CGFloat = 2.0 + let itemSpacing: CGFloat = 2.0 let itemSize = floor((width - sideInset * 2.0 - itemSpacing * (CGFloat(itemsPerRow) - 1.0)) / CGFloat(itemsPerRow)) var columnIndex = 0 diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index a7fc817a59..b3ed446341 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -27,6 +27,7 @@ import PeerInfoUI import Markdown import WebUI import BotPaymentsUI +import PremiumUI private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer { if case .default = navigation { @@ -514,8 +515,19 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur navigationController.setViewControllers(controllers, animated: true) }) } - break } + case let .premiumOffer(reference): + dismissInput() + let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)) + |> deliverOnMainQueue).start(next: { peer in + let isPremium = peer?.isPremium ?? false + if !isPremium { + let controller = PremiumIntroScreen(context: context, reference: reference) + if let navigationController = navigationController { + navigationController.pushViewController(controller, animated: true) + } + } + }) case let .joinVoiceChat(peerId, invite): dismissInput() if let navigationController = navigationController { diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 228f745658..ccdce32018 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -724,6 +724,20 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur return } } + } else if parsedUrl.host == "premium_offer" { + var reference: String? + if let components = URLComponents(string: "/?" + query) { + if let queryItems = components.queryItems { + for queryItem in queryItems { + if let value = queryItem.value { + if queryItem.name == "ref" { + reference = value + } + } + } + } + } + handleResolvedUrl(.premiumOffer(reference: reference)) } } else { if parsedUrl.host == "importStickers" { @@ -743,6 +757,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur handleResolvedUrl(.settings(section)) } } + } else if parsedUrl.host == "premium_offer" { + handleResolvedUrl(.premiumOffer(reference: nil)) } } diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 9d4e2d7d3a..1617a354a3 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -136,6 +136,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _ in + }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index c2999aaad2..4e540db625 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -2312,15 +2312,36 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else if case .scam = credibilityIcon { image = PresentationResourcesChatList.scamIcon(presentationData.theme, strings: presentationData.strings, type: .regular) } else if case .verified = credibilityIcon { - if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") { - image = generateImage(sourceImage.size, contextGenerator: { size, context in - context.clear(CGRect(origin: CGPoint(), size: size)) - context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 7.0, dy: 7.0)) - context.setFillColor(presentationData.theme.list.itemCheckColors.fillColor.cgColor) - context.clip(to: CGRect(origin: CGPoint(), size: size), mask: sourceImage.cgImage!) - context.fill(CGRect(origin: CGPoint(), size: size)) - }) + if let backgroundImage = UIImage(bundleImageName: "Peer Info/VerifiedIconBackground"), let foregroundImage = UIImage(bundleImageName: "Peer Info/VerifiedIconForeground") { + image = generateImage(backgroundImage.size, contextGenerator: { size, context in + if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage { + context.clear(CGRect(origin: CGPoint(), size: size)) + context.saveGState() + context.clip(to: CGRect(origin: .zero, size: size), mask: backgroundCgImage) + + context.setFillColor(presentationData.theme.list.itemCheckColors.fillColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + context.restoreGState() + + context.clip(to: CGRect(origin: .zero, size: size), mask: foregroundCgImage) + context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + } + }, opaque: false) + expandedImage = generateImage(backgroundImage.size, contextGenerator: { size, context in + if let backgroundCgImage = backgroundImage.cgImage, let foregroundCgImage = foregroundImage.cgImage { + context.clear(CGRect(origin: CGPoint(), size: size)) + context.saveGState() + context.clip(to: CGRect(origin: .zero, size: size), mask: backgroundCgImage) + context.setFillColor(UIColor(rgb: 0xffffff, alpha: 0.75).cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) + context.restoreGState() + + context.clip(to: CGRect(origin: .zero, size: size), mask: foregroundCgImage) + context.setBlendMode(.clear) + context.fill(CGRect(origin: CGPoint(), size: size)) + } + }, opaque: false) } else { image = nil } @@ -2331,17 +2352,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { context.clear(CGRect(origin: CGPoint(), size: size)) context.clip(to: CGRect(origin: .zero, size: size), mask: cgImage) - let colorsArray: [CGColor] = [ - UIColor(rgb: 0x6B93FF).cgColor, - UIColor(rgb: 0x6B93FF).cgColor, - UIColor(rgb: 0x976FFF).cgColor, - UIColor(rgb: 0xE46ACE).cgColor, - UIColor(rgb: 0xE46ACE).cgColor - ] - var locations: [CGFloat] = [0.0, 0.35, 0.5, 0.65, 1.0] - let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)! - - context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: size.height), options: CGGradientDrawingOptions()) + context.setFillColor(presentationData.theme.list.itemCheckColors.fillColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: size)) } }, opaque: false) expandedImage = generateImage(sourceImage.size, contextGenerator: { size, context in diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 7637f0f6a0..f3d0ed5ba4 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -68,6 +68,7 @@ import ChatPresentationInterfaceState import CreateExternalMediaStreamScreen import PaymentMethodUI import PremiumUI +import InstantPageCache protocol PeerInfoScreenItem: AnyObject { var id: AnyHashable { get } @@ -2299,6 +2300,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _ in + }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in @@ -5572,6 +5574,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate actions.append(ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuTranslate, accessibilityLabel: presentationData.strings.Conversation_ContextMenuTranslate), action: { [weak self] in let controller = TranslateScreen(context: context, text: text, fromLanguage: language) + controller.pushController = { [weak self] c in + (self?.controller?.navigationController as? NavigationController)?._keepModalDismissProgress = true + self?.controller?.push(c) + } + controller.presentController = { [weak self] c in + self?.controller?.present(c, in: .window(.root)) + } self?.controller?.present(controller, in: .window(.root)) })) } @@ -6200,7 +6209,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate case .language: push(LocalizationListController(context: self.context)) case .premium: - self.controller?.push(PremiumIntroScreen(context: self.context, modal: false)) + self.controller?.push(PremiumIntroScreen(context: self.context, modal: false, source: .settings)) case .stickers: if let settings = self.data?.globalSettings { push(installedStickerPacksController(context: self.context, mode: .general, archivedPacks: settings.archivedStickerPacks, updatedPacks: { [weak self] packs in @@ -7453,10 +7462,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .done, isForExpandedView: false)) } else { if self.isSettings { - if let addressName = self.data?.peer?.addressName, !addressName.isEmpty { - leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .qrCode, isForExpandedView: false)) - } - + leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .qrCode, isForExpandedView: false)) rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false)) rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .search, isForExpandedView: true)) } else if peerInfoCanEdit(peer: self.data?.peer, cachedData: self.data?.cachedData, isContact: self.data?.isContact) { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 3ac5c6c2f1..522198d0da 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1313,6 +1313,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, displayPsa: { _, _ in }, displayDiceTooltip: { _ in }, animateDiceSuccess: { _ in + }, displayPremiumStickerTooltip: { _, _ in }, openPeerContextMenu: { _, _, _, _, _ in }, openMessageReplies: { _, _, _ in }, openReplyThreadOriginalMessage: { _ in diff --git a/submodules/UndoUI/Sources/UndoOverlayController.swift b/submodules/UndoUI/Sources/UndoOverlayController.swift index b6b2cb8a69..4afcdbe5a9 100644 --- a/submodules/UndoUI/Sources/UndoOverlayController.swift +++ b/submodules/UndoUI/Sources/UndoOverlayController.swift @@ -34,7 +34,7 @@ public enum UndoOverlayContent { case voiceChatRecording(text: String) case voiceChatFlag(text: String) case voiceChatCanSpeak(text: String) - case sticker(context: AccountContext, file: TelegramMediaFile, title: String?, text: String) + case sticker(context: AccountContext, file: TelegramMediaFile, title: String?, text: String, undoText: String?) case copy(text: String) case mediaSaved(text: String) case paymentSent(currencyValue: String, itemTitle: String) diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index 17219ed8d9..6368fbf93d 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -628,7 +628,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { displayUndo = false self.originalRemainingSeconds = 3 - case let .sticker(context, file, title, text): + case let .sticker(context, file, title, text, customUndoText): self.avatarNode = nil self.iconNode = nil self.iconCheckNode = nil @@ -702,7 +702,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { isUserInteractionEnabled = true } - displayUndo = false + if let customUndoText = customUndoText { + undoText = customUndoText + displayUndo = true + } else { + displayUndo = false + } self.originalRemainingSeconds = 3 if let updatedFetchSignal = updatedFetchSignal { @@ -869,12 +874,14 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { switch content { case .removedChat: self.panelWrapperNode.addSubnode(self.timerTextNode) - case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent, .notificationSoundAdded, .universal: + case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent, .notificationSoundAdded, .universal: if self.textNode.tapAttributeAction != nil { self.isUserInteractionEnabled = true } else { self.isUserInteractionEnabled = false } + case let .sticker(_, _, _, _, undoText): + self.isUserInteractionEnabled = undoText != nil case .dice: self.panelWrapperNode.clipsToBounds = true case .info: diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 7375ae9a30..855b8180ae 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -427,6 +427,8 @@ public final class WebAppController: ViewController, AttachmentContainable { } } + private let hapticFeedback = HapticFeedback() + private var delayedScriptMessage: WKScriptMessage? private func handleScriptMessage(_ message: WKScriptMessage) { guard let controller = self.controller else { @@ -487,7 +489,7 @@ public final class WebAppController: ViewController, AttachmentContainable { } case "web_app_open_invoice": if let json = json, let slug = json["slug"] as? String { - self.paymentDisposable = (context.engine.payments.fetchBotPaymentInvoice(source: .slug(slug)) + self.paymentDisposable = (self.context.engine.payments.fetchBotPaymentInvoice(source: .slug(slug)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) @@ -510,6 +512,55 @@ public final class WebAppController: ViewController, AttachmentContainable { } }) } + case "web_app_open_link": + if let json = json, let url = json["url"] as? String { + let currentTimestamp = CACurrentMediaTime() + if let lastTouchTimestamp = self.webView?.lastTouchTimestamp, currentTimestamp < lastTouchTimestamp + 10.0 { + self.webView?.lastTouchTimestamp = nil + self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {}) + } + } + case "web_app_setup_back_button": + break + case "web_app_trigger_haptic_feedback": + if let json = json, let type = json["type"] as? String { + switch type { + case "impact": + if let impactType = json["impact_style"] as? String { + switch impactType { + case "light": + self.hapticFeedback.impact(.light) + case "medium": + self.hapticFeedback.impact(.medium) + case "heavy": + self.hapticFeedback.impact(.heavy) + case "rigid": + self.hapticFeedback.impact(.rigid) + case "soft": + self.hapticFeedback.impact(.soft) + default: + break + } + } + case "notification": + if let notificationType = json["notification_type"] as? String { + switch notificationType { + case "success": + self.hapticFeedback.success() + case "error": + self.hapticFeedback.error() + case "warning": + self.hapticFeedback.warning() + default: + break + } + } + case "selection_change": + self.hapticFeedback.tap() + default: + break + } + } default: break } diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index 4adf65fe62..61aa444e20 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -132,6 +132,7 @@ final class WebAppWebView: WKWebView { self.sendEvent(name: "viewport_changed", data: data) } + var lastTouchTimestamp: Double? private(set) var didTouchOnce = false var onFirstTouch: () -> Void = {} @@ -161,6 +162,7 @@ final class WebAppWebView: WKWebView { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let result = super.hitTest(point, with: event) + self.lastTouchTimestamp = CACurrentMediaTime() if result != nil && !self.didTouchOnce { self.didTouchOnce = true self.onFirstTouch()