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_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.AmountTitle" = "ENTER AMOUNT";
"Stars.SendStars.AmountPlaceholder" = "Stars Amount";

View File

@ -71,6 +71,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
var isPanningUpdated: (Bool) -> Void = { _ in }
var isExpandedUpdated: (Bool) -> Void = { _ in }
var isPanGestureEnabled: (() -> Bool)?
var isInnerPanGestureEnabled: (() -> Bool)?
var onExpandAnimationCompleted: () -> Void = {}
init(isFullSize: Bool) {
@ -146,6 +147,23 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
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
}
@ -163,23 +181,6 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
}
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 {
return true
}
@ -197,7 +198,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
private var panGestureArguments: (topInset: CGFloat, offset: CGFloat, scrollView: UIScrollView?, listNode: ListView?)?
@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
}
@ -271,9 +272,13 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
}
if !self.isExpanded || self.isFullSize, translation > 40.0, let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() {
self.cancelPanGesture()
self.requestDismiss?()
return
if lastController.isMinimizable {
} else {
self.cancelPanGesture()
self.requestDismiss?()
return
}
}
var bounds = self.bounds
@ -323,7 +328,11 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
var ignoreDismiss = false
if let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() {
ignoreDismiss = true
if lastController.isMinimizable {
} else {
ignoreDismiss = true
}
}
var minimizing = false

View File

