Web app improvements

This commit is contained in:
Ilya Laktyushin 2024-07-02 21:03:22 +04:00
parent 613bba57c2
commit f5092b8d8d
33 changed files with 1483 additions and 1306 deletions

View File

@ -12473,6 +12473,10 @@ Sorry for the inconvenience.";
"WebApp.MinimizedTitle.Others_1" = "%@ Other"; "WebApp.MinimizedTitle.Others_1" = "%@ Other";
"WebApp.MinimizedTitle.Others_any" = "%@ Others"; "WebApp.MinimizedTitle.Others_any" = "%@ Others";
"WebApp.Minimized.CloseAllTitle" = "Are you sure you want to close all open tabs?";
"WebApp.Minimized.CloseAll_1" = "Close All %@ Tab";
"WebApp.Minimized.CloseAll_any" = "Close All %@ Tabs";
"Stars.SendStars.Title" = "Send Stars"; "Stars.SendStars.Title" = "Send Stars";
"Stars.SendStars.AmountTitle" = "ENTER AMOUNT"; "Stars.SendStars.AmountTitle" = "ENTER AMOUNT";
"Stars.SendStars.AmountPlaceholder" = "Stars Amount"; "Stars.SendStars.AmountPlaceholder" = "Stars Amount";

View File

@ -71,6 +71,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
var isPanningUpdated: (Bool) -> Void = { _ in } var isPanningUpdated: (Bool) -> Void = { _ in }
var isExpandedUpdated: (Bool) -> Void = { _ in } var isExpandedUpdated: (Bool) -> Void = { _ in }
var isPanGestureEnabled: (() -> Bool)? var isPanGestureEnabled: (() -> Bool)?
var isInnerPanGestureEnabled: (() -> Bool)?
var onExpandAnimationCompleted: () -> Void = {} var onExpandAnimationCompleted: () -> Void = {}
init(isFullSize: Bool) { init(isFullSize: Bool) {
@ -146,6 +147,23 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
return false return false
} }
} }
if let isInnerPanGestureEnabled = self.isInnerPanGestureEnabled, !isInnerPanGestureEnabled() {
func findWebViewAncestor(view: UIView?) -> WKWebView? {
guard let view else {
return nil
}
if let view = view as? WKWebView {
return view
} else if view != self.view {
return findWebViewAncestor(view: view.superview)
} else {
return nil
}
}
if let otherView = self.hitTest(gestureRecognizer.location(in: self.view), with: nil), let _ = findWebViewAncestor(view: otherView) {
return false
}
}
} }
return true return true
} }
@ -163,23 +181,6 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
} }
return true return true
} }
if gestureRecognizer is UIPanGestureRecognizer {
func findWebViewAncestor(view: UIView?) -> WKWebView? {
guard let view else {
return nil
}
if let view = view as? WKWebView {
return view
} else if view != self.view {
return findWebViewAncestor(view: view.superview)
} else {
return nil
}
}
if let otherView = otherGestureRecognizer.view, let _ = findWebViewAncestor(view: otherView) {
return true
}
}
if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UILongPressGestureRecognizer { if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UILongPressGestureRecognizer {
return true return true
} }
@ -197,7 +198,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
private var panGestureArguments: (topInset: CGFloat, offset: CGFloat, scrollView: UIScrollView?, listNode: ListView?)? private var panGestureArguments: (topInset: CGFloat, offset: CGFloat, scrollView: UIScrollView?, listNode: ListView?)?
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) { @objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
guard let (layout, controllers, coveredByModalTransition) = self.validLayout else { guard let (layout, controllers, coveredByModalTransition) = self.validLayout, let lastController = controllers.last else {
return return
} }
@ -271,10 +272,14 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
} }
if !self.isExpanded || self.isFullSize, translation > 40.0, let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() { if !self.isExpanded || self.isFullSize, translation > 40.0, let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() {
if lastController.isMinimizable {
} else {
self.cancelPanGesture() self.cancelPanGesture()
self.requestDismiss?() self.requestDismiss?()
return return
} }
}
var bounds = self.bounds var bounds = self.bounds
if self.isExpanded && !self.isFullSize { if self.isExpanded && !self.isFullSize {
@ -323,8 +328,12 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
var ignoreDismiss = false var ignoreDismiss = false
if let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() { if let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() {
if lastController.isMinimizable {
} else {
ignoreDismiss = true ignoreDismiss = true
} }
}
var minimizing = false var minimizing = false
var dismissing = false var dismissing = false

View File

@ -121,6 +121,7 @@ public protocol AttachmentContainable: ViewController, MinimizableController {
var isContainerPanning: () -> Bool { get set } var isContainerPanning: () -> Bool { get set }
var isContainerExpanded: () -> Bool { get set } var isContainerExpanded: () -> Bool { get set }
var isPanGestureEnabled: (() -> Bool)? { get } var isPanGestureEnabled: (() -> Bool)? { get }
var isInnerPanGestureEnabled: (() -> Bool)? { get }
var mediaPickerContext: AttachmentMediaPickerContext? { get } var mediaPickerContext: AttachmentMediaPickerContext? { get }
var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)? { get } var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)? { get }
@ -172,6 +173,10 @@ public extension AttachmentContainable {
return nil return nil
} }
var isInnerPanGestureEnabled: (() -> Bool)? {
return nil
}
var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)? { var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)? {
return nil return nil
} }
@ -196,6 +201,10 @@ public protocol AttachmentMediaPickerContext {
var captionIsAboveMedia: Signal<Bool, NoError> { get } var captionIsAboveMedia: Signal<Bool, NoError> { get }
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void
var canMakePaidContent: Bool { get }
var price: Int64? { get }
func setPrice(_ price: Int64) -> Void
var loadingProgress: Signal<CGFloat?, NoError> { get } var loadingProgress: Signal<CGFloat?, NoError> { get }
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get } var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
@ -206,6 +215,58 @@ public protocol AttachmentMediaPickerContext {
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?)
} }
public extension AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
var hasCaption: Bool {
return false
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
var canMakePaidContent: Bool {
return false
}
var price: Int64? {
return nil
}
func setPrice(_ price: Int64) -> Void {
}
var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
}
}
private func generateShadowImage() -> UIImage? { private func generateShadowImage() -> UIImage? {
return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
@ -444,6 +505,17 @@ public class AttachmentController: ViewController, MinimizableController {
} }
} }
self.container.isInnerPanGestureEnabled = { [weak self] in
guard let self, let currentController = self.currentControllers.last else {
return true
}
if let isInnerPanGestureEnabled = currentController.isInnerPanGestureEnabled {
return isInnerPanGestureEnabled()
} else {
return true
}
}
self.container.shouldCancelPanGesture = { [weak self] in self.container.shouldCancelPanGesture = { [weak self] in
if let strongSelf = self, let currentController = strongSelf.currentControllers.last { if let strongSelf = self, let currentController = strongSelf.currentControllers.last {
if !currentController.shouldDismissImmediately() { if !currentController.shouldDismissImmediately() {
@ -1191,6 +1263,14 @@ public class AttachmentController: ViewController, MinimizableController {
} }
} }
public var isMinimizable: Bool {
return self.mainController.isMinimizable
}
public func shouldDismissImmediately() -> Bool {
return self.mainController.shouldDismissImmediately()
}
private var validLayout: ContainerViewLayout? private var validLayout: ContainerViewLayout?
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {

View File

@ -985,8 +985,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
} }
var captionIsAboveMedia: Signal<Bool, NoError> = .single(false) var captionIsAboveMedia: Signal<Bool, NoError> = .single(false)
var canMakePaidContent = false
var currentPrice: Int64?
if let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext { if let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext {
captionIsAboveMedia = mediaPickerContext.captionIsAboveMedia captionIsAboveMedia = mediaPickerContext.captionIsAboveMedia
canMakePaidContent = mediaPickerContext.canMakePaidContent
currentPrice = mediaPickerContext.price
} }
let _ = (combineLatest( let _ = (combineLatest(
@ -1016,7 +1020,9 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
messageEffect: nil, messageEffect: nil,
attachment: true, attachment: true,
canSendWhenOnline: sendWhenOnlineAvailable, canSendWhenOnline: sendWhenOnlineAvailable,
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
canMakePaidContent: canMakePaidContent,
currentPrice: currentPrice
)), )),
hasEntityKeyboard: hasEntityKeyboard, hasEntityKeyboard: hasEntityKeyboard,
gesture: gesture, gesture: gesture,
@ -1038,6 +1044,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
schedule: { [weak textInputPanelNode] messageEffect in schedule: { [weak textInputPanelNode] messageEffect in
textInputPanelNode?.sendMessage(.schedule, messageEffect) textInputPanelNode?.sendMessage(.schedule, messageEffect)
}, },
editPrice: { [weak strongSelf] price in
guard let strongSelf, let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext else {
return
}
mediaPickerContext.setPrice(price)
},
openPremiumPaywall: { [weak self] c in openPremiumPaywall: { [weak self] c in
guard let self else { guard let self else {
return return

View File

@ -10,23 +10,26 @@ swift_library(
"-warnings-as-errors", "-warnings-as-errors",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit",
"//submodules/Display:Display", "//submodules/Display",
"//submodules/Postbox:Postbox", "//submodules/Postbox",
"//submodules/TelegramCore:TelegramCore", "//submodules/TelegramCore",
"//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences:TelegramUIPreferences", "//submodules/TelegramUIPreferences",
"//submodules/AppBundle:AppBundle", "//submodules/AppBundle",
"//submodules/InstantPageUI:InstantPageUI", "//submodules/InstantPageUI",
"//submodules/ContextUI:ContextUI", "//submodules/ContextUI",
"//submodules/UndoUI:UndoUI", "//submodules/UndoUI",
"//submodules/TranslateUI",
"//submodules/ComponentFlow:ComponentFlow", "//submodules/ComponentFlow:ComponentFlow",
"//submodules/Components/ViewControllerComponent:ViewControllerComponent", "//submodules/Components/ViewControllerComponent:ViewControllerComponent",
"//submodules/Components/MultilineTextComponent:MultilineTextComponent", "//submodules/Components/MultilineTextComponent:MultilineTextComponent",
"//submodules/Components/BundleIconComponent:BundleIconComponent", "//submodules/Components/BundleIconComponent:BundleIconComponent",
"//submodules/Components/BlurredBackgroundComponent:BlurredBackgroundComponent", "//submodules/Components/BlurredBackgroundComponent:BlurredBackgroundComponent",
"//submodules/TelegramUI/Components/MinimizedContainer", "//submodules/TelegramUI/Components/MinimizedContainer",
"//submodules/Pasteboard",
"//submodules/SaveToCameraRoll",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

File diff suppressed because it is too large Load Diff

View File

@ -110,7 +110,7 @@ final class BrowserNavigationBarComponent: CombinedComponent {
return { context in return { context in
var availableWidth = context.availableSize.width var availableWidth = context.availableSize.width
let sideInset: CGFloat = 11.0 + context.component.sideInset let sideInset: CGFloat = 16.0 + context.component.sideInset
let collapsedHeight: CGFloat = 24.0 let collapsedHeight: CGFloat = 24.0
let expandedHeight = context.component.height let expandedHeight = context.component.height
@ -202,8 +202,8 @@ final class BrowserNavigationBarComponent: CombinedComponent {
centerLeftInset += item.size.width + 8.0 centerLeftInset += item.size.width + 8.0
} }
var centerRightInset = sideInset var centerRightInset = sideInset - 5.0
var rightItemX = context.availableSize.width - sideInset var rightItemX = context.availableSize.width - (sideInset - 5.0)
for item in rightItemList.reversed() { for item in rightItemList.reversed() {
context.add(item context.add(item
.position(CGPoint(x: rightItemX - item.size.width / 2.0 + (item.size.width / 2.0 * 0.35 * context.component.collapseFraction), y: context.component.topInset + contentHeight / 2.0)) .position(CGPoint(x: rightItemX - item.size.width / 2.0 + (item.size.width / 2.0 * 0.35 * context.component.collapseFraction), y: context.component.topInset + contentHeight / 2.0))

View File

@ -2,6 +2,7 @@ import Foundation
import UIKit import UIKit
import SwiftSignalKit import SwiftSignalKit
import Display import Display
import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import ComponentFlow import ComponentFlow
import ViewControllerComponent import ViewControllerComponent
@ -14,6 +15,7 @@ import TelegramUIPreferences
import OpenInExternalAppUI import OpenInExternalAppUI
import MultilineTextComponent import MultilineTextComponent
import MinimizedContainer import MinimizedContainer
import InstantPageUI
private let settingsTag = GenericComponentViewTag() private let settingsTag = GenericComponentViewTag()
@ -72,8 +74,8 @@ private final class BrowserScreenComponent: CombinedComponent {
let performAction = context.component.performAction let performAction = context.component.performAction
let navigationContent: AnyComponentWithIdentity<Empty>? let navigationContent: AnyComponentWithIdentity<Empty>?
let navigationLeftItems: [AnyComponentWithIdentity<Empty>] var navigationLeftItems: [AnyComponentWithIdentity<Empty>]
let navigationRightItems: [AnyComponentWithIdentity<Empty>] var navigationRightItems: [AnyComponentWithIdentity<Empty>]
if context.component.presentationState.isSearching { if context.component.presentationState.isSearching {
navigationContent = AnyComponentWithIdentity( navigationContent = AnyComponentWithIdentity(
id: "search", id: "search",
@ -113,23 +115,6 @@ private final class BrowserScreenComponent: CombinedComponent {
let isLoading = (context.component.contentState?.estimatedProgress ?? 1.0) < 1.0 let isLoading = (context.component.contentState?.estimatedProgress ?? 1.0) < 1.0
navigationRightItems = [ navigationRightItems = [
AnyComponentWithIdentity(
id: isLoading ? "stop" : "reload",
component: AnyComponent(
ReferenceButtonComponent(
content: AnyComponent(
BundleIconComponent(
name: isLoading ? "Instant View/CloseIcon" : "Chat/Context Menu/Reload",
tintColor: environment.theme.rootController.navigationBar.primaryTextColor
)
),
tag: settingsTag,
action: {
performAction.invoke(isLoading ? .stop : .reload)
}
)
)
),
AnyComponentWithIdentity( AnyComponentWithIdentity(
id: "settings", id: "settings",
component: AnyComponent( component: AnyComponent(
@ -148,6 +133,28 @@ private final class BrowserScreenComponent: CombinedComponent {
) )
) )
] ]
if case .webPage = context.component.contentState?.contentType {
navigationRightItems.insert(
AnyComponentWithIdentity(
id: isLoading ? "stop" : "reload",
component: AnyComponent(
ReferenceButtonComponent(
content: AnyComponent(
BundleIconComponent(
name: isLoading ? "Instant View/CloseIcon" : "Chat/Context Menu/Reload",
tintColor: environment.theme.rootController.navigationBar.primaryTextColor
)
),
tag: settingsTag,
action: {
performAction.invoke(isLoading ? .stop : .reload)
}
)
)
),
at: 0
)
}
} }
let collapseFraction = context.component.presentationState.isSearching ? 0.0 : context.component.panelCollapseFraction let collapseFraction = context.component.presentationState.isSearching ? 0.0 : context.component.panelCollapseFraction
@ -303,6 +310,8 @@ public class BrowserScreen: ViewController, MinimizableController {
switch controller.subject { switch controller.subject {
case let .webPage(url): case let .webPage(url):
content = BrowserWebContent(context: controller.context, url: url) content = BrowserWebContent(context: controller.context, url: url)
case let .instantPage(webPage, sourceLocation):
content = BrowserInstantPageContent(context: controller.context, webPage: webPage, url: webPage.content.url ?? "", sourceLocation: sourceLocation)
} }
self.content = content self.content = content
@ -717,6 +726,7 @@ public class BrowserScreen: ViewController, MinimizableController {
public enum Subject { public enum Subject {
case webPage(url: String) case webPage(url: String)
case instantPage(webPage: TelegramMediaWebpage, sourceLocation: InstantPageSourceLocation)
} }
private let context: AccountContext private let context: AccountContext
@ -754,6 +764,7 @@ public class BrowserScreen: ViewController, MinimizableController {
} }
public var isMinimized = false public var isMinimized = false
public var isMinimizable = true
} }
private final class BrowserReferenceContentSource: ContextReferenceContentSource { private final class BrowserReferenceContentSource: ContextReferenceContentSource {

View File

@ -20,6 +20,8 @@ public enum SendMessageActionSheetControllerParams {
public let attachment: Bool public let attachment: Bool
public let canSendWhenOnline: Bool public let canSendWhenOnline: Bool
public let forwardMessageIds: [EngineMessage.Id] public let forwardMessageIds: [EngineMessage.Id]
public let canMakePaidContent: Bool
public let currentPrice: Int64?
public init( public init(
isScheduledMessages: Bool, isScheduledMessages: Bool,
@ -28,7 +30,9 @@ public enum SendMessageActionSheetControllerParams {
messageEffect: (ChatSendMessageActionSheetControllerSendParameters.Effect?, (ChatSendMessageActionSheetControllerSendParameters.Effect?) -> Void)?, messageEffect: (ChatSendMessageActionSheetControllerSendParameters.Effect?, (ChatSendMessageActionSheetControllerSendParameters.Effect?) -> Void)?,
attachment: Bool, attachment: Bool,
canSendWhenOnline: Bool, canSendWhenOnline: Bool,
forwardMessageIds: [EngineMessage.Id] forwardMessageIds: [EngineMessage.Id],
canMakePaidContent: Bool,
currentPrice: Int64?
) { ) {
self.isScheduledMessages = isScheduledMessages self.isScheduledMessages = isScheduledMessages
self.mediaPreview = mediaPreview self.mediaPreview = mediaPreview
@ -37,6 +41,8 @@ public enum SendMessageActionSheetControllerParams {
self.attachment = attachment self.attachment = attachment
self.canSendWhenOnline = canSendWhenOnline self.canSendWhenOnline = canSendWhenOnline
self.forwardMessageIds = forwardMessageIds self.forwardMessageIds = forwardMessageIds
self.canMakePaidContent = canMakePaidContent
self.currentPrice = currentPrice
} }
} }
@ -71,6 +77,7 @@ public func makeChatSendMessageActionSheetController(
completion: @escaping () -> Void, completion: @escaping () -> Void,
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void, sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void,
schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void, schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void,
editPrice: @escaping (Int64) -> Void,
openPremiumPaywall: @escaping (ViewController) -> Void, openPremiumPaywall: @escaping (ViewController) -> Void,
reactionItems: [ReactionItem]? = nil, reactionItems: [ReactionItem]? = nil,
availableMessageEffects: AvailableMessageEffects? = nil, availableMessageEffects: AvailableMessageEffects? = nil,
@ -91,6 +98,7 @@ public func makeChatSendMessageActionSheetController(
completion: completion, completion: completion,
sendMessage: sendMessage, sendMessage: sendMessage,
schedule: schedule, schedule: schedule,
editPrice: editPrice,
openPremiumPaywall: openPremiumPaywall, openPremiumPaywall: openPremiumPaywall,
reactionItems: reactionItems, reactionItems: reactionItems,
availableMessageEffects: availableMessageEffects, availableMessageEffects: availableMessageEffects,

View File

@ -67,6 +67,7 @@ final class ChatSendMessageContextScreenComponent: Component {
let completion: () -> Void let completion: () -> Void
let sendMessage: (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void let sendMessage: (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void
let schedule: (ChatSendMessageActionSheetController.SendParameters?) -> Void let schedule: (ChatSendMessageActionSheetController.SendParameters?) -> Void
let editPrice: (Int64) -> Void
let openPremiumPaywall: (ViewController) -> Void let openPremiumPaywall: (ViewController) -> Void
let reactionItems: [ReactionItem]? let reactionItems: [ReactionItem]?
let availableMessageEffects: AvailableMessageEffects? let availableMessageEffects: AvailableMessageEffects?
@ -87,6 +88,7 @@ final class ChatSendMessageContextScreenComponent: Component {
completion: @escaping () -> Void, completion: @escaping () -> Void,
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void, sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void,
schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void, schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void,
editPrice: @escaping (Int64) -> Void,
openPremiumPaywall: @escaping (ViewController) -> Void, openPremiumPaywall: @escaping (ViewController) -> Void,
reactionItems: [ReactionItem]?, reactionItems: [ReactionItem]?,
availableMessageEffects: AvailableMessageEffects?, availableMessageEffects: AvailableMessageEffects?,
@ -106,6 +108,7 @@ final class ChatSendMessageContextScreenComponent: Component {
self.completion = completion self.completion = completion
self.sendMessage = sendMessage self.sendMessage = sendMessage
self.schedule = schedule self.schedule = schedule
self.editPrice = editPrice
self.openPremiumPaywall = openPremiumPaywall self.openPremiumPaywall = openPremiumPaywall
self.reactionItems = reactionItems self.reactionItems = reactionItems
self.availableMessageEffects = availableMessageEffects self.availableMessageEffects = availableMessageEffects
@ -437,6 +440,8 @@ final class ChatSendMessageContextScreenComponent: Component {
var reminders = false var reminders = false
var isSecret = false var isSecret = false
var canSchedule = false var canSchedule = false
var canMakePaidContent = false
var currentPrice: Int64?
switch component.params { switch component.params {
case let .sendMessage(sendMessage): case let .sendMessage(sendMessage):
if let peerId = component.peerId { if let peerId = component.peerId {
@ -447,6 +452,8 @@ final class ChatSendMessageContextScreenComponent: Component {
if sendMessage.isScheduledMessages { if sendMessage.isScheduledMessages {
canSchedule = false canSchedule = false
} }
canMakePaidContent = sendMessage.canMakePaidContent
currentPrice = sendMessage.currentPrice
case .editMessage: case .editMessage:
break break
} }
@ -566,6 +573,38 @@ final class ChatSendMessageContextScreenComponent: Component {
} }
))) )))
} }
if canMakePaidContent {
let title: String
let titleLayout: ContextMenuActionItemTextLayout
if let currentPrice {
title = environment.strings.Attachment_Paid_EditPrice
titleLayout = .secondLineWithValue(environment.strings.Attachment_Paid_EditPrice_Stars(Int32(currentPrice)))
} else {
title = environment.strings.Attachment_Paid_Create
titleLayout = .twoLinesMax
}
items.append(.action(ContextMenuActionItem(
id: AnyHashable("paid"),
text: title,
textLayout: titleLayout,
icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Paid"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, _ in
guard let self, let component = self.component, case let .sendMessage(params) = component.params else {
return
}
let editPrice = component.editPrice
let controller = component.context.sharedContext.makeStarsAmountScreen(context: component.context, initialValue: params.currentPrice, completion: { amount in
editPrice(amount)
})
self.environment?.controller()?.dismiss()
Queue.mainQueue().after(0.45) {
component.openPremiumPaywall(controller)
}
}
)))
}
case .editMessage: case .editMessage:
items.append(.action(ContextMenuActionItem( items.append(.action(ContextMenuActionItem(
id: AnyHashable("silent"), id: AnyHashable("silent"),
@ -1385,6 +1424,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
completion: @escaping () -> Void, completion: @escaping () -> Void,
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void, sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void,
schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void, schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void,
editPrice: @escaping (Int64) -> Void,
openPremiumPaywall: @escaping (ViewController) -> Void, openPremiumPaywall: @escaping (ViewController) -> Void,
reactionItems: [ReactionItem]?, reactionItems: [ReactionItem]?,
availableMessageEffects: AvailableMessageEffects?, availableMessageEffects: AvailableMessageEffects?,
@ -1409,6 +1449,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
completion: completion, completion: completion,
sendMessage: sendMessage, sendMessage: sendMessage,
schedule: schedule, schedule: schedule,
editPrice: editPrice,
openPremiumPaywall: openPremiumPaywall, openPremiumPaywall: openPremiumPaywall,
reactionItems: reactionItems, reactionItems: reactionItems,
availableMessageEffects: availableMessageEffects, availableMessageEffects: availableMessageEffects,

View File

@ -532,44 +532,7 @@ public final class ComposedPoll {
} }
private final class CreatePollContext: AttachmentMediaPickerContext { private final class CreatePollContext: AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
var hasCaption: Bool {
return false
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
}
} }

View File

@ -24,8 +24,10 @@ public protocol MinimizableController: ViewController {
var minimizedTopEdgeOffset: CGFloat? { get } var minimizedTopEdgeOffset: CGFloat? { get }
var minimizedBounds: CGRect? { get } var minimizedBounds: CGRect? { get }
var isMinimized: Bool { get set } var isMinimized: Bool { get set }
var isMinimizable: Bool { get }
func makeContentSnapshotView() -> UIView? func makeContentSnapshotView() -> UIView?
func shouldDismissImmediately() -> Bool
} }
public extension MinimizableController { public extension MinimizableController {
@ -41,7 +43,15 @@ public extension MinimizableController {
return false return false
} }
var isMinimizable: Bool {
return false
}
func makeContentSnapshotView() -> UIView? { func makeContentSnapshotView() -> UIView? {
return self.displayNode.view.snapshotView(afterScreenUpdates: false) return self.displayNode.view.snapshotView(afterScreenUpdates: false)
} }
func shouldDismissImmediately() -> Bool {
return true
}
} }

View File

@ -319,7 +319,7 @@ public final class InstantPageContentNode : ASDisplayNode {
// } // }
} }
func updateDetailsExpanded(_ index: Int, _ expanded: Bool, animated: Bool = true, requestLayout: Bool = true) { public func updateDetailsExpanded(_ index: Int, _ expanded: Bool, animated: Bool = true, requestLayout: Bool = true) {
if var currentExpandedDetails = self.currentExpandedDetails { if var currentExpandedDetails = self.currentExpandedDetails {
currentExpandedDetails[index] = expanded currentExpandedDetails[index] = expanded
self.currentExpandedDetails = currentExpandedDetails self.currentExpandedDetails = currentExpandedDetails
@ -353,7 +353,7 @@ public final class InstantPageContentNode : ASDisplayNode {
return contentOffset return contentOffset
} }
func nodeForDetailsItem(_ item: InstantPageDetailsItem) -> InstantPageDetailsNode? { public func nodeForDetailsItem(_ item: InstantPageDetailsItem) -> InstantPageDetailsNode? {
for (_, itemNode) in self.visibleItemsWithNodes { for (_, itemNode) in self.visibleItemsWithNodes {
if let detailsNode = itemNode as? InstantPageDetailsNode, detailsNode.item === item { if let detailsNode = itemNode as? InstantPageDetailsNode, detailsNode.item === item {
return detailsNode return detailsNode

View File

@ -26,7 +26,7 @@ public final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
private let buttonNode: HighlightableButtonNode private let buttonNode: HighlightableButtonNode
private let arrowNode: InstantPageDetailsArrowNode private let arrowNode: InstantPageDetailsArrowNode
let separatorNode: ASDisplayNode let separatorNode: ASDisplayNode
let contentNode: InstantPageContentNode public let contentNode: InstantPageContentNode
private let updateExpanded: (Bool) -> Void private let updateExpanded: (Bool) -> Void
var expanded: Bool var expanded: Bool
@ -114,7 +114,7 @@ public final class InstantPageDetailsNode: ASDisplayNode, InstantPageNode {
self.updateExpanded(expanded) self.updateExpanded(expanded)
} }
func setExpanded(_ expanded: Bool, animated: Bool) { public func setExpanded(_ expanded: Bool, animated: Bool) {
self.expanded = expanded self.expanded = expanded
self.arrowNode.setOpen(expanded, animated: animated) self.arrowNode.setOpen(expanded, animated: animated)
} }

View File

@ -20,7 +20,7 @@ public final class InstantPageImageItem: InstantPageItem {
let webPage: TelegramMediaWebpage let webPage: TelegramMediaWebpage
let media: InstantPageMedia public let media: InstantPageMedia
let attributes: [InstantPageImageAttribute] let attributes: [InstantPageImageAttribute]
public var medias: [InstantPageMedia] { public var medias: [InstantPageMedia] {

View File

@ -50,11 +50,11 @@ public final class InstantPageScrollableContentNode: ASDisplayNode {
} }
} }
final class InstantPageScrollableNode: ASScrollNode, InstantPageNode { public final class InstantPageScrollableNode: ASScrollNode, InstantPageNode {
let item: InstantPageScrollableItem public let item: InstantPageScrollableItem
let contentNode: InstantPageScrollableContentNode let contentNode: InstantPageScrollableContentNode
var contentOffset: CGPoint { public var contentOffset: CGPoint {
return self.view.contentOffset return self.view.contentOffset
} }
@ -90,19 +90,19 @@ final class InstantPageScrollableNode: ASScrollNode, InstantPageNode {
} }
} }
func updateIsVisible(_ isVisible: Bool) { public func updateIsVisible(_ isVisible: Bool) {
} }
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
} }
func transitionNode(media: InstantPageMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { public func transitionNode(media: InstantPageMedia) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
return nil return nil
} }
func updateHiddenMedia(media: InstantPageMedia?) { public func updateHiddenMedia(media: InstantPageMedia?) {
} }
func update(strings: PresentationStrings, theme: InstantPageTheme) { public func update(strings: PresentationStrings, theme: InstantPageTheme) {
} }
} }

View File

@ -96,7 +96,7 @@ public final class InstantPageTextItem: InstantPageItem {
let alignment: NSTextAlignment let alignment: NSTextAlignment
let opaqueBackground: Bool let opaqueBackground: Bool
public let medias: [InstantPageMedia] = [] public let medias: [InstantPageMedia] = []
let anchors: [String: (Int, Bool)] public let anchors: [String: (Int, Bool)]
public let wantsNode: Bool = false public let wantsNode: Bool = false
public let separatesTiles: Bool = false public let separatesTiles: Bool = false
public var selectable: Bool = true public var selectable: Bool = true

View File

@ -84,32 +84,32 @@ public struct InstantPageTextCategories {
} }
public final class InstantPageTheme { public final class InstantPageTheme {
let type: InstantPageThemeType public let type: InstantPageThemeType
let pageBackgroundColor: UIColor public let pageBackgroundColor: UIColor
let textCategories: InstantPageTextCategories public let textCategories: InstantPageTextCategories
let serif: Bool public let serif: Bool
let codeBlockBackgroundColor: UIColor public let codeBlockBackgroundColor: UIColor
let linkColor: UIColor public let linkColor: UIColor
let textHighlightColor: UIColor public let textHighlightColor: UIColor
let linkHighlightColor: UIColor public let linkHighlightColor: UIColor
let markerColor: UIColor public let markerColor: UIColor
let panelBackgroundColor: UIColor public let panelBackgroundColor: UIColor
let panelHighlightedBackgroundColor: UIColor public let panelHighlightedBackgroundColor: UIColor
let panelPrimaryColor: UIColor public let panelPrimaryColor: UIColor
let panelSecondaryColor: UIColor public let panelSecondaryColor: UIColor
let panelAccentColor: UIColor public let panelAccentColor: UIColor
let tableBorderColor: UIColor public let tableBorderColor: UIColor
let tableHeaderColor: UIColor public let tableHeaderColor: UIColor
let controlColor: UIColor public let controlColor: UIColor
let imageTintColor: UIColor? public let imageTintColor: UIColor?
let overlayPanelColor: UIColor public let overlayPanelColor: UIColor
public init(type: InstantPageThemeType, pageBackgroundColor: UIColor, textCategories: InstantPageTextCategories, serif: Bool, codeBlockBackgroundColor: UIColor, linkColor: UIColor, textHighlightColor: UIColor, linkHighlightColor: UIColor, markerColor: UIColor, panelBackgroundColor: UIColor, panelHighlightedBackgroundColor: UIColor, panelPrimaryColor: UIColor, panelSecondaryColor: UIColor, panelAccentColor: UIColor, tableBorderColor: UIColor, tableHeaderColor: UIColor, controlColor: UIColor, imageTintColor: UIColor?, overlayPanelColor: UIColor) { public init(type: InstantPageThemeType, pageBackgroundColor: UIColor, textCategories: InstantPageTextCategories, serif: Bool, codeBlockBackgroundColor: UIColor, linkColor: UIColor, textHighlightColor: UIColor, linkHighlightColor: UIColor, markerColor: UIColor, panelBackgroundColor: UIColor, panelHighlightedBackgroundColor: UIColor, panelPrimaryColor: UIColor, panelSecondaryColor: UIColor, panelAccentColor: UIColor, tableBorderColor: UIColor, tableHeaderColor: UIColor, controlColor: UIColor, imageTintColor: UIColor?, overlayPanelColor: UIColor) {
self.type = type self.type = type
@ -308,7 +308,7 @@ func instantPageThemeTypeForSettingsAndTime(themeSettings: PresentationThemeSett
return (settings.themeType, false) return (settings.themeType, false)
} }
func instantPageThemeForType(_ type: InstantPageThemeType, settings: InstantPagePresentationSettings) -> InstantPageTheme { public func instantPageThemeForType(_ type: InstantPageThemeType, settings: InstantPagePresentationSettings) -> InstantPageTheme {
switch type { switch type {
case .light: case .light:
return lightTheme.withUpdatedFontStyles(sizeMultiplier: fontSizeMultiplierForVariant(settings.fontSize), forceSerif: settings.forceSerif) return lightTheme.withUpdatedFontStyles(sizeMultiplier: fontSizeMultiplierForVariant(settings.fontSize), forceSerif: settings.forceSerif)

View File

@ -397,44 +397,6 @@ public final class LocationPickerController: ViewController, AttachmentContainab
} }
private final class LocationPickerContext: AttachmentMediaPickerContext { private final class LocationPickerContext: AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var hasCaption: Bool {
return false
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
}
} }
public func storyLocationPickerController( public func storyLocationPickerController(

View File

@ -188,7 +188,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
private let bannedSendPhotos: (Int32, Bool)? private let bannedSendPhotos: (Int32, Bool)?
private let bannedSendVideos: (Int32, Bool)? private let bannedSendVideos: (Int32, Bool)?
private let canBoostToUnrestrict: Bool private let canBoostToUnrestrict: Bool
private let paidMediaAllowed: Bool fileprivate let paidMediaAllowed: Bool
private let subject: Subject private let subject: Subject
private let saveEditedPhotos: Bool private let saveEditedPhotos: Bool
@ -2207,7 +2207,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
}) })
} }
private var selectionCount: Int32 = 0 fileprivate var selectionCount: Int32 = 0
fileprivate func updateSelectionState(count: Int32) { fileprivate func updateSelectionState(count: Int32) {
self.selectionCount = count self.selectionCount = count
@ -2667,6 +2667,45 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
return isForcedCaption return isForcedCaption
} }
var canMakePaidContent: Bool {
guard let controller = self.controller else {
return false
}
var isPaidAvailable = false
if controller.paidMediaAllowed && controller.selectionCount <= 10 {
isPaidAvailable = true
}
return isPaidAvailable
}
var price: Int64? {
guard let controller = self.controller else {
return nil
}
var price: Int64?
if let selectionContext = controller.interaction?.selectionState, let editingContext = controller.interaction?.editingState {
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
if price == nil, let itemPrice = editingContext.price(for: item) as? Int64 {
price = itemPrice
break
}
}
}
return price
}
func setPrice(_ price: Int64) {
guard let controller = self.controller else {
return
}
if let selectionContext = controller.interaction?.selectionState, let editingContext = controller.interaction?.editingState {
selectionContext.selectionLimit = 10
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
editingContext.setPrice(NSNumber(value: price), for: item)
}
}
}
var captionIsAboveMedia: Signal<Bool, NoError> { var captionIsAboveMedia: Signal<Bool, NoError> {
return Signal { [weak self] subscriber in return Signal { [weak self] subscriber in
guard let interaction = self?.controller?.interaction else { guard let interaction = self?.controller?.interaction else {

View File

@ -1516,11 +1516,14 @@ private func monetizationEntries(
starsTransactionsInfo: StarsTransactionsContext.State, starsTransactionsInfo: StarsTransactionsContext.State,
adsRestricted: Bool, adsRestricted: Bool,
premiumConfiguration: PremiumConfiguration, premiumConfiguration: PremiumConfiguration,
monetizationConfiguration: MonetizationConfiguration monetizationConfiguration: MonetizationConfiguration,
canViewRevenue: Bool,
canViewStarsRevenue: Bool
) -> [StatsEntry] { ) -> [StatsEntry] {
var entries: [StatsEntry] = [] var entries: [StatsEntry] = []
entries.append(.adsHeader(presentationData.theme, presentationData.strings.Monetization_Header)) entries.append(.adsHeader(presentationData.theme, presentationData.strings.Monetization_Header))
if canViewRevenue {
if !data.topHoursGraph.isEmpty { if !data.topHoursGraph.isEmpty {
entries.append(.adsImpressionsTitle(presentationData.theme, presentationData.strings.Monetization_ImpressionsTitle)) entries.append(.adsImpressionsTitle(presentationData.theme, presentationData.strings.Monetization_ImpressionsTitle))
entries.append(.adsImpressionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.topHoursGraph, .hourlyStep)) entries.append(.adsImpressionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.topHoursGraph, .hourlyStep))
@ -1530,11 +1533,14 @@ private func monetizationEntries(
entries.append(.adsTonRevenueTitle(presentationData.theme, presentationData.strings.Monetization_AdRevenueTitle)) entries.append(.adsTonRevenueTitle(presentationData.theme, presentationData.strings.Monetization_AdRevenueTitle))
entries.append(.adsTonRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.revenueGraph, .currency, data.usdRate)) entries.append(.adsTonRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.revenueGraph, .currency, data.usdRate))
} }
}
if canViewStarsRevenue {
if let starsData, !starsData.revenueGraph.isEmpty { if let starsData, !starsData.revenueGraph.isEmpty {
entries.append(.adsStarsRevenueTitle(presentationData.theme, presentationData.strings.Monetization_StarsRevenueTitle)) entries.append(.adsStarsRevenueTitle(presentationData.theme, presentationData.strings.Monetization_StarsRevenueTitle))
entries.append(.adsStarsRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, starsData.revenueGraph, .stars, starsData.usdRate)) entries.append(.adsStarsRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, starsData.revenueGraph, .stars, starsData.usdRate))
} }
}
entries.append(.adsProceedsTitle(presentationData.theme, presentationData.strings.Monetization_OverviewTitle)) entries.append(.adsProceedsTitle(presentationData.theme, presentationData.strings.Monetization_OverviewTitle))
entries.append(.adsProceedsOverview(presentationData.theme, data, starsData)) entries.append(.adsProceedsOverview(presentationData.theme, data, starsData))
@ -1543,6 +1549,8 @@ private func monetizationEntries(
if let peer, case let .channel(channel) = peer, channel.flags.contains(.isCreator) { if let peer, case let .channel(channel) = peer, channel.flags.contains(.isCreator) {
isCreator = true isCreator = true
} }
if canViewRevenue {
entries.append(.adsTonBalanceTitle(presentationData.theme, presentationData.strings.Monetization_TonBalanceTitle)) entries.append(.adsTonBalanceTitle(presentationData.theme, presentationData.strings.Monetization_TonBalanceTitle))
entries.append(.adsTonBalance(presentationData.theme, data, isCreator && data.balances.availableBalance > 0, monetizationConfiguration.withdrawalAvailable)) entries.append(.adsTonBalance(presentationData.theme, data, isCreator && data.balances.availableBalance > 0, monetizationConfiguration.withdrawalAvailable))
@ -1557,26 +1565,29 @@ private func monetizationEntries(
} }
entries.append(.adsTonBalanceInfo(presentationData.theme, withdrawalInfoText)) entries.append(.adsTonBalanceInfo(presentationData.theme, withdrawalInfoText))
} }
}
if canViewStarsRevenue {
if let starsData, starsData.balances.overallRevenue > 0 { if let starsData, starsData.balances.overallRevenue > 0 {
entries.append(.adsStarsBalanceTitle(presentationData.theme, presentationData.strings.Monetization_StarsBalanceTitle)) entries.append(.adsStarsBalanceTitle(presentationData.theme, presentationData.strings.Monetization_StarsBalanceTitle))
entries.append(.adsStarsBalance(presentationData.theme, starsData, isCreator && starsData.balances.availableBalance > 0, starsData.balances.withdrawEnabled, starsData.balances.nextWithdrawalTimestamp)) entries.append(.adsStarsBalance(presentationData.theme, starsData, isCreator && starsData.balances.availableBalance > 0, starsData.balances.withdrawEnabled, starsData.balances.nextWithdrawalTimestamp))
entries.append(.adsStarsBalanceInfo(presentationData.theme, presentationData.strings.Monetization_Balance_StarsInfo)) entries.append(.adsStarsBalanceInfo(presentationData.theme, presentationData.strings.Monetization_Balance_StarsInfo))
} }
}
var addedTransactionsTabs = false var addedTransactionsTabs = false
if !transactionsInfo.transactions.isEmpty && !starsTransactionsInfo.transactions.isEmpty { if !transactionsInfo.transactions.isEmpty && !starsTransactionsInfo.transactions.isEmpty && canViewRevenue && canViewStarsRevenue {
addedTransactionsTabs = true addedTransactionsTabs = true
entries.append(.adsTransactionsTabs(presentationData.theme, presentationData.strings.Monetization_TonTransactions, presentationData.strings.Monetization_StarsTransactions, state.starsSelected)) entries.append(.adsTransactionsTabs(presentationData.theme, presentationData.strings.Monetization_TonTransactions, presentationData.strings.Monetization_StarsTransactions, state.starsSelected))
} }
var displayTonTransactions = false var displayTonTransactions = false
if !transactionsInfo.transactions.isEmpty && (starsTransactionsInfo.transactions.isEmpty || !state.starsSelected) { if canViewRevenue && !transactionsInfo.transactions.isEmpty && (starsTransactionsInfo.transactions.isEmpty || !state.starsSelected) {
displayTonTransactions = true displayTonTransactions = true
} }
var displayStarsTransactions = false var displayStarsTransactions = false
if !starsTransactionsInfo.transactions.isEmpty && (transactionsInfo.transactions.isEmpty || state.starsSelected) { if canViewStarsRevenue && !starsTransactionsInfo.transactions.isEmpty && (transactionsInfo.transactions.isEmpty || state.starsSelected) {
displayStarsTransactions = true displayStarsTransactions = true
} }
@ -1675,7 +1686,9 @@ private func channelStatsControllerEntries(
starsTransactions: StarsTransactionsContext.State, starsTransactions: StarsTransactionsContext.State,
adsRestricted: Bool, adsRestricted: Bool,
premiumConfiguration: PremiumConfiguration, premiumConfiguration: PremiumConfiguration,
monetizationConfiguration: MonetizationConfiguration monetizationConfiguration: MonetizationConfiguration,
canViewRevenue: Bool,
canViewStarsRevenue: Bool
) -> [StatsEntry] { ) -> [StatsEntry] {
switch state.section { switch state.section {
case .stats: case .stats:
@ -1715,7 +1728,9 @@ private func channelStatsControllerEntries(
starsTransactionsInfo: starsTransactions, starsTransactionsInfo: starsTransactions,
adsRestricted: adsRestricted, adsRestricted: adsRestricted,
premiumConfiguration: premiumConfiguration, premiumConfiguration: premiumConfiguration,
monetizationConfiguration: monetizationConfiguration monetizationConfiguration: monetizationConfiguration,
canViewRevenue: canViewRevenue,
canViewStarsRevenue: canViewStarsRevenue
) )
} }
} }
@ -2039,7 +2054,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
) )
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, state, peer, data, messageView, stories, boostData, boostersState, giftsState, revenueState, revenueTransactions, starsState, starsTransactions, peerData, longLoading -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, state, peer, data, messageView, stories, boostData, boostersState, giftsState, revenueState, revenueTransactions, starsState, starsTransactions, peerData, longLoading -> (ItemListControllerState, (ItemListNodeState, Any)) in
let (adsRestricted, canViewRevenue, _) = peerData let (adsRestricted, canViewRevenue, canViewStarsRevenue) = peerData
var isGroup = false var isGroup = false
if let peer, case let .channel(channel) = peer, case .group = channel.info { if let peer, case let .channel(channel) = peer, case .group = channel.info {
@ -2124,14 +2139,14 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
var tabs: [String] = [] var tabs: [String] = []
tabs.append(presentationData.strings.Stats_Statistics) tabs.append(presentationData.strings.Stats_Statistics)
tabs.append(presentationData.strings.Stats_Boosts) tabs.append(presentationData.strings.Stats_Boosts)
if canViewRevenue { if canViewRevenue || canViewStarsRevenue {
tabs.append(presentationData.strings.Stats_Monetization) tabs.append(presentationData.strings.Stats_Monetization)
} }
title = .textWithTabs(peer?.compactDisplayTitle ?? "", tabs, index) title = .textWithTabs(peer?.compactDisplayTitle ?? "", tabs, index)
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: title, leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(presentationData: presentationData, state: state, peer: peer, data: data, messages: messages, stories: stories, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable, isGroup: isGroup, boostsOnly: boostsOnly, revenueState: revenueState?.stats, revenueTransactions: revenueTransactions, starsState: starsState?.stats, starsTransactions: starsTransactions, adsRestricted: adsRestricted, premiumConfiguration: premiumConfiguration, monetizationConfiguration: monetizationConfiguration), style: .blocks, emptyStateItem: emptyStateItem, headerItem: headerItem, crossfadeState: previous == nil, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(presentationData: presentationData, state: state, peer: peer, data: data, messages: messages, stories: stories, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable, isGroup: isGroup, boostsOnly: boostsOnly, revenueState: revenueState?.stats, revenueTransactions: revenueTransactions, starsState: starsState?.stats, starsTransactions: starsTransactions, adsRestricted: adsRestricted, premiumConfiguration: premiumConfiguration, monetizationConfiguration: monetizationConfiguration, canViewRevenue: canViewRevenue, canViewStarsRevenue: canViewStarsRevenue), style: .blocks, emptyStateItem: emptyStateItem, headerItem: headerItem, crossfadeState: previous == nil, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -179,7 +179,17 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
case .text: case .text:
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingMessageIconImage : graphics.chatBubbleActionButtonOutgoingMessageIconImage iconImage = incoming ? graphics.chatBubbleActionButtonIncomingMessageIconImage : graphics.chatBubbleActionButtonOutgoingMessageIconImage
case let .url(value): case let .url(value):
if isTelegramMeLink(value), let internalUrl = parseFullInternalUrl(sharedContext: context.sharedContext, url: value), case .peer(_, .appStart) = internalUrl { var isApp = false
if isTelegramMeLink(value), let internalUrl = parseFullInternalUrl(sharedContext: context.sharedContext, url: value) {
if case .peer(_, .appStart) = internalUrl {
isApp = true
} else if case .peer(_, .attachBotStart) = internalUrl {
isApp = true
} else if case .startAttach = internalUrl {
isApp = true
}
}
if isApp {
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingWebAppIconImage : graphics.chatBubbleActionButtonOutgoingWebAppIconImage iconImage = incoming ? graphics.chatBubbleActionButtonIncomingWebAppIconImage : graphics.chatBubbleActionButtonOutgoingWebAppIconImage
} else if value.lowercased().contains("?startgroup=") { } else if value.lowercased().contains("?startgroup=") {
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingAddToChatIconImage : graphics.chatBubbleActionButtonOutgoingAddToChatIconImage iconImage = incoming ? graphics.chatBubbleActionButtonIncomingAddToChatIconImage : graphics.chatBubbleActionButtonOutgoingAddToChatIconImage

View File

@ -697,11 +697,15 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
self.scrollView.addSubnode(itemNode) self.scrollView.addSubnode(itemNode)
self.itemNodes[item.id] = itemNode self.itemNodes[item.id] = itemNode
} }
itemNode.closeTapped = { [weak self] in itemNode.closeTapped = { [weak self, weak itemNode] in
guard let self else { guard let self else {
return return
} }
if self.isExpanded { if self.isExpanded {
let proceed = { [weak self] in
guard let self else {
return
}
var needsLayout = true var needsLayout = true
self.currentTransition = .dismiss(itemId: item.id) self.currentTransition = .dismiss(itemId: item.id)
@ -714,10 +718,72 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
if needsLayout { if needsLayout {
self.requestUpdate(transition: .animated(duration: 0.4, curve: .spring)) self.requestUpdate(transition: .animated(duration: 0.4, curve: .spring))
} }
}
if let item = itemNode?.item, !item.controller.shouldDismissImmediately() {
let actionSheet = ActionSheetController(presentationData: self.presentationData)
actionSheet.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetTextItem(title: self.presentationData.strings.WebApp_CloseConfirmation),
ActionSheetButtonItem(title: self.presentationData.strings.WebApp_CloseAnyway, color: .destructive, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
proceed()
})
]),
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])
])
self.navigationController?.presentOverlay(controller: actionSheet, inGlobal: false, blockInteraction: false)
} else {
proceed()
}
} else {
if self.items.count > 1 {
let actionSheet = ActionSheetController(presentationData: self.presentationData)
actionSheet.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetTextItem(title: self.presentationData.strings.WebApp_Minimized_CloseAllTitle),
ActionSheetButtonItem(title: self.presentationData.strings.WebApp_Minimized_CloseAll(Int32(self.items.count)), color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
self?.navigationController?.dismissMinimizedControllers(animated: true)
})
]),
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])
])
self.navigationController?.presentOverlay(controller: actionSheet, inGlobal: false, blockInteraction: false)
} else if let item = self.items.first {
if !item.controller.shouldDismissImmediately() {
let actionSheet = ActionSheetController(presentationData: self.presentationData)
actionSheet.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetTextItem(title: self.presentationData.strings.WebApp_CloseConfirmation),
ActionSheetButtonItem(title: self.presentationData.strings.WebApp_CloseAnyway, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
self?.navigationController?.dismissMinimizedControllers(animated: true)
})
]),
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])
])
self.navigationController?.presentOverlay(controller: actionSheet, inGlobal: false, blockInteraction: false)
} else { } else {
self.navigationController?.dismissMinimizedControllers(animated: true) self.navigationController?.dismissMinimizedControllers(animated: true)
} }
} }
}
}
itemNode.tapped = { [weak self, weak itemNode] in itemNode.tapped = { [weak self, weak itemNode] in
guard let self else { guard let self else {
return return

View File

@ -709,7 +709,9 @@ final class PeerSelectionControllerNode: ASDisplayNode {
messageEffect: nil, messageEffect: nil,
attachment: false, attachment: false,
canSendWhenOnline: false, canSendWhenOnline: false,
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
canMakePaidContent: false,
currentPrice: nil
)), )),
hasEntityKeyboard: hasEntityKeyboard, hasEntityKeyboard: hasEntityKeyboard,
gesture: gesture, gesture: gesture,
@ -731,6 +733,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
schedule: { [weak textInputPanelNode] messageEffect in schedule: { [weak textInputPanelNode] messageEffect in
textInputPanelNode?.sendMessage(.schedule, messageEffect) textInputPanelNode?.sendMessage(.schedule, messageEffect)
}, },
editPrice: { _ in },
openPremiumPaywall: { [weak controller] c in openPremiumPaywall: { [weak controller] c in
guard let controller else { guard let controller else {
return return

View File

@ -27,29 +27,6 @@ public class PremiumGiftAttachmentScreen: PremiumGiftScreen, AttachmentContainab
private final class PremiumGiftContext: AttachmentMediaPickerContext { private final class PremiumGiftContext: AttachmentMediaPickerContext {
private weak var controller: PremiumGiftScreen? private weak var controller: PremiumGiftScreen?
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var hasCaption: Bool {
return false
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return self.controller?.mainButtonStatePromise.get() ?? .single(nil) return self.controller?.mainButtonStatePromise.get() ?? .single(nil)
} }
@ -58,15 +35,6 @@ private final class PremiumGiftContext: AttachmentMediaPickerContext {
self.controller = controller self.controller = controller
} }
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() { func mainButtonAction() {
self.controller?.mainButtonPressed() self.controller?.mainButtonPressed()
} }

View File

@ -355,29 +355,6 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
private final class ThemeColorsGridContext: AttachmentMediaPickerContext { private final class ThemeColorsGridContext: AttachmentMediaPickerContext {
private weak var controller: ThemeColorsGridController? private weak var controller: ThemeColorsGridController?
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var hasCaption: Bool {
return false
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(self.controller?.mainButtonState) return .single(self.controller?.mainButtonState)
} }
@ -386,15 +363,6 @@ private final class ThemeColorsGridContext: AttachmentMediaPickerContext {
self.controller = controller self.controller = controller
} }
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() { func mainButtonAction() {
self.controller?.mainButtonPressed() self.controller?.mainButtonPressed()
} }

View File

@ -164,44 +164,6 @@ private func attachmentFileControllerEntries(presentationData: PresentationData,
} }
private final class AttachmentFileContext: AttachmentMediaPickerContext { private final class AttachmentFileContext: AttachmentMediaPickerContext {
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var hasCaption: Bool {
return false
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
}
} }
class AttachmentFileControllerImpl: ItemListController, AttachmentFileController, AttachmentContainable { class AttachmentFileControllerImpl: ItemListController, AttachmentFileController, AttachmentContainable {

View File

@ -78,7 +78,6 @@ public extension ChatControllerImpl {
if source == .menu { if source == .menu {
self.updateChatPresentationInterfaceState(interactive: false) { state in self.updateChatPresentationInterfaceState(interactive: false) { state in
return state.updatedForceInputCommandsHidden(true) return state.updatedForceInputCommandsHidden(true)
// return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
} }
if let navigationController = self.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer { if let navigationController = self.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer {
@ -199,7 +198,7 @@ public extension ChatControllerImpl {
} }
})) }))
} else { } else {
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(self.presentationData.theme), fromMenu: buttonText == "Menu", replyToMessageId: nil, threadId: self.chatLocation.threadId) self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestWebView(peerId: peerId, botId: peerId, url: !url.isEmpty ? url : nil, payload: nil, themeParams: generateWebAppThemeParams(self.presentationData.theme), fromMenu: false, replyToMessageId: nil, threadId: self.chatLocation.threadId)
|> afterDisposed { |> afterDisposed {
updateProgress() updateProgress()
}) })
@ -208,7 +207,7 @@ public extension ChatControllerImpl {
return return
} }
let context = strongSelf.context let context = strongSelf.context
let params = WebAppParameters(source: .generic, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize)) let params = WebAppParameters(source: .button, peerId: peerId, botId: peerId, botName: botName, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit) self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}, completion: { [weak self] in }, completion: { [weak self] in

View File

@ -163,6 +163,8 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
selfController.interfaceInteraction?.editMessage() selfController.interfaceInteraction?.editMessage()
}, },
schedule: { _ in schedule: { _ in
},
editPrice: { _ in
}, openPremiumPaywall: { [weak selfController] c in }, openPremiumPaywall: { [weak selfController] c in
guard let selfController else { guard let selfController else {
return return
@ -231,7 +233,9 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
}), }),
attachment: false, attachment: false,
canSendWhenOnline: sendWhenOnlineAvailable, canSendWhenOnline: sendWhenOnlineAvailable,
forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
canMakePaidContent: false,
currentPrice: nil
)), )),
hasEntityKeyboard: hasEntityKeyboard, hasEntityKeyboard: hasEntityKeyboard,
gesture: gesture, gesture: gesture,
@ -271,6 +275,7 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
return return
} }
selfController.controllerInteraction?.scheduleCurrentMessage(params) selfController.controllerInteraction?.scheduleCurrentMessage(params)
}, editPrice: { _ in
}, openPremiumPaywall: { [weak selfController] c in }, openPremiumPaywall: { [weak selfController] c in
guard let selfController else { guard let selfController else {
return return

View File

@ -454,29 +454,6 @@ final class ContactsPickerContext: AttachmentMediaPickerContext {
} }
} }
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var hasCaption: Bool {
return false
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
init(controller: ContactSelectionControllerImpl) { init(controller: ContactSelectionControllerImpl) {
self.controller = controller self.controller = controller
} }

View File

@ -24,6 +24,7 @@ import WebsiteType
import GalleryData import GalleryData
import StoryContainerScreen import StoryContainerScreen
import WallpaperGalleryScreen import WallpaperGalleryScreen
import BrowserUI
func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
var story: TelegramMediaStory? var story: TelegramMediaStory?
@ -373,7 +374,13 @@ func openChatInstantPageImpl(context: AccountContext, message: Message, sourcePe
if let (webpage, anchor) = instantPageAndAnchor(message: message) { if let (webpage, anchor) = instantPageAndAnchor(message: message) {
let sourceLocation = InstantPageSourceLocation(userLocation: .peer(message.id.peerId), peerType: sourcePeerType ?? .channel) let sourceLocation = InstantPageSourceLocation(userLocation: .peer(message.id.peerId), peerType: sourcePeerType ?? .channel)
let pageController = InstantPageController(context: context, webPage: webpage, sourceLocation: sourceLocation, anchor: anchor) let pageController: ViewController
if !"".isEmpty, context.sharedContext.immediateExperimentalUISettings.browserExperiment {
let _ = anchor
pageController = BrowserScreen(context: context, subject: .instantPage(webPage: webpage, sourceLocation: sourceLocation))
} else {
pageController = InstantPageController(context: context, webPage: webpage, sourceLocation: sourceLocation, anchor: anchor)
}
navigationController.pushViewController(pageController) navigationController.pushViewController(pageController)
} }
} }

