Various fixes

This commit is contained in:
Ilya Laktyushin 2024-07-10 13:58:29 +04:00
parent ec074f650d
commit 9ba7e6e735
11 changed files with 211 additions and 70 deletions

View File

@ -12487,3 +12487,6 @@ Sorry for the inconvenience.";
"ChatList.DeleteForMe" = "Delete for me"; "ChatList.DeleteForMe" = "Delete for me";
"ChatList.DeleteForAllWhenPossible" = "Delete from both sides where possible"; "ChatList.DeleteForAllWhenPossible" = "Delete from both sides where possible";
"ChatList.DeleteForAll" = "Delete from both sides"; "ChatList.DeleteForAll" = "Delete from both sides";
"WebApp.Miniapp" = "miniapp";
"WebApp.Share" = "Share";

View File

@ -153,10 +153,9 @@ class BarsComponentController: GeneralChartComponentController {
func verticalLimitsLabels(verticalRange: ClosedRange<CGFloat>, secondary: Bool) -> (ClosedRange<CGFloat>, [LinesChartLabel]) { func verticalLimitsLabels(verticalRange: ClosedRange<CGFloat>, secondary: Bool) -> (ClosedRange<CGFloat>, [LinesChartLabel]) {
var (range, labels) = super.verticalLimitsLabels(verticalRange: verticalRange) var (range, labels) = super.verticalLimitsLabels(verticalRange: verticalRange)
if secondary { if secondary {
let allowedChars = "0123456789\(self.verticalLimitsNumberFormatter.decimalSeparator ?? ".")"
var updatedLabels: [LinesChartLabel] = [] var updatedLabels: [LinesChartLabel] = []
for label in labels { for label in labels {
let convertedValue = (Double(label.text.filter(allowedChars.contains)) ?? 0.0) * self.conversionRate let convertedValue = (self.verticalLimitsNumberFormatter.number(from: label.text) as? Double ?? 0.0) * self.conversionRate
let text: String let text: String
if convertedValue > 1.0 { if convertedValue > 1.0 {
text = String(format: "%0.1f", convertedValue) text = String(format: "%0.1f", convertedValue)

View File

@ -14,9 +14,12 @@ swift_library(
"//submodules/AsyncDisplayKit", "//submodules/AsyncDisplayKit",
"//submodules/Display", "//submodules/Display",
"//submodules/TelegramPresentationData", "//submodules/TelegramPresentationData",
"//submodules/ComponentFlow",
"//submodules/AccountContext", "//submodules/AccountContext",
"//submodules/UIKitRuntimeUtils", "//submodules/UIKitRuntimeUtils",
"//submodules/ComponentFlow",
"//submodules/Components/MultilineTextComponent",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramUI/Components/PlainButtonComponent",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -12,11 +12,11 @@ private let minimizedNavigationHeight: CGFloat = 44.0
private let minimizedTopMargin: CGFloat = 3.0 private let minimizedTopMargin: CGFloat = 3.0
final class ScrollViewImpl: UIScrollView { final class ScrollViewImpl: UIScrollView {
var passthrough = false var shouldPassthrough: () -> Bool = { return false }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let result = super.hitTest(point, with: event) let result = super.hitTest(point, with: event)
if result === self && self.passthrough { if result === self && self.shouldPassthrough() {
return nil return nil
} }
return result return result
@ -36,6 +36,13 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
} }
} }
final class SnapshotContainerView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
self.removeFromSuperview()
return nil
}
}
final class ItemNode: ASDisplayNode { final class ItemNode: ASDisplayNode {
var theme: PresentationTheme { var theme: PresentationTheme {
didSet { didSet {
@ -54,7 +61,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
private let shadowNode: ASImageNode private let shadowNode: ASImageNode
private var controllerView: UIView? private var controllerView: UIView?
fileprivate let snapshotContainerView = UIView() fileprivate let snapshotContainerView = SnapshotContainerView()
fileprivate var snapshotView: UIView? fileprivate var snapshotView: UIView?
fileprivate var blurredSnapshotView: UIView? fileprivate var blurredSnapshotView: UIView?
@ -372,6 +379,12 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
self.scrollView.alwaysBounceVertical = true self.scrollView.alwaysBounceVertical = true
self.scrollView.showsVerticalScrollIndicator = false self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.showsHorizontalScrollIndicator = false self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.shouldPassthrough = { [weak self] in
guard let self else {
return true
}
return !self.isExpanded
}
let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))) let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
panGestureRecognizer.delegate = self.wrappedGestureRecognizerDelegate panGestureRecognizer.delegate = self.wrappedGestureRecognizerDelegate
@ -648,6 +661,12 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
}) })
]) ])
]) ])
actionSheet.dismissed = { cancelled in
guard cancelled else {
return
}
completion(false)
}
self.navigationController?.presentOverlay(controller: actionSheet, inGlobal: false, blockInteraction: false) self.navigationController?.presentOverlay(controller: actionSheet, inGlobal: false, blockInteraction: false)
} }
@ -926,7 +945,6 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
if self.scrollView.frame != bounds { if self.scrollView.frame != bounds {
self.scrollView.frame = bounds self.scrollView.frame = bounds
} }
self.scrollView.passthrough = !self.isExpanded
self.scrollView.isScrollEnabled = self.isExpanded self.scrollView.isScrollEnabled = self.isExpanded
self.expandedTapGestureRecoginzer?.isEnabled = self.isExpanded self.expandedTapGestureRecoginzer?.isEnabled = self.isExpanded
@ -1010,10 +1028,11 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
if let _ = itemNode.snapshotView { if let _ = itemNode.snapshotView {
let snapshotContainerView = itemNode.snapshotContainerView let snapshotContainerView = itemNode.snapshotContainerView
snapshotContainerView.isUserInteractionEnabled = true
snapshotContainerView.layer.allowsGroupOpacity = true snapshotContainerView.layer.allowsGroupOpacity = true
snapshotContainerView.center = CGPoint(x: itemNode.item.controller.displayNode.view.bounds.width / 2.0, y: snapshotContainerView.bounds.height / 2.0) snapshotContainerView.center = CGPoint(x: itemNode.item.controller.displayNode.view.bounds.width / 2.0, y: snapshotContainerView.bounds.height / 2.0)
itemNode.item.controller.displayNode.view.addSubview(snapshotContainerView) itemNode.item.controller.displayNode.view.addSubview(snapshotContainerView)
Queue.mainQueue().after(0.15, { Queue.mainQueue().after(0.35, {
snapshotContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in snapshotContainerView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
snapshotContainerView.removeFromSuperview() snapshotContainerView.removeFromSuperview()
}) })

View File

@ -4,40 +4,62 @@ import AsyncDisplayKit
import Display import Display
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import ComponentFlow
import MultilineTextComponent
import BundleIconComponent
import PlainButtonComponent
private final class WeakController {
private weak var _value: MinimizableController?
public var value: MinimizableController? {
return self._value
}
public init(_ value: MinimizableController) {
self._value = value
}
}
final class MinimizedHeaderNode: ASDisplayNode { final class MinimizedHeaderNode: ASDisplayNode {
var theme: NavigationControllerTheme { var theme: NavigationControllerTheme {
didSet { didSet {
self.minimizedBackgroundNode.backgroundColor = self.theme.navigationBar.opaqueBackgroundColor self.backgroundView.backgroundColor = self.theme.navigationBar.opaqueBackgroundColor
self.minimizedCloseButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Instant View/Close"), color: self.theme.navigationBar.primaryTextColor), for: .normal)
} }
} }
let strings: PresentationStrings let strings: PresentationStrings
private let minimizedBackgroundNode: ASDisplayNode private let backgroundView = UIView()
private let minimizedTitleNode: ImmediateTextNode private var iconView = UIImageView()
private let minimizedCloseButton: HighlightableButtonNode private let titleLabel = ComponentView<Empty>()
private var minimizedTitleDisposable: Disposable? private let closeButton = ComponentView<Empty>()
private var titleDisposable: Disposable?
private var _controllers: [Weak<ViewController>] = [] private var _controllers: [WeakController] = []
var controllers: [ViewController] { var controllers: [MinimizableController] {
get { get {
return self._controllers.compactMap { $0.value } return self._controllers.compactMap { $0.value }
} }
set { set {
if !newValue.isEmpty { if !newValue.isEmpty {
if newValue.count != self.controllers.count { if self.controllers.count == 1, let icon = self.controllers.first?.minimizedIcon {
self._controllers = newValue.map { Weak($0) } self.icon = icon
} else {
self.icon = nil
}
self.minimizedTitleDisposable?.dispose() if newValue.count != self.controllers.count {
self.minimizedTitleDisposable = nil self._controllers = newValue.map { WeakController($0) }
self.titleDisposable?.dispose()
self.titleDisposable = nil
var signals: [Signal<String?, NoError>] = [] var signals: [Signal<String?, NoError>] = []
for controller in newValue { for controller in newValue {
signals.append(controller.titleSignal) signals.append(controller.titleSignal)
} }
self.minimizedTitleDisposable = (combineLatest(signals) self.titleDisposable = (combineLatest(signals)
|> deliverOnMainQueue).start(next: { [weak self] titles in |> deliverOnMainQueue).start(next: { [weak self] titles in
guard let self else { guard let self else {
return return
@ -54,8 +76,19 @@ final class MinimizedHeaderNode: ASDisplayNode {
}) })
} }
} else { } else {
self.minimizedTitleDisposable?.dispose() self.icon = nil
self.minimizedTitleDisposable = nil
self.titleDisposable?.dispose()
self.titleDisposable = nil
}
}
}
var icon: UIImage? {
didSet {
self.iconView.image = self.icon
if let (size, insets, isExpanded) = self.validLayout {
self.update(size: size, insets: insets, isExpanded: isExpanded, transition: .immediate)
} }
} }
} }
@ -77,40 +110,30 @@ final class MinimizedHeaderNode: ASDisplayNode {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.minimizedBackgroundNode = ASDisplayNode() self.backgroundView.clipsToBounds = true
self.minimizedBackgroundNode.cornerRadius = 10.0 self.backgroundView.backgroundColor = theme.navigationBar.opaqueBackgroundColor
self.minimizedBackgroundNode.clipsToBounds = true self.backgroundView.layer.cornerRadius = 10.0
self.minimizedBackgroundNode.backgroundColor = theme.navigationBar.opaqueBackgroundColor
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
self.minimizedBackgroundNode.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] self.backgroundView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
} }
self.minimizedTitleNode = ImmediateTextNode() self.iconView.clipsToBounds = true
self.iconView.layer.cornerRadius = 2.5
self.minimizedCloseButton = HighlightableButtonNode()
self.minimizedCloseButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Instant View/Close"), color: self.theme.navigationBar.primaryTextColor), for: .normal)
super.init() super.init()
self.clipsToBounds = true self.clipsToBounds = true
self.addSubnode(self.minimizedBackgroundNode) self.view.addSubview(self.backgroundView)
self.minimizedBackgroundNode.addSubnode(self.minimizedTitleNode) self.backgroundView.addSubview(self.iconView)
self.minimizedBackgroundNode.addSubnode(self.minimizedCloseButton)
self.minimizedCloseButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: .touchUpInside) applySmoothRoundedCorners(self.backgroundView.layer)
applySmoothRoundedCorners(self.minimizedBackgroundNode.layer)
} }
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
self.minimizedBackgroundNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.maximizeTapGesture(_:)))) self.backgroundView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.maximizeTapGesture(_:))))
}
@objc private func closePressed() {
self.requestClose()
} }
@objc private func maximizeTapGesture(_ recognizer: UITapGestureRecognizer) { @objc private func maximizeTapGesture(_ recognizer: UITapGestureRecognizer) {
@ -128,19 +151,74 @@ final class MinimizedHeaderNode: ASDisplayNode {
self.validLayout = (size, insets, isExpanded) self.validLayout = (size, insets, isExpanded)
let headerHeight: CGFloat = 44.0 let headerHeight: CGFloat = 44.0
let titleSpacing: CGFloat = 4.0
var titleSideInset: CGFloat = 56.0 var titleSideInset: CGFloat = 56.0
if !isExpanded { if !isExpanded {
titleSideInset += insets.left titleSideInset += insets.left
} }
self.minimizedTitleNode.attributedText = NSAttributedString(string: self.title ?? "", font: Font.bold(17.0), textColor: self.theme.navigationBar.primaryTextColor) let iconSize = CGSize(width: 20.0, height: 20.0)
let titleSize = self.minimizedTitleNode.updateLayout(CGSize(width: size.width - titleSideInset * 2.0, height: headerHeight)) let titleSize = self.titleLabel.update(
let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: floorToScreenPixels((headerHeight - titleSize.height) / 2.0)), size: titleSize) transition: .immediate,
self.minimizedTitleNode.bounds = CGRect(origin: .zero, size: titleFrame.size) component: AnyComponent(
transition.updatePosition(node: self.minimizedTitleNode, position: titleFrame.center) MultilineTextComponent(text: .plain(NSAttributedString(string: self.title ?? "", font: Font.bold(17.0), textColor: self.theme.navigationBar.primaryTextColor)), horizontalAlignment: .center, maximumNumberOfLines: 1)
transition.updateFrame(node: self.minimizedCloseButton, frame: CGRect(origin: CGPoint(x: isExpanded ? 0.0 : insets.left, y: 0.0), size: CGSize(width: 44.0, height: 44.0))) ),
environment: {},
containerSize: CGSize(width: size.width - titleSideInset * 2.0, height: headerHeight)
)
transition.updateFrame(node: self.minimizedBackgroundNode, frame: CGRect(origin: .zero, size: CGSize(width: size.width, height: 243.0))) var totalWidth = titleSize.width
if isExpanded, let icon = self.icon {
self.iconView.image = icon
totalWidth += iconSize.width + titleSpacing
} else {
self.iconView.image = nil
}
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - totalWidth) / 2.0), y: floorToScreenPixels((headerHeight - iconSize.height) / 2.0)), size: iconSize)
transition.updateFrame(view: self.iconView, frame: iconFrame)
let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - totalWidth) / 2.0) + totalWidth - titleSize.width, y: floorToScreenPixels((headerHeight - titleSize.height) / 2.0)), size: titleSize)
if let view = self.titleLabel.view {
if view.superview == nil {
self.backgroundView.addSubview(view)
}
view.bounds = CGRect(origin: .zero, size: titleFrame.size)
transition.updatePosition(layer: view.layer, position: titleFrame.center)
}
let _ = self.closeButton.update(
transition: .immediate,
component: AnyComponent(
PlainButtonComponent(
content: AnyComponent(
BundleIconComponent(
name: "Instant View/Close",
tintColor: self.theme.navigationBar.primaryTextColor
)
),
effectAlignment: .center,
minSize: CGSize(width: 44.0, height: 44.0),
action: { [weak self] in
self?.requestClose()
},
animateScale: false
)
),
environment: {},
containerSize: CGSize(width: 44.0, height: 44.0)
)
let closeButtonFrame = CGRect(origin: CGPoint(x: isExpanded ? 0.0 : insets.left, y: 0.0), size: CGSize(width: 44.0, height: 44.0))
if let view = self.closeButton.view {
if view.superview == nil {
self.backgroundView.addSubview(view)
}
transition.updateFrame(view: view, frame: closeButtonFrame)
}
transition.updateFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: CGSize(width: size.width, height: 243.0)))
} }
} }