@ -121,6 +121,7 @@ public protocol AttachmentContainable: ViewController, MinimizableController {
var isContainerPanning: () -> Bool { get set }
var isContainerExpanded: () -> Bool { get set }
var isPanGestureEnabled: (() -> Bool)? { get }
var isInnerPanGestureEnabled: (() -> Bool)? { get }
var mediaPickerContext: AttachmentMediaPickerContext? { get }
var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)? { get }
@ -172,6 +173,10 @@ public extension AttachmentContainable {
return nil
}
var isInnerPanGestureEnabled: (() -> Bool)? {
return nil
}
var getCurrentSendMessageContextMediaPreview: (() -> ChatSendMessageContextScreenMediaPreview?)? {
return nil
}
@ -196,6 +201,10 @@ public protocol AttachmentMediaPickerContext {
var captionIsAboveMedia: Signal<Bool, NoError> { get }
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 mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
@ -206,6 +215,58 @@ public protocol AttachmentMediaPickerContext {
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? {
return generateImage(CGSize(width: 140.0, height: 140.0), rotatedContext: { size, context in
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
if let strongSelf = self, let currentController = strongSelf.currentControllers.last {
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?
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 canMakePaidContent = false
var currentPrice: Int64?
if let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext {
captionIsAboveMedia = mediaPickerContext.captionIsAboveMedia
canMakePaidContent = mediaPickerContext.canMakePaidContent
currentPrice = mediaPickerContext.price
}
let _ = (combineLatest(
@ -1016,7 +1020,9 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
messageEffect: nil,
attachment: true,
canSendWhenOnline: sendWhenOnlineAvailable,
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? []
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
canMakePaidContent: canMakePaidContent,
currentPrice: currentPrice
)),
hasEntityKeyboard: hasEntityKeyboard,
gesture: gesture,
@ -1038,6 +1044,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
schedule: { [weak textInputPanelNode] messageEffect in
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
guard let self else {
return

View File

@ -10,23 +10,26 @@ swift_library(
"-warnings-as-errors",
],
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/AppBundle:AppBundle",
"//submodules/InstantPageUI:InstantPageUI",
"//submodules/ContextUI:ContextUI",
"//submodules/UndoUI:UndoUI",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences",
"//submodules/AppBundle",
"//submodules/InstantPageUI",
"//submodules/ContextUI",
"//submodules/UndoUI",
"//submodules/TranslateUI",
"//submodules/ComponentFlow:ComponentFlow",
"//submodules/Components/ViewControllerComponent:ViewControllerComponent",
"//submodules/Components/MultilineTextComponent:MultilineTextComponent",
"//submodules/Components/BundleIconComponent:BundleIconComponent",
"//submodules/Components/BlurredBackgroundComponent:BlurredBackgroundComponent",
"//submodules/TelegramUI/Components/MinimizedContainer",
"//submodules/Pasteboard",
"//submodules/SaveToCameraRoll",
],
visibility = [
"//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
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 expandedHeight = context.component.height
@ -202,8 +202,8 @@ final class BrowserNavigationBarComponent: CombinedComponent {
centerLeftInset += item.size.width + 8.0
}
var centerRightInset = sideInset
var rightItemX = context.availableSize.width - sideInset
var centerRightInset = sideInset - 5.0
var rightItemX = context.availableSize.width - (sideInset - 5.0)
for item in rightItemList.reversed() {
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))

View File

@ -2,6 +2,7 @@ import Foundation
import UIKit
import SwiftSignalKit
import Display
import TelegramCore
import TelegramPresentationData
import ComponentFlow
import ViewControllerComponent
@ -14,6 +15,7 @@ import TelegramUIPreferences
import OpenInExternalAppUI
import MultilineTextComponent
import MinimizedContainer
import InstantPageUI
private let settingsTag = GenericComponentViewTag()
@ -72,8 +74,8 @@ private final class BrowserScreenComponent: CombinedComponent {
let performAction = context.component.performAction
let navigationContent: AnyComponentWithIdentity<Empty>?
let navigationLeftItems: [AnyComponentWithIdentity<Empty>]
let navigationRightItems: [AnyComponentWithIdentity<Empty>]
var navigationLeftItems: [AnyComponentWithIdentity<Empty>]
var navigationRightItems: [AnyComponentWithIdentity<Empty>]
if context.component.presentationState.isSearching {
navigationContent = AnyComponentWithIdentity(
id: "search",
@ -113,23 +115,6 @@ private final class BrowserScreenComponent: CombinedComponent {
let isLoading = (context.component.contentState?.estimatedProgress ?? 1.0) < 1.0
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(
id: "settings",
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
@ -303,6 +310,8 @@ public class BrowserScreen: ViewController, MinimizableController {
switch controller.subject {
case let .webPage(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
@ -717,6 +726,7 @@ public class BrowserScreen: ViewController, MinimizableController {
public enum Subject {
case webPage(url: String)
case instantPage(webPage: TelegramMediaWebpage, sourceLocation: InstantPageSourceLocation)
}
private let context: AccountContext
@ -754,6 +764,7 @@ public class BrowserScreen: ViewController, MinimizableController {
}
public var isMinimized = false
public var isMinimizable = true
}
private final class BrowserReferenceContentSource: ContextReferenceContentSource {

View File

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

View File

@ -67,6 +67,7 @@ final class ChatSendMessageContextScreenComponent: Component {
let completion: () -> Void
let sendMessage: (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void
let schedule: (ChatSendMessageActionSheetController.SendParameters?) -> Void
let editPrice: (Int64) -> Void
let openPremiumPaywall: (ViewController) -> Void
let reactionItems: [ReactionItem]?
let availableMessageEffects: AvailableMessageEffects?
@ -87,6 +88,7 @@ final class ChatSendMessageContextScreenComponent: Component {
completion: @escaping () -> Void,
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void,
schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void,
editPrice: @escaping (Int64) -> Void,
openPremiumPaywall: @escaping (ViewController) -> Void,
reactionItems: [ReactionItem]?,
availableMessageEffects: AvailableMessageEffects?,
@ -106,6 +108,7 @@ final class ChatSendMessageContextScreenComponent: Component {
self.completion = completion
self.sendMessage = sendMessage
self.schedule = schedule
self.editPrice = editPrice
self.openPremiumPaywall = openPremiumPaywall
self.reactionItems = reactionItems
self.availableMessageEffects = availableMessageEffects
@ -437,6 +440,8 @@ final class ChatSendMessageContextScreenComponent: Component {
var reminders = false
var isSecret = false
var canSchedule = false
var canMakePaidContent = false
var currentPrice: Int64?
switch component.params {
case let .sendMessage(sendMessage):
if let peerId = component.peerId {
@ -447,6 +452,8 @@ final class ChatSendMessageContextScreenComponent: Component {
if sendMessage.isScheduledMessages {
canSchedule = false
}
canMakePaidContent = sendMessage.canMakePaidContent
currentPrice = sendMessage.currentPrice
case .editMessage:
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:
items.append(.action(ContextMenuActionItem(
id: AnyHashable("silent"),
@ -1385,6 +1424,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
completion: @escaping () -> Void,
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.SendParameters?) -> Void,
schedule: @escaping (ChatSendMessageActionSheetController.SendParameters?) -> Void,
editPrice: @escaping (Int64) -> Void,
openPremiumPaywall: @escaping (ViewController) -> Void,
reactionItems: [ReactionItem]?,
availableMessageEffects: AvailableMessageEffects?,
@ -1409,6 +1449,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
completion: completion,
sendMessage: sendMessage,
schedule: schedule,
editPrice: editPrice,
openPremiumPaywall: openPremiumPaywall,
reactionItems: reactionItems,
availableMessageEffects: availableMessageEffects,

View File

@ -532,44 +532,7 @@ public final class ComposedPoll {
}
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 minimizedBounds: CGRect? { get }
var isMinimized: Bool { get set }
var isMinimizable: Bool { get }
func makeContentSnapshotView() -> UIView?
func shouldDismissImmediately() -> Bool
}
public extension MinimizableController {
@ -41,7 +43,15 @@ public extension MinimizableController {
return false
}
var isMinimizable: Bool {
return false
}
func makeContentSnapshotView() -> UIView? {
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 {
currentExpandedDetails[index] = expanded
self.currentExpandedDetails = currentExpandedDetails
@ -353,7 +353,7 @@ public final class InstantPageContentNode : ASDisplayNode {
return contentOffset
}
func nodeForDetailsItem(_ item: InstantPageDetailsItem) -> InstantPageDetailsNode? {
public func nodeForDetailsItem(_ item: InstantPageDetailsItem) -> InstantPageDetailsNode? {
for (_, itemNode) in self.visibleItemsWithNodes {
if let detailsNode = itemNode as? InstantPageDetailsNode, detailsNode.item === item {
return detailsNode

View File

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

View File

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

View File

@ -50,11 +50,11 @@ public final class InstantPageScrollableContentNode: ASDisplayNode {
}
}
final class InstantPageScrollableNode: ASScrollNode, InstantPageNode {
let item: InstantPageScrollableItem
public final class InstantPageScrollableNode: ASScrollNode, InstantPageNode {
public let item: InstantPageScrollableItem
let contentNode: InstantPageScrollableContentNode
var contentOffset: CGPoint {
public var contentOffset: CGPoint {
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
}
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 opaqueBackground: Bool
public let medias: [InstantPageMedia] = []
let anchors: [String: (Int, Bool)]
public let anchors: [String: (Int, Bool)]
public let wantsNode: Bool = false
public let separatesTiles: Bool = false
public var selectable: Bool = true

View File

@ -84,32 +84,32 @@ public struct InstantPageTextCategories {
}
public final class InstantPageTheme {
let type: InstantPageThemeType
let pageBackgroundColor: UIColor
public let type: InstantPageThemeType
public let pageBackgroundColor: UIColor
let textCategories: InstantPageTextCategories
let serif: Bool
public let textCategories: InstantPageTextCategories
public let serif: Bool
let codeBlockBackgroundColor: UIColor
public let codeBlockBackgroundColor: UIColor
let linkColor: UIColor
let textHighlightColor: UIColor
let linkHighlightColor: UIColor
let markerColor: UIColor
public let linkColor: UIColor
public let textHighlightColor: UIColor
public let linkHighlightColor: UIColor
public let markerColor: UIColor
let panelBackgroundColor: UIColor
let panelHighlightedBackgroundColor: UIColor
let panelPrimaryColor: UIColor
let panelSecondaryColor: UIColor
let panelAccentColor: UIColor
public let panelBackgroundColor: UIColor
public let panelHighlightedBackgroundColor: UIColor
public let panelPrimaryColor: UIColor
public let panelSecondaryColor: UIColor
public let panelAccentColor: UIColor
let tableBorderColor: UIColor
let tableHeaderColor: UIColor
let controlColor: UIColor
public let tableBorderColor: UIColor
public let tableHeaderColor: 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) {
self.type = type
@ -308,7 +308,7 @@ func instantPageThemeTypeForSettingsAndTime(themeSettings: PresentationThemeSett
return (settings.themeType, false)
}
func instantPageThemeForType(_ type: InstantPageThemeType, settings: InstantPagePresentationSettings) -> InstantPageTheme {
public func instantPageThemeForType(_ type: InstantPageThemeType, settings: InstantPagePresentationSettings) -> InstantPageTheme {
switch type {
case .light:
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 {
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(

View File

@ -188,7 +188,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
private let bannedSendPhotos: (Int32, Bool)?
private let bannedSendVideos: (Int32, Bool)?
private let canBoostToUnrestrict: Bool
private let paidMediaAllowed: Bool
fileprivate let paidMediaAllowed: Bool
private let subject: Subject
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) {
self.selectionCount = count
@ -2667,6 +2667,45 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
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> {
return Signal { [weak self] subscriber in
guard let interaction = self?.controller?.interaction else {

View File

@ -1516,24 +1516,30 @@ private func monetizationEntries(
starsTransactionsInfo: StarsTransactionsContext.State,
adsRestricted: Bool,
premiumConfiguration: PremiumConfiguration,
monetizationConfiguration: MonetizationConfiguration
monetizationConfiguration: MonetizationConfiguration,
canViewRevenue: Bool,
canViewStarsRevenue: Bool
) -> [StatsEntry] {
var entries: [StatsEntry] = []
entries.append(.adsHeader(presentationData.theme, presentationData.strings.Monetization_Header))
if !data.topHoursGraph.isEmpty {
entries.append(.adsImpressionsTitle(presentationData.theme, presentationData.strings.Monetization_ImpressionsTitle))
entries.append(.adsImpressionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.topHoursGraph, .hourlyStep))
if canViewRevenue {
if !data.topHoursGraph.isEmpty {
entries.append(.adsImpressionsTitle(presentationData.theme, presentationData.strings.Monetization_ImpressionsTitle))
entries.append(.adsImpressionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.topHoursGraph, .hourlyStep))
}
if !data.revenueGraph.isEmpty {
entries.append(.adsTonRevenueTitle(presentationData.theme, presentationData.strings.Monetization_AdRevenueTitle))
entries.append(.adsTonRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.revenueGraph, .currency, data.usdRate))
}
}
if !data.revenueGraph.isEmpty {
entries.append(.adsTonRevenueTitle(presentationData.theme, presentationData.strings.Monetization_AdRevenueTitle))
entries.append(.adsTonRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.revenueGraph, .currency, data.usdRate))
}
if let starsData, !starsData.revenueGraph.isEmpty {
entries.append(.adsStarsRevenueTitle(presentationData.theme, presentationData.strings.Monetization_StarsRevenueTitle))
entries.append(.adsStarsRevenueGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, starsData.revenueGraph, .stars, starsData.usdRate))
if canViewStarsRevenue {
if let starsData, !starsData.revenueGraph.isEmpty {
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(.adsProceedsTitle(presentationData.theme, presentationData.strings.Monetization_OverviewTitle))
@ -1543,40 +1549,45 @@ private func monetizationEntries(
if let peer, case let .channel(channel) = peer, channel.flags.contains(.isCreator) {
isCreator = true
}
entries.append(.adsTonBalanceTitle(presentationData.theme, presentationData.strings.Monetization_TonBalanceTitle))
entries.append(.adsTonBalance(presentationData.theme, data, isCreator && data.balances.availableBalance > 0, monetizationConfiguration.withdrawalAvailable))
if isCreator {
let withdrawalInfoText: String
if data.balances.availableBalance == 0 {
withdrawalInfoText = presentationData.strings.Monetization_Balance_ZeroInfo
} else if monetizationConfiguration.withdrawalAvailable {
withdrawalInfoText = presentationData.strings.Monetization_Balance_AvailableInfo
} else {
withdrawalInfoText = presentationData.strings.Monetization_Balance_ComingLaterInfo
if canViewRevenue {
entries.append(.adsTonBalanceTitle(presentationData.theme, presentationData.strings.Monetization_TonBalanceTitle))
entries.append(.adsTonBalance(presentationData.theme, data, isCreator && data.balances.availableBalance > 0, monetizationConfiguration.withdrawalAvailable))
if isCreator {
let withdrawalInfoText: String
if data.balances.availableBalance == 0 {
withdrawalInfoText = presentationData.strings.Monetization_Balance_ZeroInfo
} else if monetizationConfiguration.withdrawalAvailable {
withdrawalInfoText = presentationData.strings.Monetization_Balance_AvailableInfo
} else {
withdrawalInfoText = presentationData.strings.Monetization_Balance_ComingLaterInfo
}
entries.append(.adsTonBalanceInfo(presentationData.theme, withdrawalInfoText))
}
entries.append(.adsTonBalanceInfo(presentationData.theme, withdrawalInfoText))
}
if let starsData, starsData.balances.overallRevenue > 0 {
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(.adsStarsBalanceInfo(presentationData.theme, presentationData.strings.Monetization_Balance_StarsInfo))
if canViewStarsRevenue {
if let starsData, starsData.balances.overallRevenue > 0 {
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(.adsStarsBalanceInfo(presentationData.theme, presentationData.strings.Monetization_Balance_StarsInfo))
}
}
var addedTransactionsTabs = false
if !transactionsInfo.transactions.isEmpty && !starsTransactionsInfo.transactions.isEmpty {
if !transactionsInfo.transactions.isEmpty && !starsTransactionsInfo.transactions.isEmpty && canViewRevenue && canViewStarsRevenue {
addedTransactionsTabs = true
entries.append(.adsTransactionsTabs(presentationData.theme, presentationData.strings.Monetization_TonTransactions, presentationData.strings.Monetization_StarsTransactions, state.starsSelected))
}
var displayTonTransactions = false
if !transactionsInfo.transactions.isEmpty && (starsTransactionsInfo.transactions.isEmpty || !state.starsSelected) {
if canViewRevenue && !transactionsInfo.transactions.isEmpty && (starsTransactionsInfo.transactions.isEmpty || !state.starsSelected) {
displayTonTransactions = true
}
var displayStarsTransactions = false
if !starsTransactionsInfo.transactions.isEmpty && (transactionsInfo.transactions.isEmpty || state.starsSelected) {
if canViewStarsRevenue && !starsTransactionsInfo.transactions.isEmpty && (transactionsInfo.transactions.isEmpty || state.starsSelected) {
displayStarsTransactions = true
}
@ -1675,7 +1686,9 @@ private func channelStatsControllerEntries(
starsTransactions: StarsTransactionsContext.State,
adsRestricted: Bool,
premiumConfiguration: PremiumConfiguration,
monetizationConfiguration: MonetizationConfiguration
monetizationConfiguration: MonetizationConfiguration,
canViewRevenue: Bool,
canViewStarsRevenue: Bool
) -> [StatsEntry] {
switch state.section {
case .stats:
@ -1715,7 +1728,9 @@ private func channelStatsControllerEntries(
starsTransactionsInfo: starsTransactions,
adsRestricted: adsRestricted,
premiumConfiguration: premiumConfiguration,
monetizationConfiguration: monetizationConfiguration
monetizationConfiguration: monetizationConfiguration,
canViewRevenue: canViewRevenue,
canViewStarsRevenue: canViewStarsRevenue
)
}
}
@ -2039,7 +2054,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
)
|> deliverOnMainQueue
|> 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
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] = []
tabs.append(presentationData.strings.Stats_Statistics)
tabs.append(presentationData.strings.Stats_Boosts)
if canViewRevenue {
if canViewRevenue || canViewStarsRevenue {
tabs.append(presentationData.strings.Stats_Monetization)
}
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 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))
}

View File

@ -179,7 +179,17 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
case .text:
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingMessageIconImage : graphics.chatBubbleActionButtonOutgoingMessageIconImage
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
} else if value.lowercased().contains("?startgroup=") {
iconImage = incoming ? graphics.chatBubbleActionButtonIncomingAddToChatIconImage : graphics.chatBubbleActionButtonOutgoingAddToChatIconImage

View File

@ -697,25 +697,91 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
self.scrollView.addSubnode(itemNode)
self.itemNodes[item.id] = itemNode
}
itemNode.closeTapped = { [weak self] in
itemNode.closeTapped = { [weak self, weak itemNode] in
guard let self else {
return
}
if self.isExpanded {
var needsLayout = true
self.currentTransition = .dismiss(itemId: item.id)
self.items.removeAll(where: { $0.id == item.id })
if self.items.count == 1 {
self.isExpanded = false
self.willMaximize?()
needsLayout = false
let proceed = { [weak self] in
guard let self else {
return
}
var needsLayout = true
self.currentTransition = .dismiss(itemId: item.id)
self.items.removeAll(where: { $0.id == item.id })
if self.items.count == 1 {
self.isExpanded = false
self.willMaximize?()
needsLayout = false
}
if needsLayout {
self.requestUpdate(transition: .animated(duration: 0.4, curve: .spring))
}
}
if needsLayout {
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 {
self.navigationController?.dismissMinimizedControllers(animated: true)
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 {
self.navigationController?.dismissMinimizedControllers(animated: true)
}
}
}
}
itemNode.tapped = { [weak self, weak itemNode] in

View File

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

View File

@ -26,30 +26,7 @@ public class PremiumGiftAttachmentScreen: PremiumGiftScreen, AttachmentContainab
private final class PremiumGiftContext: AttachmentMediaPickerContext {
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> {
return self.controller?.mainButtonStatePromise.get() ?? .single(nil)
}
@ -57,15 +34,6 @@ private final class PremiumGiftContext: AttachmentMediaPickerContext {
init(controller: PremiumGiftScreen) {
self.controller = controller
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
self.controller?.mainButtonPressed()

View File

@ -355,29 +355,6 @@ public final class ThemeColorsGridController: ViewController, AttachmentContaina
private final class ThemeColorsGridContext: AttachmentMediaPickerContext {
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> {
return .single(self.controller?.mainButtonState)
}
@ -386,15 +363,6 @@ private final class ThemeColorsGridContext: AttachmentMediaPickerContext {
self.controller = controller
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
self.controller?.mainButtonPressed()
}

View File

@ -164,44 +164,6 @@ private func attachmentFileControllerEntries(presentationData: PresentationData,
}
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 {

View File

@ -78,7 +78,6 @@ public extension ChatControllerImpl {
if source == .menu {
self.updateChatPresentationInterfaceState(interactive: false) { state in
return state.updatedForceInputCommandsHidden(true)
// return state.updatedShowWebView(true).updatedForceInputCommandsHidden(true)
}
if let navigationController = self.navigationController as? NavigationController, let minimizedContainer = navigationController.minimizedContainer {
@ -199,7 +198,7 @@ public extension ChatControllerImpl {
}
}))
} 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 {
updateProgress()
})
@ -208,7 +207,7 @@ public extension ChatControllerImpl {
return
}
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
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
}, completion: { [weak self] in

View File

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

View File

@ -453,29 +453,6 @@ final class ContactsPickerContext: AttachmentMediaPickerContext {
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)
}
init(controller: ContactSelectionControllerImpl) {
self.controller = controller

View File

@ -24,6 +24,7 @@ import WebsiteType
import GalleryData
import StoryContainerScreen
import WallpaperGalleryScreen
import BrowserUI
func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
var story: TelegramMediaStory?
@ -373,7 +374,13 @@ func openChatInstantPageImpl(context: AccountContext, message: Message, sourcePe
if let (webpage, anchor) = instantPageAndAnchor(message: message) {
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)
}
}

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) {
self.interaction = interaction
}
@ -624,8 +605,4 @@ public class WebSearchPickerContext: AttachmentMediaPickerContext {
public func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
self.interaction?.schedule(parameters)
}
public func mainButtonAction() {
}
}

View File

@ -184,6 +184,7 @@ public class WebAppCancelButtonNode: ASDisplayNode {
public struct WebAppParameters {
public enum Source {
case generic
case button
case menu
case attachMenu
case inline
@ -1211,6 +1212,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
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:
break
}
@ -1949,7 +1954,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
switch self.source {
case .generic, .settings:
completion()
case .inline, .attachMenu, .menu, .simple:
case .button, .inline, .attachMenu, .menu, .simple:
let _ = (self.context.engine.data.get(
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
}
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 {
return self.controllerNode.canMinimize
}
@ -2191,25 +2214,6 @@ public final class WebAppController: ViewController, AttachmentContainable {
final class WebAppPickerContext: AttachmentMediaPickerContext {
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> {
return self.controller?.controllerNode.loadingProgressPromise.get() ?? .single(nil)
}
@ -2222,15 +2226,6 @@ final class WebAppPickerContext: AttachmentMediaPickerContext {
self.controller = controller
}
func setCaption(_ caption: NSAttributedString) {
}
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
}
func mainButtonAction() {
self.controller?.controllerNode.mainButtonPressed()
}