View File

@ -590,25 +590,6 @@ public class WebSearchPickerContext: AttachmentMediaPickerContext {
} }
} }
public var hasCaption: Bool {
return false
}
public var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
public func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> {
return .single(nil)
}
public var mainButtonState: Signal<AttachmentMainButtonState?, NoError> {
return .single(nil)
}
init(interaction: WebSearchControllerInteraction) { init(interaction: WebSearchControllerInteraction) {
self.interaction = interaction self.interaction = interaction
} }
@ -624,8 +605,4 @@ public class WebSearchPickerContext: AttachmentMediaPickerContext {
public func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) { public func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
self.interaction?.schedule(parameters) self.interaction?.schedule(parameters)
} }
public func mainButtonAction() {
}
} }

View File

@ -184,6 +184,7 @@ public class WebAppCancelButtonNode: ASDisplayNode {
public struct WebAppParameters { public struct WebAppParameters {
public enum Source { public enum Source {
case generic case generic
case button
case menu case menu
case attachMenu case attachMenu
case inline case inline
@ -1211,6 +1212,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.openBotSettings() self.openBotSettings()
} }
case "web_app_setup_swipe_behavior":
if let json = json, let isPanGestureEnabled = json["allow_vertical_swipe"] as? Bool {
self.controller?._isPanGestureEnabled = isPanGestureEnabled
}
default: default:
break break
} }
@ -1949,7 +1954,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
switch self.source { switch self.source {
case .generic, .settings: case .generic, .settings:
completion() completion()
case .inline, .attachMenu, .menu, .simple: case .button, .inline, .attachMenu, .menu, .simple:
let _ = (self.context.engine.data.get( let _ = (self.context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId) TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId)
) )
@ -2179,10 +2184,28 @@ public final class WebAppController: ViewController, AttachmentContainable {
} }
} }
public func shouldDismissImmediately() -> Bool { public var isMinimizable: Bool {
return true return true
} }
public func shouldDismissImmediately() -> Bool {
if self.controllerNode.needDismissConfirmation {
return false
} else {
return true
}
}
fileprivate var _isPanGestureEnabled = true
public var isInnerPanGestureEnabled: (() -> Bool)? {
return { [weak self] in
guard let self else {
return true
}
return self._isPanGestureEnabled
}
}
fileprivate var canMinimize: Bool { fileprivate var canMinimize: Bool {
return self.controllerNode.canMinimize return self.controllerNode.canMinimize
} }
@ -2191,25 +2214,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
final class WebAppPickerContext: AttachmentMediaPickerContext { final class WebAppPickerContext: AttachmentMediaPickerContext {
private weak var controller: WebAppController? private weak var controller: WebAppController?
var selectionCount: Signal<Int, NoError> {
return .single(0)
}
var caption: Signal<NSAttributedString?, NoError> {
return .single(nil)
}
var hasCaption: Bool {
return false
}
var captionIsAboveMedia: Signal<Bool, NoError> {
return .single(false)
}
func setCaptionIsAboveMedia(_ captionIsAboveMedia: Bool) -> Void {
}
public var loadingProgress: Signal<CGFloat?, NoError> { public var loadingProgress: Signal<CGFloat?, NoError> {
return self.controller?.controllerNode.loadingProgressPromise.get() ?? .single(nil) return self.controller?.controllerNode.loadingProgressPromise.get() ?? .single(nil)
} }
@ -2222,15 +2226,6 @@ final class WebAppPickerContext: AttachmentMediaPickerContext {
self.controller = controller self.controller = controller
} }
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() { func mainButtonAction() {
self.controller?.controllerNode.mainButtonPressed() self.controller?.controllerNode.mainButtonPressed()
} }