View File

@ -5282,7 +5282,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} }
let context = self.context let context = self.context
let peerId = self.peerId let peerId = self.peerId
let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings), fullSize: true) let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings), fullSize: true)
var openUrlImpl: ((String, Bool, @escaping () -> Void) -> Void)? var openUrlImpl: ((String, Bool, @escaping () -> Void) -> Void)?
var presentImpl: ((ViewController, Any?) -> Void)? var presentImpl: ((ViewController, Any?) -> Void)?

View File

@ -1808,7 +1808,7 @@ final class StoryItemSetContainerSendMessage {
//TODO:gift controller //TODO:gift controller
break break
case let .app(bot): case let .app(bot):
let params = WebAppParameters(source: .attachMenu, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: true) let params = WebAppParameters(source: .attachMenu, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: true)
let theme = component.theme let theme = component.theme
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }) let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil) let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)

View File

@ -24,12 +24,15 @@ public extension ChatControllerImpl {
let botName: String let botName: String
let botAddress: String let botAddress: String
let botVerified: Bool
if case let .inline(bot) = source { if case let .inline(bot) = source {
botName = bot.compactDisplayTitle botName = bot.compactDisplayTitle
botAddress = bot.addressName ?? "" botAddress = bot.addressName ?? ""
botVerified = bot.isVerified
} else { } else {
botName = EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) botName = EnginePeer(peer).displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)
botAddress = peer.addressName ?? "" botAddress = peer.addressName ?? ""
botVerified = peer.isVerified
} }
if source == .generic { if source == .generic {
@ -98,7 +101,7 @@ public extension ChatControllerImpl {
} }
var presentImpl: ((ViewController, Any?) -> Void)? var presentImpl: ((ViewController, Any?) -> Void)?
let params = WebAppParameters(source: .menu, peerId: peerId, botId: peerId, botName: botName, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize) let params = WebAppParameters(source: .menu, peerId: peerId, botId: peerId, botName: botName, botVerified: botVerified, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize)
let controller = standaloneWebAppController(context: self.context, updatedPresentationData: self.updatedPresentationData, params: params, threadId: self.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in let controller = standaloneWebAppController(context: self.context, updatedPresentationData: self.updatedPresentationData, params: params, threadId: self.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
presentImpl?(c, a) presentImpl?(c, a)
@ -145,11 +148,13 @@ public extension ChatControllerImpl {
var botId = peerId var botId = peerId
var botName = botName var botName = botName
var botAddress = "" var botAddress = ""
var botVerified = false
if case let .inline(bot) = source { if case let .inline(bot) = source {
isInline = true isInline = true
botId = bot.id botId = bot.id
botName = bot.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder) botName = bot.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)
botAddress = bot.addressName ?? "" botAddress = bot.addressName ?? ""
botVerified = bot.isVerified
} }
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestSimpleWebView(botId: botId, url: url, source: isInline ? .inline : .generic, themeParams: generateWebAppThemeParams(self.presentationData.theme)) self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestSimpleWebView(botId: botId, url: url, source: isInline ? .inline : .generic, themeParams: generateWebAppThemeParams(self.presentationData.theme))
@ -162,7 +167,7 @@ public extension ChatControllerImpl {
} }
var presentImpl: ((ViewController, Any?) -> Void)? var presentImpl: ((ViewController, Any?) -> Void)?
let context = strongSelf.context let context = strongSelf.context
let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peerId, botId: botId, botName: botName, url: result.url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize)) let params = WebAppParameters(source: isInline ? .inline : .simple, peerId: peerId, botId: botId, botName: botName, botVerified: botVerified, url: result.url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, 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
ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
presentImpl?(c, a) presentImpl?(c, a)
@ -196,7 +201,7 @@ public extension ChatControllerImpl {
} }
var presentImpl: ((ViewController, Any?) -> Void)? var presentImpl: ((ViewController, Any?) -> Void)?
let context = strongSelf.context let context = strongSelf.context
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 params = WebAppParameters(source: .button, peerId: peerId, botId: peerId, botName: botName, botVerified: botVerified, 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
ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
presentImpl?(c, a) presentImpl?(c, a)
@ -401,7 +406,7 @@ public extension ChatControllerImpl {
return return
} }
let context = strongSelf.context let context = strongSelf.context
let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, url: result.url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings), fullSize: result.flags.contains(.fullSize)) let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, botVerified: botPeer.isVerified, url: result.url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings), fullSize: result.flags.contains(.fullSize))
var presentImpl: ((ViewController, Any?) -> Void)? var presentImpl: ((ViewController, Any?) -> Void)?
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
ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in

