diff --git a/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift b/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift index a0677bdd9e..b635d9e54f 100644 --- a/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift +++ b/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift @@ -176,7 +176,7 @@ open class ViewControllerComponentContainer: ViewController { private let component: AnyComponent private var presentationDataDisposable: Disposable? - private var validLayout: ContainerViewLayout? + public private(set) var validLayout: ContainerViewLayout? public init(context: AccountContext, component: C, navigationBarAppearance: NavigationBarAppearance, statusBarStyle: StatusBarStyle = .default, theme: PresentationTheme? = nil) where C.EnvironmentType == ViewControllerComponentContainer.Environment { self.context = context diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index c69127b8c1..8989226abc 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -222,7 +222,7 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin self.subtitleNode.attributedText = subtitle.flatMap { subtitle in return NSAttributedString( - string: self.item.text, + string: subtitle, font: subtitleFont, textColor: subtitleColor ) diff --git a/submodules/Emoji/Sources/EmojiUtils.swift b/submodules/Emoji/Sources/EmojiUtils.swift index 58ba322f87..fd58bb060f 100644 --- a/submodules/Emoji/Sources/EmojiUtils.swift +++ b/submodules/Emoji/Sources/EmojiUtils.swift @@ -5,7 +5,7 @@ import AVFoundation public extension UnicodeScalar { var isEmoji: Bool { switch self.value { - case 0x1F600...0x1F64F, 0x1F300...0x1F5FF, 0x1F680...0x1F6FF, 0x1F1E6...0x1F1FF, 0xE0020...0xE007F, 0xFE00...0xFE0F, 0x1F900...0x1F9FF, 0x1F018...0x1F0F5, 0x1F200...0x1F270, 65024...65039, 9100...9300, 8400...8447, 0x1F004, 0x1F18E, 0x1F191...0x1F19A, 0x1F5E8, 0x1FA70...0x1FA73, 0x1FA78...0x1FA7A, 0x1FA80...0x1FA82, 0x1FA90...0x1FA95: + case 0x1F600...0x1F64F, 0x1F300...0x1F5FF, 0x1F680...0x1F6FF, 0x1F1E6...0x1F1FF, 0xE0020...0xE007F, 0xFE00...0xFE0F, 0x1F900...0x1F9FF, 0x1F018...0x1F0F5, 0x1F200...0x1F270, 65024...65039, 9100...9300, 8400...8447, 0x1F004, 0x1F18E, 0x1F191...0x1F19A, 0x1F5E8, 0x1FA70...0x1FA73, 0x1FA78...0x1FA7A, 0x1FA80...0x1FA82, 0x1FA90...0x1FA95, 0x1F382: return true case 0x2603, 0x265F, 0x267E, 0x2692, 0x26C4, 0x26C8, 0x26CE, 0x26CF, 0x26D1...0x26D3, 0x26E9, 0x26F0...0x26F9, 0x2705, 0x270A, 0x270B, 0x2728, 0x274E, 0x2753...0x2755, 0x274C, 0x2795...0x2797, 0x27B0, 0x27BF: return true diff --git a/submodules/PremiumUI/Sources/PremiumGiftScreen.swift b/submodules/PremiumUI/Sources/PremiumGiftScreen.swift index 2439774bcd..26d5e627a9 100644 --- a/submodules/PremiumUI/Sources/PremiumGiftScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumGiftScreen.swift @@ -538,7 +538,6 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent { let fade = Child(RoundedRectangle.self) let text = Child(MultilineTextComponent.self) let section = Child(ProductGroupComponent.self) - let termsText = Child(MultilineTextComponent.self) return { context in let sideInset: CGFloat = 16.0 @@ -687,55 +686,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent { size.height += section.size.height size.height += 23.0 - let textSideInset: CGFloat = 16.0 - let termsFont = Font.regular(13.0) - let termsTextColor = environment.theme.list.freeTextColor - let termsMarkdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: termsFont, textColor: termsTextColor), bold: MarkdownAttributeSet(font: termsFont, textColor: termsTextColor), link: MarkdownAttributeSet(font: termsFont, textColor: environment.theme.list.itemAccentColor), linkAttribute: { contents in - return (TelegramTextAttributes.URL, contents) - }) - - let termsString: MultilineTextComponent.TextContent = .markdown( - text: strings.Premium_Gift_Info, - attributes: termsMarkdownAttributes - ) - - let accountContext = component.context - let peerId = component.peer.id - let present = component.present - - let termsText = termsText.update( - component: MultilineTextComponent( - text: termsString, - horizontalAlignment: .center, - maximumNumberOfLines: 0, - lineSpacing: 0.0, - highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.3), - highlightAction: { attributes in - if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { - return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) - } else { - return nil - } - }, - tapAction: { attributes, _ in - if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { - let controller = PremiumIntroScreen(context: accountContext, source: .profile(peerId)) - present(controller) - } - } - ), - environment: {}, - availableSize: CGSize(width: availableWidth - sideInsets - textSideInset * 2.0, height: .greatestFiniteMagnitude), - transition: context.transition - ) -// context.add(termsText -// .position(CGPoint(x: sideInset + environment.safeInsets.left + textSideInset + termsText.size.width / 2.0, y: size.height + termsText.size.height / 2.0)) -// ) - context.add(termsText - .position(CGPoint(x: sideInset + environment.safeInsets.left + textSideInset + termsText.size.width / 2.0, y: size.height + 164.0 + termsText.size.height / 2.0)) - ) - size.height += termsText.size.height size.height += 10.0 size.height += scrollEnvironment.insets.bottom @@ -885,7 +836,6 @@ private final class PremiumGiftScreenComponent: CombinedComponent { strongSelf.updateInProgress(false) strongSelf.updated(transition: .immediate) -// strongSelf.completion(duration) addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail") @@ -958,6 +908,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent { let bottomPanel = Child(BlurredRectangle.self) let bottomSeparator = Child(Rectangle.self) let button = Child(SolidRoundedButtonComponent.self) + let termsText = Child(MultilineTextComponent.self) return { context in let environment = context.environment[EnvironmentType.self].value @@ -1098,7 +1049,7 @@ private final class PremiumGiftScreenComponent: CombinedComponent { .scale(titleScale) .opacity(titleAlpha) ) - + let price: String? if let products = state.products, let selectedProductId = state.selectedProductId, let product = products.first(where: { $0.id == selectedProductId }) { price = product.price @@ -1193,6 +1144,56 @@ private final class PremiumGiftScreenComponent: CombinedComponent { }) ) + if let _ = context.state.peer { + let accountContext = context.component.context + let present = context.component.present + + let sideInset: CGFloat = 16.0 + let textSideInset: CGFloat = 16.0 + let availableWidth = context.availableSize.width + let sideInsets = sideInset * 2.0 + environment.safeInsets.left + environment.safeInsets.right + + let termsFont = Font.regular(13.0) + let termsTextColor = environment.theme.list.freeTextColor + let termsMarkdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: termsFont, textColor: termsTextColor), bold: MarkdownAttributeSet(font: termsFont, textColor: termsTextColor), link: MarkdownAttributeSet(font: termsFont, textColor: environment.theme.list.itemAccentColor), linkAttribute: { contents in + return (TelegramTextAttributes.URL, contents) + }) + + let termsString: MultilineTextComponent.TextContent = .markdown( + text: environment.strings.Premium_Gift_Info, + attributes: termsMarkdownAttributes + ) + + let termsText = termsText.update( + component: MultilineTextComponent( + text: termsString, + horizontalAlignment: .center, + maximumNumberOfLines: 0, + lineSpacing: 0.0, + highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.3), + highlightAction: { attributes in + if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { + return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) + } else { + return nil + } + }, + tapAction: { attributes, _ in + if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { + let controller = PremiumIntroScreen(context: accountContext, source: .giftTerms) + present(controller) + } + } + ), + environment: {}, + availableSize: CGSize(width: availableWidth - sideInsets - textSideInset * 2.0, height: .greatestFiniteMagnitude), + transition: context.transition + ) + context.add(termsText + .position(CGPoint(x: sideInset + environment.safeInsets.left + textSideInset + termsText.size.width / 2.0, y: context.availableSize.height - bottomPanel.size.height - termsText.size.height)) + ) + } + return context.availableSize } } diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 0dcb18a9b6..44ff71410a 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -39,6 +39,7 @@ public enum PremiumSource: Equatable { case deeplink(String?) case profile(PeerId) case gift(from: PeerId, to: PeerId, duration: Int32) + case giftTerms var identifier: String? { switch self { @@ -74,7 +75,7 @@ public enum PremiumSource: Equatable { return "double_limits__about" case let .profile(id): return "profile__\(id.id._internalGetInt64Value())" - case .gift: + case .gift, .giftTerms: return nil case let .deeplink(reference): if let reference = reference { @@ -819,7 +820,9 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { let boldTextFont = Font.semibold(15.0) let textString: String - if let _ = context.component.otherPeerName { + if case .giftTerms = context.component.source { + textString = strings.Premium_PersonalDescription + } else if let _ = context.component.otherPeerName { if case let .gift(fromId, _, _) = context.component.source { if fromId == context.component.context.account.peerId { textString = strings.Premium_GiftedDescriptionYou @@ -1447,7 +1450,9 @@ private final class PremiumIntroScreenComponent: CombinedComponent { ) let titleString: String - if case .gift = context.component.source { + if case .giftTerms = context.component.source { + titleString = environment.strings.Premium_Title + } else if case .gift = context.component.source { titleString = environment.strings.Premium_GiftedTitle } else if state.isPremium == true { titleString = environment.strings.Premium_SubscribedTitle diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 4bc9f720fa..e56e2408dc 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1685,7 +1685,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { .offsetBy(dx: incomingMessage ? animationNode.frame.width - 10.0 : -animationNode.frame.width + 10.0, dy: 0.0) animationFrame = animationFrame.offsetBy(dx: CGFloat.random(in: -30.0 ... 30.0), dy: CGFloat.random(in: -30.0 ... 30.0)) } - + + animationFrame = animationFrame.offsetBy(dx: 0.0, dy: self.insets.top) additionalAnimationNode.frame = animationFrame if incomingMessage { additionalAnimationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0) diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 216afd8217..dbf561cd29 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -723,6 +723,60 @@ public final class WebAppController: ViewController, AttachmentContainable { self.headerColorKey = colorKey self.updateHeaderBackgroundColor(transition: .animated(duration: 0.2, curve: .linear)) } + case "web_app_open_popup": + if let json = json, let message = json["message"] as? String, let buttons = json["buttons"] as? [Any] { + let presentationData = self.presentationData + + let title = json["title"] as? String + var alertButtons: [TextAlertAction] = [] + + for buttonJson in buttons { + if let button = buttonJson as? [String: Any], let id = button["id"] as? String, let type = button["type"] as? String { + let buttonAction = { + self.sendAlertButtonEvent(id: id) + } + let text = button["text"] as? String + switch type { + case "default": + if let text = text { + alertButtons.append(TextAlertAction(type: .genericAction, title: text, action: { + buttonAction() + })) + } + case "destructive": + if let text = text { + alertButtons.append(TextAlertAction(type: .destructiveAction, title: text, action: { + buttonAction() + })) + } + case "ok": + alertButtons.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { + buttonAction() + })) + case "cancel": + alertButtons.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { + buttonAction() + })) + case "close": + alertButtons.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Close, action: { + buttonAction() + })) + default: + break + } + } + } + + var actionLayout: TextAlertContentActionLayout = .horizontal + if alertButtons.count > 2 { + actionLayout = .vertical + } + let alertController = textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: title, text: message, actions: alertButtons, actionLayout: actionLayout) + alertController.dismissed = { + self.sendAlertButtonEvent(id: nil) + } + self.controller?.present(alertController, in: .window(.root)) + } default: break } @@ -834,6 +888,14 @@ public final class WebAppController: ViewController, AttachmentContainable { fileprivate func sendSettingsButtonEvent() { self.webView?.sendEvent(name: "settings_button_pressed", data: nil) } + + fileprivate func sendAlertButtonEvent(id: String?) { + var paramsString: String? + if let id = id { + paramsString = "{id: \"\(id)\"}" + } + self.webView?.sendEvent(name: "popup_closed", data: paramsString) + } } fileprivate var controllerNode: Node {