View File

@ -615,7 +615,7 @@ extension ChatControllerImpl {
payload = botPayload payload = botPayload
fromAttachMenu = false fromAttachMenu = false
} }
let params = WebAppParameters(source: fromAttachMenu ? .attachMenu : .generic, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: false) let params = WebAppParameters(source: fromAttachMenu ? .attachMenu : .generic, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: false)
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageSubject?.messageId, threadId: strongSelf.chatLocation.threadId) let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageSubject?.messageId, threadId: strongSelf.chatLocation.threadId)
controller.openUrl = { [weak self] url, concealed, commit in controller.openUrl = { [weak self] url, concealed, commit in

View File

@ -18,7 +18,6 @@ swift_library(
"//submodules/PresentationDataUtils:PresentationDataUtils", "//submodules/PresentationDataUtils:PresentationDataUtils",
"//submodules/AccountContext:AccountContext", "//submodules/AccountContext:AccountContext",
"//submodules/AttachmentUI:AttachmentUI", "//submodules/AttachmentUI:AttachmentUI",
"//submodules/CounterControllerTitleView:CounterControllerTitleView",
"//submodules/HexColor:HexColor", "//submodules/HexColor:HexColor",
"//submodules/PhotoResources:PhotoResources", "//submodules/PhotoResources:PhotoResources",
"//submodules/ShimmerEffect:ShimmerEffect", "//submodules/ShimmerEffect:ShimmerEffect",
@ -35,7 +34,11 @@ swift_library(
"//submodules/TextFormat:TextFormat", "//submodules/TextFormat:TextFormat",
"//submodules/LocalAuth", "//submodules/LocalAuth",
"//submodules/InstantPageCache", "//submodules/InstantPageCache",
"//submodules/OpenInExternalAppUI" "//submodules/OpenInExternalAppUI",
"//submodules/ComponentFlow",
"//submodules/TelegramUI/Components/EmojiStatusComponent",
"//submodules/ShareController",
"//submodules/UndoUI",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -9,7 +9,6 @@ import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import AccountContext import AccountContext
import AttachmentUI import AttachmentUI
import CounterControllerTitleView
import ContextUI import ContextUI
import PresentationDataUtils import PresentationDataUtils
import HexColor import HexColor
@ -26,6 +25,8 @@ import InstantPageUI
import InstantPageCache import InstantPageCache
import LocalAuth import LocalAuth
import OpenInExternalAppUI import OpenInExternalAppUI
import ShareController
import UndoUI
private let durgerKingBotIds: [Int64] = [5104055776, 2200339955] private let durgerKingBotIds: [Int64] = [5104055776, 2200339955]
@ -204,6 +205,7 @@ public struct WebAppParameters {
let peerId: PeerId let peerId: PeerId
let botId: PeerId let botId: PeerId
let botName: String let botName: String
let botVerified: Bool
let url: String? let url: String?
let queryId: Int64? let queryId: Int64?
let payload: String? let payload: String?
@ -217,6 +219,7 @@ public struct WebAppParameters {
peerId: PeerId, peerId: PeerId,
botId: PeerId, botId: PeerId,
botName: String, botName: String,
botVerified: Bool,
url: String?, url: String?,
queryId: Int64?, queryId: Int64?,
payload: String?, payload: String?,
@ -229,6 +232,7 @@ public struct WebAppParameters {
self.peerId = peerId self.peerId = peerId
self.botId = botId self.botId = botId
self.botName = botName self.botName = botName
self.botVerified = botVerified
self.url = url self.url = url
self.queryId = queryId self.queryId = queryId
self.payload = payload self.payload = payload
@ -504,7 +508,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
guard let self, let parsedUrl = URL(string: result.url) else { guard let self, let parsedUrl = URL(string: result.url) else {
return return
} }
self.controller?.titleView?.title = CounterControllerTitle(title: appStart.botApp.title, counter: self.presentationData.strings.Bot_GenericBotStatus) self.controller?.titleView?.title = WebAppTitle(title: appStart.botApp.title, counter: self.presentationData.strings.WebApp_Miniapp, isVerified: controller.botVerified)
self.webView?.load(URLRequest(url: parsedUrl)) self.webView?.load(URLRequest(url: parsedUrl))
}) })
}) })
@ -1839,7 +1843,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
return self.displayNode as! Node return self.displayNode as! Node
} }
private var titleView: CounterControllerTitleView? private var titleView: WebAppTitleView?
fileprivate let cancelButtonNode: WebAppCancelButtonNode fileprivate let cancelButtonNode: WebAppCancelButtonNode
fileprivate let moreButtonNode: MoreButtonNode fileprivate let moreButtonNode: MoreButtonNode
@ -1848,6 +1852,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
private let peerId: PeerId private let peerId: PeerId
public let botId: PeerId public let botId: PeerId
private let botName: String private let botName: String
private let botVerified: Bool
private let url: String? private let url: String?
private let queryId: Int64? private let queryId: Int64?
private let payload: String? private let payload: String?
@ -1874,6 +1879,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.peerId = params.peerId self.peerId = params.peerId
self.botId = params.botId self.botId = params.botId
self.botName = params.botName self.botName = params.botName
self.botVerified = params.botVerified
self.url = params.url self.url = params.url
self.queryId = params.queryId self.queryId = params.queryId
self.payload = params.payload self.payload = params.payload
@ -1910,8 +1916,8 @@ public final class WebAppController: ViewController, AttachmentContainable {
self.navigationItem.rightBarButtonItem?.action = #selector(self.moreButtonPressed) self.navigationItem.rightBarButtonItem?.action = #selector(self.moreButtonPressed)
self.navigationItem.rightBarButtonItem?.target = self self.navigationItem.rightBarButtonItem?.target = self
let titleView = CounterControllerTitleView(theme: self.presentationData.theme) let titleView = WebAppTitleView(context: self.context, theme: self.presentationData.theme)
titleView.title = CounterControllerTitle(title: params.botName, counter: self.presentationData.strings.Bot_GenericBotStatus) titleView.title = WebAppTitle(title: params.botName, counter: self.presentationData.strings.WebApp_Miniapp, isVerified: params.botVerified)
self.navigationItem.titleView = titleView self.navigationItem.titleView = titleView
self.titleView = titleView self.titleView = titleView
@ -2020,9 +2026,12 @@ public final class WebAppController: ViewController, AttachmentContainable {
let hasSettings = self.hasSettings let hasSettings = self.hasSettings
let items = context.engine.messages.attachMenuBots() let items = combineLatest(queue: Queue.mainQueue(),
context.engine.messages.attachMenuBots(),
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.botId))
)
|> take(1) |> take(1)
|> map { [weak self] attachMenuBots -> ContextController.Items in |> map { [weak self] attachMenuBots, botPeer -> ContextController.Items in
var items: [ContextMenuItem] = [] var items: [ContextMenuItem] = []
let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) }) let attachMenuBot = attachMenuBots.first(where: { $0.peer.id == botId && !$0.flags.contains(.notActivated) })
@ -2064,6 +2073,24 @@ public final class WebAppController: ViewController, AttachmentContainable {
}))) })))
} }
if let addressName = botPeer?.addressName {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_Share, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, _ in
c?.dismiss(completion: nil)
guard let self else {
return
}
let shareController = ShareController(context: context, subject: .url("https://t.me/\(addressName)"))
shareController.actionCompleted = { [weak self] in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}
self.present(shareController, in: .window(.root))
})))
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_ReloadPage, icon: { theme in items.append(.action(ContextMenuActionItem(text: presentationData.strings.WebApp_ReloadPage, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reload"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reload"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, _ in }, action: { [weak self] c, _ in
@ -2178,8 +2205,12 @@ public final class WebAppController: ViewController, AttachmentContainable {
public var isMinimized: Bool = false { public var isMinimized: Bool = false {
didSet { didSet {
if self.isMinimized != oldValue && self.isMinimized { if self.isMinimized != oldValue {
if self.isMinimized {
self.controllerNode.webView?.hideScrollIndicators() self.controllerNode.webView?.hideScrollIndicators()
} else {
self.requestLayout(transition: .immediate)
}
} }
} }
} }