mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
32e6629538
commit
d2deea0ea2
@ -10510,11 +10510,15 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Notification.GiveawayResultsNoWinners_1" = "Due to the giveaway terms, no winners could be selected by Telegram, a gift link was forwarded to channel administrators.";
|
"Notification.GiveawayResultsNoWinners_1" = "Due to the giveaway terms, no winners could be selected by Telegram, a gift link was forwarded to channel administrators.";
|
||||||
"Notification.GiveawayResultsNoWinners_any" = "Due to the giveaway terms, no winners could be selected by Telegram, all **%@** gift links were forwarded to channel administrators.";
|
"Notification.GiveawayResultsNoWinners_any" = "Due to the giveaway terms, no winners could be selected by Telegram, all **%@** gift links were forwarded to channel administrators.";
|
||||||
|
"Notification.GiveawayResultsNoWinners.Group_1" = "Due to the giveaway terms, no winners could be selected by Telegram, a gift link was forwarded to group administrators.";
|
||||||
|
"Notification.GiveawayResultsNoWinners.Group_any" = "Due to the giveaway terms, no winners could be selected by Telegram, all **%@** gift links were forwarded to group administrators.";
|
||||||
|
|
||||||
"Notification.GiveawayResultsMixedWinners_1" = "**%@** winner of the giveaway was randomly selected by Telegram and received their gift link in a private message.";
|
"Notification.GiveawayResultsMixedWinners_1" = "**%@** winner of the giveaway was randomly selected by Telegram and received their gift link in a private message.";
|
||||||
"Notification.GiveawayResultsMixedWinners_any" = "**%@** winners of the giveaway were randomly selected by Telegram and received their gift links in private messages.";
|
"Notification.GiveawayResultsMixedWinners_any" = "**%@** winners of the giveaway were randomly selected by Telegram and received their gift links in private messages.";
|
||||||
"Notification.GiveawayResultsMixedUnclaimed_1" = "**%@** undistributed gift link was forwarded to channel administrators";
|
"Notification.GiveawayResultsMixedUnclaimed_1" = "**%@** undistributed gift link was forwarded to channel administrators";
|
||||||
"Notification.GiveawayResultsMixedUnclaimed_any" = "**%@** undistributed gift links were forwarded to channel administrators";
|
"Notification.GiveawayResultsMixedUnclaimed_any" = "**%@** undistributed gift links were forwarded to channel administrators";
|
||||||
|
"Notification.GiveawayResultsMixedUnclaimed.Group_1" = "**%@** undistributed gift link was forwarded to group administrators";
|
||||||
|
"Notification.GiveawayResultsMixedUnclaimed.Group_any" = "**%@** undistributed gift links were forwarded to group administrators";
|
||||||
|
|
||||||
"Chat.Giveaway.DeleteConfirmation.Title" = "Do you want to delete the Giveaway Announcement?";
|
"Chat.Giveaway.DeleteConfirmation.Title" = "Do you want to delete the Giveaway Announcement?";
|
||||||
"Chat.Giveaway.DeleteConfirmation.Text" = "Deleting this message won't cancel the giveaway - the winners will still be selected on **%@**.\n\nOnce deleted, the Giveaway Announcement cannot be recovered.";
|
"Chat.Giveaway.DeleteConfirmation.Text" = "Deleting this message won't cancel the giveaway - the winners will still be selected on **%@**.\n\nOnce deleted, the Giveaway Announcement cannot be recovered.";
|
||||||
@ -12876,6 +12880,11 @@ Sorry for the inconvenience.";
|
|||||||
"BoostGift.Stars.Info" = "Choose how many stars to give away and how many boosts to receive for 1 year.";
|
"BoostGift.Stars.Info" = "Choose how many stars to give away and how many boosts to receive for 1 year.";
|
||||||
"BoostGift.AdditionalPrizesInfoStarsOff" = "Turn this on if you want to give the winners your own prizes in addition to Stars.";
|
"BoostGift.AdditionalPrizesInfoStarsOff" = "Turn this on if you want to give the winners your own prizes in addition to Stars.";
|
||||||
|
|
||||||
|
"BoostGift.AdditionalPrizesInfoStars_1" = "**%@** Star";
|
||||||
|
"BoostGift.AdditionalPrizesInfoStars_any" = "**%@** Stars";
|
||||||
|
"BoostGift.AdditionalPrizesInfoStarsOn" = "All prizes: %1$@%2$@.";
|
||||||
|
"BoostGift.AdditionalPrizesInfoStarsAndOther" = " and **%1$@** %2$@";
|
||||||
|
|
||||||
"BoostGift.Stars.Winners" = "NUMBER OF WINNERS";
|
"BoostGift.Stars.Winners" = "NUMBER OF WINNERS";
|
||||||
"BoostGift.Stars.WinnersInfo" = "Choose how many winners you want to distribute stars among.";
|
"BoostGift.Stars.WinnersInfo" = "Choose how many winners you want to distribute stars among.";
|
||||||
|
|
||||||
@ -12915,3 +12924,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"Premium.BoostByGiveawayDescription" = "Get more boosts and subscribers for your channel by giving away prizes. [Get boosts >]()";
|
"Premium.BoostByGiveawayDescription" = "Get more boosts and subscribers for your channel by giving away prizes. [Get boosts >]()";
|
||||||
"Premium.Group.BoostByGiveawayDescription" = "Get more boosts and members for your group by giving away prizes. [Get boosts >]()";
|
"Premium.Group.BoostByGiveawayDescription" = "Get more boosts and members for your group by giving away prizes. [Get boosts >]()";
|
||||||
|
|
||||||
|
"Notification.StarsGiveawayResultsNoWinners" = "Due to the giveaway terms, no winners could be selected by Telegram, all stars were credited to channel administrators.";
|
||||||
|
"Notification.StarsGiveawayResultsNoWinners.Group" = "Due to the giveaway terms, no winners could be selected by Telegram, all stars were credited to group administrators.";
|
||||||
|
@ -213,6 +213,8 @@ public protocol AttachmentMediaPickerContext {
|
|||||||
var price: Int64? { get }
|
var price: Int64? { get }
|
||||||
func setPrice(_ price: Int64) -> Void
|
func setPrice(_ price: Int64) -> Void
|
||||||
|
|
||||||
|
var hasTimers: Bool { get }
|
||||||
|
|
||||||
var loadingProgress: Signal<CGFloat?, NoError> { get }
|
var loadingProgress: Signal<CGFloat?, NoError> { get }
|
||||||
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||||
var secondaryButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
var secondaryButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||||
@ -257,6 +259,10 @@ public extension AttachmentMediaPickerContext {
|
|||||||
func setPrice(_ price: Int64) -> Void {
|
func setPrice(_ price: Int64) -> Void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasTimers: Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var loadingProgress: Signal<CGFloat?, NoError> {
|
var loadingProgress: Signal<CGFloat?, NoError> {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
|
@ -1004,10 +1004,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
var captionIsAboveMedia: Signal<Bool, NoError> = .single(false)
|
var captionIsAboveMedia: Signal<Bool, NoError> = .single(false)
|
||||||
var canMakePaidContent = false
|
var canMakePaidContent = false
|
||||||
var currentPrice: Int64?
|
var currentPrice: Int64?
|
||||||
|
var hasTimers = false
|
||||||
if let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext {
|
if let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext {
|
||||||
captionIsAboveMedia = mediaPickerContext.captionIsAboveMedia
|
captionIsAboveMedia = mediaPickerContext.captionIsAboveMedia
|
||||||
canMakePaidContent = mediaPickerContext.canMakePaidContent
|
canMakePaidContent = mediaPickerContext.canMakePaidContent
|
||||||
currentPrice = mediaPickerContext.price
|
currentPrice = mediaPickerContext.price
|
||||||
|
hasTimers = mediaPickerContext.hasTimers
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = (combineLatest(
|
let _ = (combineLatest(
|
||||||
@ -1039,7 +1041,8 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
canSendWhenOnline: sendWhenOnlineAvailable,
|
canSendWhenOnline: sendWhenOnlineAvailable,
|
||||||
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
||||||
canMakePaidContent: canMakePaidContent,
|
canMakePaidContent: canMakePaidContent,
|
||||||
currentPrice: currentPrice
|
currentPrice: currentPrice,
|
||||||
|
hasTimers: hasTimers
|
||||||
)),
|
)),
|
||||||
hasEntityKeyboard: hasEntityKeyboard,
|
hasEntityKeyboard: hasEntityKeyboard,
|
||||||
gesture: gesture,
|
gesture: gesture,
|
||||||
|
@ -92,6 +92,17 @@ final class BrowserDocumentContent: UIView, BrowserContent, WKNavigationDelegate
|
|||||||
self.webView.underPageBackgroundColor = presentationData.theme.list.plainBackgroundColor
|
self.webView.underPageBackgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||||
}
|
}
|
||||||
self.addSubview(self.webView)
|
self.addSubview(self.webView)
|
||||||
|
|
||||||
|
self.webView.interactiveTransitionGestureRecognizerTest = { [weak self] point in
|
||||||
|
if let self {
|
||||||
|
if let result = self.webView.hitTest(point, with: nil), let scrollView = findScrollView(view: result), scrollView.isDescendant(of: self.webView) {
|
||||||
|
if scrollView.contentSize.width > scrollView.frame.width, scrollView.contentOffset.x > -scrollView.contentInset.left {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -416,3 +427,14 @@ final class BrowserDocumentContent: UIView, BrowserContent, WKNavigationDelegate
|
|||||||
return imageView
|
return imageView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func findScrollView(view: UIView?) -> UIScrollView? {
|
||||||
|
if let view = view {
|
||||||
|
if let view = view as? UIScrollView {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
return findScrollView(view: view.superview)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -117,12 +117,41 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
|
|||||||
self.pageNumber = (1, self.pdfView.document?.pageCount ?? 1)
|
self.pageNumber = (1, self.pdfView.document?.pageCount ?? 1)
|
||||||
|
|
||||||
self.startPageIndicatorTimer()
|
self.startPageIndicatorTimer()
|
||||||
|
|
||||||
|
self.pdfView.interactiveTransitionGestureRecognizerTest = { [weak self] point in
|
||||||
|
if let self {
|
||||||
|
if let result = self.pdfView.hitTest(point, with: nil), let scrollView = findScrollView(view: result), scrollView.isDescendant(of: self.pdfView) {
|
||||||
|
if scrollView.contentSize.width > scrollView.frame.width, scrollView.contentOffset.x > -scrollView.contentInset.left {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(self.pageChangeHandler(_:)), name: .PDFViewPageChanged, object: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self, name: .PDFViewPageChanged, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func pageChangeHandler(_ notification: Notification) {
|
||||||
|
if let document = self.pdfView.document, let page = self.pdfView.currentPage {
|
||||||
|
let number = document.index(for: page) + 1
|
||||||
|
if number != self.pageNumber?.0 {
|
||||||
|
self.pageNumber = (number, document.pageCount)
|
||||||
|
if let (size, insets, fullInsets) = self.validLayout {
|
||||||
|
self.updateLayout(size: size, insets: insets, fullInsets: fullInsets, safeInsets: .zero, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
if #available(iOS 15.0, *) {
|
if #available(iOS 15.0, *) {
|
||||||
@ -421,16 +450,6 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
|
|||||||
}
|
}
|
||||||
if !scrollView.isZooming && !self.wasZooming {
|
if !scrollView.isZooming && !self.wasZooming {
|
||||||
self.updateScrollingOffset(isReset: false, transition: .immediate)
|
self.updateScrollingOffset(isReset: false, transition: .immediate)
|
||||||
|
|
||||||
if let document = self.pdfView.document, let page = self.pdfView.currentPage {
|
|
||||||
let number = document.index(for: page) + 1
|
|
||||||
if number != self.pageNumber?.0 {
|
|
||||||
self.pageNumber = (number, document.pageCount)
|
|
||||||
if let (size, insets, fullInsets) = self.validLayout {
|
|
||||||
self.updateLayout(size: size, insets: insets, fullInsets: fullInsets, safeInsets: .zero, transition: .immediate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,3 +565,14 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func findScrollView(view: UIView?) -> UIScrollView? {
|
||||||
|
if let view = view {
|
||||||
|
if let view = view as? UIScrollView {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
return findScrollView(view: view.superview)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Display
|
import Display
|
||||||
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
@ -1473,10 +1474,19 @@ public class BrowserScreen: ViewController, MinimizableController {
|
|||||||
case instantPage(webPage: TelegramMediaWebpage, anchor: String?, sourceLocation: InstantPageSourceLocation, preloadedResources: [Any]?)
|
case instantPage(webPage: TelegramMediaWebpage, anchor: String?, sourceLocation: InstantPageSourceLocation, preloadedResources: [Any]?)
|
||||||
case document(file: TelegramMediaFile, canShare: Bool)
|
case document(file: TelegramMediaFile, canShare: Bool)
|
||||||
case pdfDocument(file: TelegramMediaFile, canShare: Bool)
|
case pdfDocument(file: TelegramMediaFile, canShare: Bool)
|
||||||
|
|
||||||
|
public var fileId: MediaId? {
|
||||||
|
switch self {
|
||||||
|
case let .document(file, _), let .pdfDocument(file, _):
|
||||||
|
return file.fileId
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
fileprivate let subject: Subject
|
public let subject: Subject
|
||||||
private var preferredConfiguration: WKWebViewConfiguration?
|
private var preferredConfiguration: WKWebViewConfiguration?
|
||||||
private var openPreviousOnClose = false
|
private var openPreviousOnClose = false
|
||||||
|
|
||||||
|
@ -740,7 +740,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||||||
// })
|
// })
|
||||||
// } else {
|
// } else {
|
||||||
if let url = navigationAction.request.url?.absoluteString {
|
if let url = navigationAction.request.url?.absoluteString {
|
||||||
if (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true) && (isTelegramMeLink(url) || isTelegraPhLink(url)) && !url.contains("/auth/push?") && !self._state.url.contains("/auth/push?") {
|
if (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true) && (isTelegramMeLink(url) || isTelegraPhLink(url) || url.hasPrefix("tg://")) && !url.contains("/auth/push?") && !self._state.url.contains("/auth/push?") {
|
||||||
decisionHandler(.cancel, preferences)
|
decisionHandler(.cancel, preferences)
|
||||||
self.minimize()
|
self.minimize()
|
||||||
self.openAppUrl(url)
|
self.openAppUrl(url)
|
||||||
@ -776,7 +776,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||||||
|
|
||||||
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
||||||
if let url = navigationAction.request.url?.absoluteString {
|
if let url = navigationAction.request.url?.absoluteString {
|
||||||
if (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true) && (isTelegramMeLink(url) || isTelegraPhLink(url)) {
|
if (navigationAction.targetFrame == nil || navigationAction.targetFrame?.isMainFrame == true) && (isTelegramMeLink(url) || isTelegraPhLink(url) || url.hasPrefix("tg://")) {
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
self.minimize()
|
self.minimize()
|
||||||
self.openAppUrl(url)
|
self.openAppUrl(url)
|
||||||
@ -858,7 +858,10 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||||||
|
|
||||||
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||||
if [-1003, -1100, 102].contains((error as NSError).code) {
|
if [-1003, -1100, 102].contains((error as NSError).code) {
|
||||||
|
if let url = (error as NSError).userInfo["NSErrorFailingURLKey"] as? URL, url.absoluteString.hasPrefix("itms-appss:") {
|
||||||
|
} else {
|
||||||
self.currentError = error
|
self.currentError = error
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.currentError = nil
|
self.currentError = nil
|
||||||
}
|
}
|
||||||
@ -870,7 +873,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||||||
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||||
if navigationAction.targetFrame == nil {
|
if navigationAction.targetFrame == nil {
|
||||||
if let url = navigationAction.request.url?.absoluteString {
|
if let url = navigationAction.request.url?.absoluteString {
|
||||||
if isTelegramMeLink(url) || isTelegraPhLink(url) {
|
if isTelegramMeLink(url) || isTelegraPhLink(url) || url.hasPrefix("tg://") {
|
||||||
self.minimize()
|
self.minimize()
|
||||||
self.openAppUrl(url)
|
self.openAppUrl(url)
|
||||||
} else {
|
} else {
|
||||||
@ -1350,7 +1353,7 @@ let setupFontFunctions = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
private let videoSource = """
|
private let videoSource = """
|
||||||
function disableWebkitEnterFullscreen(videoElement) {
|
function tgBrowserDisableWebkitEnterFullscreen(videoElement) {
|
||||||
if (videoElement && videoElement.webkitEnterFullscreen) {
|
if (videoElement && videoElement.webkitEnterFullscreen) {
|
||||||
Object.defineProperty(videoElement, 'webkitEnterFullscreen', {
|
Object.defineProperty(videoElement, 'webkitEnterFullscreen', {
|
||||||
value: undefined
|
value: undefined
|
||||||
@ -1358,11 +1361,11 @@ function disableWebkitEnterFullscreen(videoElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableFullscreenOnExistingVideos() {
|
function tgBrowserDisableFullscreenOnExistingVideos() {
|
||||||
document.querySelectorAll('video').forEach(disableWebkitEnterFullscreen);
|
document.querySelectorAll('video').forEach(tgBrowserDisableWebkitEnterFullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMutations(mutations) {
|
function tgBrowserHandleMutations(mutations) {
|
||||||
mutations.forEach((mutation) => {
|
mutations.forEach((mutation) => {
|
||||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||||
mutation.addedNodes.forEach((newNode) => {
|
mutation.addedNodes.forEach((newNode) => {
|
||||||
@ -1377,17 +1380,17 @@ function handleMutations(mutations) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
disableFullscreenOnExistingVideos();
|
tgBrowserDisableFullscreenOnExistingVideos();
|
||||||
|
|
||||||
const observer = new MutationObserver(handleMutations);
|
const _tgbrowser_observer = new MutationObserver(tgBrowserHandleMutations);
|
||||||
|
|
||||||
observer.observe(document.body, {
|
_tgbrowser_observer.observe(document.body, {
|
||||||
childList: true,
|
childList: true,
|
||||||
subtree: true
|
subtree: true
|
||||||
});
|
});
|
||||||
|
|
||||||
function disconnectObserver() {
|
function tgBrowserDisconnectObserver() {
|
||||||
observer.disconnect();
|
_tgbrowser_observer.disconnect();
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ public enum SendMessageActionSheetControllerParams {
|
|||||||
public let forwardMessageIds: [EngineMessage.Id]
|
public let forwardMessageIds: [EngineMessage.Id]
|
||||||
public let canMakePaidContent: Bool
|
public let canMakePaidContent: Bool
|
||||||
public let currentPrice: Int64?
|
public let currentPrice: Int64?
|
||||||
|
public let hasTimers: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
isScheduledMessages: Bool,
|
isScheduledMessages: Bool,
|
||||||
@ -32,7 +33,8 @@ public enum SendMessageActionSheetControllerParams {
|
|||||||
canSendWhenOnline: Bool,
|
canSendWhenOnline: Bool,
|
||||||
forwardMessageIds: [EngineMessage.Id],
|
forwardMessageIds: [EngineMessage.Id],
|
||||||
canMakePaidContent: Bool,
|
canMakePaidContent: Bool,
|
||||||
currentPrice: Int64?
|
currentPrice: Int64?,
|
||||||
|
hasTimers: Bool
|
||||||
) {
|
) {
|
||||||
self.isScheduledMessages = isScheduledMessages
|
self.isScheduledMessages = isScheduledMessages
|
||||||
self.mediaPreview = mediaPreview
|
self.mediaPreview = mediaPreview
|
||||||
@ -43,6 +45,7 @@ public enum SendMessageActionSheetControllerParams {
|
|||||||
self.forwardMessageIds = forwardMessageIds
|
self.forwardMessageIds = forwardMessageIds
|
||||||
self.canMakePaidContent = canMakePaidContent
|
self.canMakePaidContent = canMakePaidContent
|
||||||
self.currentPrice = currentPrice
|
self.currentPrice = currentPrice
|
||||||
|
self.hasTimers = hasTimers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +452,9 @@ final class ChatSendMessageContextScreenComponent: Component {
|
|||||||
if sendMessage.isScheduledMessages {
|
if sendMessage.isScheduledMessages {
|
||||||
canSchedule = false
|
canSchedule = false
|
||||||
}
|
}
|
||||||
|
if sendMessage.hasTimers {
|
||||||
|
canSchedule = false
|
||||||
|
}
|
||||||
canMakePaidContent = sendMessage.canMakePaidContent
|
canMakePaidContent = sendMessage.canMakePaidContent
|
||||||
currentPrice = sendMessage.currentPrice
|
currentPrice = sendMessage.currentPrice
|
||||||
case .editMessage:
|
case .editMessage:
|
||||||
|
@ -488,6 +488,8 @@ final class ComposePollScreenComponent: Component {
|
|||||||
self.environment = environment
|
self.environment = environment
|
||||||
|
|
||||||
if self.component == nil {
|
if self.component == nil {
|
||||||
|
self.isQuiz = component.isQuiz ?? false
|
||||||
|
|
||||||
self.pollOptions.append(ComposePollScreenComponent.PollOption(
|
self.pollOptions.append(ComposePollScreenComponent.PollOption(
|
||||||
id: self.nextPollOptionId
|
id: self.nextPollOptionId
|
||||||
))
|
))
|
||||||
@ -1002,7 +1004,13 @@ final class ComposePollScreenComponent: Component {
|
|||||||
contentHeight += pollOptionsSectionFooterSize.height
|
contentHeight += pollOptionsSectionFooterSize.height
|
||||||
contentHeight += sectionSpacing
|
contentHeight += sectionSpacing
|
||||||
|
|
||||||
|
var canBePublic = true
|
||||||
|
if case let .channel(channel) = component.peer, case .broadcast = channel.info {
|
||||||
|
canBePublic = false
|
||||||
|
}
|
||||||
|
|
||||||
var pollSettingsSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
var pollSettingsSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
||||||
|
if canBePublic {
|
||||||
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "anonymous", component: AnyComponent(ListActionItemComponent(
|
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "anonymous", component: AnyComponent(ListActionItemComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
title: AnyComponent(VStack([
|
title: AnyComponent(VStack([
|
||||||
@ -1024,6 +1032,7 @@ final class ComposePollScreenComponent: Component {
|
|||||||
})),
|
})),
|
||||||
action: nil
|
action: nil
|
||||||
))))
|
))))
|
||||||
|
}
|
||||||
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "multiAnswer", component: AnyComponent(ListActionItemComponent(
|
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "multiAnswer", component: AnyComponent(ListActionItemComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
title: AnyComponent(VStack([
|
title: AnyComponent(VStack([
|
||||||
@ -1569,7 +1578,7 @@ public class ComposePollScreen: ViewControllerComponentContainer, AttachmentCont
|
|||||||
|
|
||||||
public static func initialData(context: AccountContext) -> InitialData {
|
public static func initialData(context: AccountContext) -> InitialData {
|
||||||
return InitialData(
|
return InitialData(
|
||||||
maxPollTextLength: Int(255),
|
maxPollTextLength: Int(200),
|
||||||
maxPollOptionLength: 100
|
maxPollOptionLength: 100
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ private struct OrderedLinkedList<T: Equatable>: Sequence, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private let maxTextLength = 255
|
private let maxTextLength = 200
|
||||||
private let maxOptionLength = 100
|
private let maxOptionLength = 100
|
||||||
private let maxOptionCount = 10
|
private let maxOptionCount = 10
|
||||||
|
|
||||||
|
@ -1714,6 +1714,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||||||
shareController.dismissed = { [weak self] _ in
|
shareController.dismissed = { [weak self] _ in
|
||||||
self?.interacting?(false)
|
self?.interacting?(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
shareController.actionCompleted = { [weak self] in
|
shareController.actionCompleted = { [weak self] in
|
||||||
if let strongSelf = self, let actionCompletionText = actionCompletionText {
|
if let strongSelf = self, let actionCompletionText = actionCompletionText {
|
||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
@ -259,6 +259,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
private let dataDisposable = MetaDisposable()
|
private let dataDisposable = MetaDisposable()
|
||||||
private let recognitionDisposable = MetaDisposable()
|
private let recognitionDisposable = MetaDisposable()
|
||||||
private var status: MediaResourceStatus?
|
private var status: MediaResourceStatus?
|
||||||
|
private var fetchedDimensions: PixelDimensions?
|
||||||
|
|
||||||
private let pagingEnabledPromise = ValuePromise<Bool>(true)
|
private let pagingEnabledPromise = ValuePromise<Bool>(true)
|
||||||
|
|
||||||
@ -806,9 +807,9 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) {
|
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, force: Bool = false) {
|
||||||
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) {
|
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) || force {
|
||||||
if var largestSize = fileReference.media.dimensions {
|
if var largestSize = (fileReference.media.dimensions ?? self.fetchedDimensions) {
|
||||||
var displaySize = largestSize.cgSize.dividedByScreenScale()
|
var displaySize = largestSize.cgSize.dividedByScreenScale()
|
||||||
if let previewDimensions = largestImageRepresentation(fileReference.media.previewRepresentations)?.dimensions {
|
if let previewDimensions = largestImageRepresentation(fileReference.media.previewRepresentations)?.dimensions {
|
||||||
let previewAspect = CGFloat(previewDimensions.width) / CGFloat(previewDimensions.height)
|
let previewAspect = CGFloat(previewDimensions.width) / CGFloat(previewDimensions.height)
|
||||||
@ -848,6 +849,22 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|
|
||||||
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: fileReference.resourceReference(fileReference.media.resource)).start())
|
self.fetchDisposable.set(fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: fileReference.resourceReference(fileReference.media.resource)).start())
|
||||||
} else {
|
} else {
|
||||||
|
let _ = (chatMessageFileDatas(account: context.account, userLocation: userLocation, fileReference: fileReference, progressive: false, fetched: true)
|
||||||
|
|> mapToSignal { value -> Signal<UIImage?, NoError> in
|
||||||
|
if value._2, let path = value._1, let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
|
||||||
|
return .single(UIImage(data: data))
|
||||||
|
}
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] image in
|
||||||
|
if let self, let image {
|
||||||
|
self.fetchedDimensions = PixelDimensions(image.size)
|
||||||
|
self.setFile(context: context, userLocation: userLocation, fileReference: fileReference, force: true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self._ready.set(.single(Void()))
|
self._ready.set(.single(Void()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2775,6 +2775,20 @@ final class MediaPickerContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasTimers: Bool {
|
||||||
|
guard let controller = self.controller else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if let selectionContext = controller.interaction?.selectionState, let editingContext = controller.interaction?.editingState {
|
||||||
|
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
||||||
|
if let time = editingContext.timer(for: item), time.intValue > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var captionIsAboveMedia: Signal<Bool, NoError> {
|
var captionIsAboveMedia: Signal<Bool, NoError> {
|
||||||
return Signal { [weak self] subscriber in
|
return Signal { [weak self] subscriber in
|
||||||
guard let interaction = self?.controller?.interaction else {
|
guard let interaction = self?.controller?.interaction else {
|
||||||
|
@ -271,7 +271,7 @@ func chatMessagePhotoDatas(mediaBox: MediaBox, userLocation: MediaResourceUserLo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func chatMessageFileDatas(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, fetched: Bool = false) -> Signal<Tuple3<Data?, String?, Bool>, NoError> {
|
public func chatMessageFileDatas(account: Account, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, pathExtension: String? = nil, progressive: Bool = false, fetched: Bool = false) -> Signal<Tuple3<Data?, String?, Bool>, NoError> {
|
||||||
let thumbnailResource = fetched ? nil : smallestImageRepresentation(fileReference.media.previewRepresentations)?.resource
|
let thumbnailResource = fetched ? nil : smallestImageRepresentation(fileReference.media.previewRepresentations)?.resource
|
||||||
let fullSizeResource = fileReference.media.resource
|
let fullSizeResource = fileReference.media.resource
|
||||||
|
|
||||||
|
@ -784,6 +784,7 @@ private func createGiveawayControllerEntries(
|
|||||||
entries.append(.prepaid(presentationData.theme, title, text, prepaidGiveaway))
|
entries.append(.prepaid(presentationData.theme, title, text, prepaidGiveaway))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var starsPerUser: Int64 = 0
|
||||||
if case .starsGiveaway = state.mode, !starsGiveawayOptions.isEmpty {
|
if case .starsGiveaway = state.mode, !starsGiveawayOptions.isEmpty {
|
||||||
let selectedOption = starsGiveawayOptions.first(where: { $0.giveawayOption.count == state.stars })!
|
let selectedOption = starsGiveawayOptions.first(where: { $0.giveawayOption.count == state.stars })!
|
||||||
entries.append(.starsHeader(presentationData.theme, presentationData.strings.BoostGift_Stars_Title.uppercased(), presentationData.strings.BoostGift_Stars_Boosts(selectedOption.giveawayOption.yearlyBoosts).uppercased()))
|
entries.append(.starsHeader(presentationData.theme, presentationData.strings.BoostGift_Stars_Title.uppercased(), presentationData.strings.BoostGift_Stars_Boosts(selectedOption.giveawayOption.yearlyBoosts).uppercased()))
|
||||||
@ -800,6 +801,7 @@ private func createGiveawayControllerEntries(
|
|||||||
|
|
||||||
let subtitle = presentationData.strings.BoostGift_Stars_PerUser("\(winners.starsPerUser)").string
|
let subtitle = presentationData.strings.BoostGift_Stars_PerUser("\(winners.starsPerUser)").string
|
||||||
let label = product.storeProduct.price
|
let label = product.storeProduct.price
|
||||||
|
starsPerUser = winners.starsPerUser
|
||||||
|
|
||||||
let isSelected = product.giveawayOption.count == state.stars
|
let isSelected = product.giveawayOption.count == state.stars
|
||||||
entries.append(.stars(i, presentationData.theme, Int32(product.giveawayOption.count), giftTitle, subtitle, label, isSelected, maxWinners))
|
entries.append(.stars(i, presentationData.theme, Int32(product.giveawayOption.count), giftTitle, subtitle, label, isSelected, maxWinners))
|
||||||
@ -933,6 +935,15 @@ private func createGiveawayControllerEntries(
|
|||||||
if state.showPrizeDescription {
|
if state.showPrizeDescription {
|
||||||
entries.append(.prizeDescriptionText(presentationData.theme, presentationData.strings.BoostGift_AdditionalPrizesPlaceholder, state.prizeDescription, state.subscriptions))
|
entries.append(.prizeDescriptionText(presentationData.theme, presentationData.strings.BoostGift_AdditionalPrizesPlaceholder, state.prizeDescription, state.subscriptions))
|
||||||
|
|
||||||
|
if state.mode == .starsGiveaway {
|
||||||
|
let starsString = presentationData.strings.BoostGift_AdditionalPrizesInfoStars(Int32(state.stars))
|
||||||
|
if state.prizeDescription.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
|
let _ = starsPerUser
|
||||||
|
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoStarsOn(starsString, "").string
|
||||||
|
} else {
|
||||||
|
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoStarsOn(starsString, presentationData.strings.BoostGift_AdditionalPrizesInfoStarsAndOther("\(state.winners)", state.prizeDescription).string).string
|
||||||
|
}
|
||||||
|
} else {
|
||||||
let monthsString = presentationData.strings.BoostGift_AdditionalPrizesInfoForMonths(state.selectedMonths ?? 12)
|
let monthsString = presentationData.strings.BoostGift_AdditionalPrizesInfoForMonths(state.selectedMonths ?? 12)
|
||||||
if state.prizeDescription.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
if state.prizeDescription.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||||
let subscriptionsString = presentationData.strings.BoostGift_AdditionalPrizesInfoSubscriptions(state.subscriptions).replacingOccurrences(of: "\(state.subscriptions) ", with: "")
|
let subscriptionsString = presentationData.strings.BoostGift_AdditionalPrizesInfoSubscriptions(state.subscriptions).replacingOccurrences(of: "\(state.subscriptions) ", with: "")
|
||||||
@ -943,6 +954,7 @@ private func createGiveawayControllerEntries(
|
|||||||
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOn("\(state.subscriptions)", description, monthsString).string
|
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOn("\(state.subscriptions)", description, monthsString).string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
entries.append(.prizeDescriptionInfo(presentationData.theme, prizeDescriptionInfoText))
|
entries.append(.prizeDescriptionInfo(presentationData.theme, prizeDescriptionInfoText))
|
||||||
|
|
||||||
entries.append(.timeHeader(presentationData.theme, presentationData.strings.BoostGift_DateTitle.uppercased()))
|
entries.append(.timeHeader(presentationData.theme, presentationData.strings.BoostGift_DateTitle.uppercased()))
|
||||||
|
@ -241,7 +241,6 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
} else {
|
} else {
|
||||||
type = .video
|
type = .video
|
||||||
}
|
}
|
||||||
break inner
|
|
||||||
case let .Audio(isVoice, _, _, _, _):
|
case let .Audio(isVoice, _, _, _, _):
|
||||||
if isVoice {
|
if isVoice {
|
||||||
type = .audio
|
type = .audio
|
||||||
@ -981,12 +980,21 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||||
case .joinedChannel:
|
case .joinedChannel:
|
||||||
attributedString = NSAttributedString(string: strings.Notification_ChannelJoinedByYou, font: titleBoldFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: strings.Notification_ChannelJoinedByYou, font: titleBoldFont, textColor: primaryTextColor)
|
||||||
case let .giveawayResults(winners, unclaimed, _):
|
case let .giveawayResults(winners, unclaimed, stars):
|
||||||
|
var isGroup = false
|
||||||
|
let messagePeer = message.peers[message.id.peerId]
|
||||||
|
if let channel = messagePeer as? TelegramChannel, case .group = channel.info {
|
||||||
|
isGroup = true
|
||||||
|
}
|
||||||
if winners == 0 {
|
if winners == 0 {
|
||||||
attributedString = parseMarkdownIntoAttributedString(strings.Notification_GiveawayResultsNoWinners(unclaimed), attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
if stars {
|
||||||
|
attributedString = parseMarkdownIntoAttributedString(isGroup ? strings.Notification_StarsGiveawayResultsNoWinners_Group : strings.Notification_StarsGiveawayResultsNoWinners, attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
||||||
|
} else {
|
||||||
|
attributedString = parseMarkdownIntoAttributedString(isGroup ? strings.Notification_GiveawayResultsNoWinners_Group(unclaimed) : strings.Notification_GiveawayResultsNoWinners(unclaimed), attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
||||||
|
}
|
||||||
} else if unclaimed > 0 {
|
} else if unclaimed > 0 {
|
||||||
let winnersString = parseMarkdownIntoAttributedString(strings.Notification_GiveawayResultsMixedWinners(winners), attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
let winnersString = parseMarkdownIntoAttributedString(strings.Notification_GiveawayResultsMixedWinners(winners), attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
||||||
let unclaimedString = parseMarkdownIntoAttributedString(strings.Notification_GiveawayResultsMixedUnclaimed(unclaimed), attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
let unclaimedString = parseMarkdownIntoAttributedString(isGroup ? strings.Notification_GiveawayResultsMixedUnclaimed_Group(unclaimed) : strings.Notification_GiveawayResultsMixedUnclaimed(unclaimed), attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
|
||||||
let combinedString = NSMutableAttributedString(attributedString: winnersString)
|
let combinedString = NSMutableAttributedString(attributedString: winnersString)
|
||||||
combinedString.append(NSAttributedString(string: "\n"))
|
combinedString.append(NSAttributedString(string: "\n"))
|
||||||
combinedString.append(unclaimedString)
|
combinedString.append(unclaimedString)
|
||||||
|
@ -289,9 +289,10 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
|
|||||||
badgeString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: badgeString.string))
|
badgeString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: badgeString.string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let badgeBackgroundColor = !incoming || !isStars ? accentColor : UIColor(rgb: 0xffaf0a)
|
||||||
var updatedBadgeImage: UIImage?
|
var updatedBadgeImage: UIImage?
|
||||||
if themeUpdated {
|
if themeUpdated {
|
||||||
updatedBadgeImage = generateStretchableFilledCircleImage(diameter: 21.0, color: isStars ? UIColor(rgb: 0xffaf0a) : accentColor, strokeColor: backgroundColor, strokeWidth: 1.0 + UIScreenPixel, backgroundColor: nil)
|
updatedBadgeImage = generateStretchableFilledCircleImage(diameter: 21.0, color: badgeBackgroundColor, strokeColor: backgroundColor, strokeWidth: 1.0 + UIScreenPixel, backgroundColor: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let prizeTitleText: String
|
let prizeTitleText: String
|
||||||
|
@ -995,7 +995,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
return ChatMessageBubbleContentTapAction(content: .none)
|
return ChatMessageBubbleContentTapAction(content: .none)
|
||||||
} else {
|
} else {
|
||||||
if let text = self.textNode.textNode.attributeSubstring(name: "Attribute__Blockquote", index: index) {
|
if let text = self.textNode.textNode.attributeSubstring(name: "Attribute__Blockquote", index: index) {
|
||||||
return ChatMessageBubbleContentTapAction(content: .copy(text.1))
|
return ChatMessageBubbleContentTapAction(content: .copy(text.0))
|
||||||
} else {
|
} else {
|
||||||
return ChatMessageBubbleContentTapAction(content: .none)
|
return ChatMessageBubbleContentTapAction(content: .none)
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
self.expandedDeletedMessages.insert(messageId)
|
self.expandedDeletedMessages.insert(messageId)
|
||||||
}
|
}
|
||||||
}, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _, _ in }, openUrl: { [weak self] url in
|
}, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _, _ in }, openUrl: { [weak self] url in
|
||||||
self?.openUrl(url.url)
|
self?.openUrl(url.url, progress: url.progress)
|
||||||
}, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { [weak self] message, associatedData in
|
}, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { [weak self] message, associatedData in
|
||||||
if let strongSelf = self, let navigationController = strongSelf.getNavigationController() {
|
if let strongSelf = self, let navigationController = strongSelf.getNavigationController() {
|
||||||
if let controller = strongSelf.context.sharedContext.makeInstantPageController(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType) {
|
if let controller = strongSelf.context.sharedContext.makeInstantPageController(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType) {
|
||||||
@ -628,6 +628,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}, playMessageEffect: { _ in
|
}, playMessageEffect: { _ in
|
||||||
}, editMessageFactCheck: { _ in
|
}, editMessageFactCheck: { _ in
|
||||||
}, requestMessageUpdate: { _, _ in
|
}, requestMessageUpdate: { _, _ in
|
||||||
|
|
||||||
}, cancelInteractiveKeyboardGestures: {
|
}, cancelInteractiveKeyboardGestures: {
|
||||||
}, dismissTextInput: {
|
}, dismissTextInput: {
|
||||||
}, scrollToMessageId: { _ in
|
}, scrollToMessageId: { _ in
|
||||||
@ -1159,7 +1160,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openUrl(_ url: String) {
|
private func openUrl(_ url: String, progress: Promise<Bool>? = nil) {
|
||||||
self.navigationActionDisposable.set((self.context.sharedContext.resolveUrl(context: self.context, peerId: nil, url: url, skipUrlAuth: true) |> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
self.navigationActionDisposable.set((self.context.sharedContext.resolveUrl(context: self.context, peerId: nil, url: url, skipUrlAuth: true) |> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
switch result {
|
switch result {
|
||||||
@ -1235,11 +1236,104 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
let browserController = strongSelf.context.sharedContext.makeInstantPageController(context: strongSelf.context, webPage: webPage, anchor: anchor, sourceLocation: InstantPageSourceLocation(userLocation: .peer(strongSelf.peer.id), peerType: .channel))
|
let browserController = strongSelf.context.sharedContext.makeInstantPageController(context: strongSelf.context, webPage: webPage, anchor: anchor, sourceLocation: InstantPageSourceLocation(userLocation: .peer(strongSelf.peer.id), peerType: .channel))
|
||||||
strongSelf.pushController(browserController)
|
strongSelf.pushController(browserController)
|
||||||
case let .join(link):
|
case let .join(link):
|
||||||
strongSelf.presentController(JoinLinkPreviewController(context: strongSelf.context, link: link, navigateToPeer: { peer, peekData in
|
let context = strongSelf.context
|
||||||
if let strongSelf = self {
|
let navigationController = strongSelf.getNavigationController()
|
||||||
strongSelf.openPeer(peer: peer, peekData: peekData)
|
let openPeer: (EnginePeer, ChatPeekTimeout?) -> Void = { [weak self] peer, peekData in
|
||||||
|
self?.openPeer(peer: peer, peekData: peekData)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let progress {
|
||||||
|
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||||
|
progress.set(.single(true))
|
||||||
|
return ActionDisposable {
|
||||||
|
Queue.mainQueue().async() {
|
||||||
|
progress.set(.single(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> runOn(Queue.mainQueue())
|
||||||
|
|> delay(0.1, queue: Queue.mainQueue())
|
||||||
|
let progressDisposable = progressSignal.startStrict()
|
||||||
|
|
||||||
|
var signal = context.engine.peers.joinLinkInformation(link)
|
||||||
|
signal = signal
|
||||||
|
|> afterDisposed {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
progressDisposable.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = (signal
|
||||||
|
|> deliverOnMainQueue).startStandalone(next: { [weak navigationController] resolvedState in
|
||||||
|
switch resolvedState {
|
||||||
|
case let .alreadyJoined(peer):
|
||||||
|
openPeer(peer, nil)
|
||||||
|
case let .peek(peer, deadline):
|
||||||
|
openPeer(peer, ChatPeekTimeout(deadline: deadline, linkData: link))
|
||||||
|
case let .invite(invite):
|
||||||
|
if let subscriptionPricing = invite.subscriptionPricing, let subscriptionFormId = invite.subscriptionFormId, let starsContext = context.starsContext {
|
||||||
|
let inputData = Promise<BotCheckoutController.InputData?>()
|
||||||
|
var photo: [TelegramMediaImageRepresentation] = []
|
||||||
|
if let photoRepresentation = invite.photoRepresentation {
|
||||||
|
photo.append(photoRepresentation)
|
||||||
|
}
|
||||||
|
let channel = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(0)), accessHash: .genericPublic(0), title: invite.title, username: nil, photo: photo, creationDate: 0, version: 0, participationStatus: .left, info: .broadcast(TelegramChannelBroadcastInfo(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil, usernames: [], storiesHidden: nil, nameColor: invite.nameColor, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, emojiStatus: nil, approximateBoostLevel: nil, subscriptionUntilDate: nil)
|
||||||
|
let invoice = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: subscriptionPricing.amount, startParam: "", extendedMedia: nil, flags: [], version: 0)
|
||||||
|
|
||||||
|
inputData.set(.single(BotCheckoutController.InputData(
|
||||||
|
form: BotPaymentForm(
|
||||||
|
id: subscriptionFormId,
|
||||||
|
canSaveCredentials: false,
|
||||||
|
passwordMissing: false,
|
||||||
|
invoice: BotPaymentInvoice(isTest: false, requestedFields: [], currency: "XTR", prices: [BotPaymentPrice(label: "", amount: subscriptionPricing.amount)], tip: nil, termsInfo: nil),
|
||||||
|
paymentBotId: channel.id,
|
||||||
|
providerId: nil,
|
||||||
|
url: nil,
|
||||||
|
nativeProvider: nil,
|
||||||
|
savedInfo: nil,
|
||||||
|
savedCredentials: [],
|
||||||
|
additionalPaymentMethods: []
|
||||||
|
),
|
||||||
|
validatedFormInfo: nil,
|
||||||
|
botPeer: EnginePeer(channel)
|
||||||
|
)))
|
||||||
|
|
||||||
|
let starsInputData = combineLatest(
|
||||||
|
inputData.get(),
|
||||||
|
starsContext.state
|
||||||
|
)
|
||||||
|
|> map { data, state -> (StarsContext.State, BotPaymentForm, EnginePeer?, EnginePeer?)? in
|
||||||
|
if let data, let state {
|
||||||
|
return (state, data.form, data.botPeer, nil)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let _ = (starsInputData
|
||||||
|
|> SwiftSignalKit.filter { $0 != nil }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { _ in
|
||||||
|
let controller = context.sharedContext.makeStarsSubscriptionTransferScreen(context: context, starsContext: starsContext, invoice: invoice, link: link, inputData: starsInputData, navigateToPeer: { peer in
|
||||||
|
openPeer(peer, nil)
|
||||||
|
})
|
||||||
|
navigationController?.pushViewController(controller)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
strongSelf.presentController(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in
|
||||||
|
openPeer(peer, peekData)
|
||||||
|
}, parentNavigationController: navigationController, resolvedState: resolvedState), .window(.root), nil)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
strongSelf.presentController(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in
|
||||||
|
openPeer(peer, peekData)
|
||||||
|
}, parentNavigationController: navigationController, resolvedState: resolvedState), .window(.root), nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
strongSelf.presentController(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in
|
||||||
|
openPeer(peer, peekData)
|
||||||
|
}, parentNavigationController: navigationController), .window(.root), nil)
|
||||||
}
|
}
|
||||||
}, parentNavigationController: strongSelf.getNavigationController()), .window(.root), nil)
|
|
||||||
case let .localization(identifier):
|
case let .localization(identifier):
|
||||||
strongSelf.presentController(LanguageLinkPreviewController(context: strongSelf.context, identifier: identifier), .window(.root), nil)
|
strongSelf.presentController(LanguageLinkPreviewController(context: strongSelf.context, identifier: identifier), .window(.root), nil)
|
||||||
case .proxy, .confirmationCode, .cancelAccountReset, .share:
|
case .proxy, .confirmationCode, .cancelAccountReset, .share:
|
||||||
|
@ -1746,7 +1746,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
self.topPeerItems[topPeer.id] = itemView
|
self.topPeerItems[topPeer.id] = itemView
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemCountString = "\(topPeer.count)"
|
let itemCountString = presentationStringsFormattedNumber(Int32(topPeer.count), environment.dateTimeFormat.groupingSeparator)
|
||||||
/*if topPeer.isMy && myCountAddition != 0 && topPeer.count > myCountAddition {
|
/*if topPeer.isMy && myCountAddition != 0 && topPeer.count > myCountAddition {
|
||||||
itemCountString = "\(topPeer.count - myCountAddition) +\(myCountAddition)"
|
itemCountString = "\(topPeer.count - myCountAddition) +\(myCountAddition)"
|
||||||
}*/
|
}*/
|
||||||
|
@ -711,7 +711,8 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
canSendWhenOnline: false,
|
canSendWhenOnline: false,
|
||||||
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
||||||
canMakePaidContent: false,
|
canMakePaidContent: false,
|
||||||
currentPrice: nil
|
currentPrice: nil,
|
||||||
|
hasTimers: false
|
||||||
)),
|
)),
|
||||||
hasEntityKeyboard: hasEntityKeyboard,
|
hasEntityKeyboard: hasEntityKeyboard,
|
||||||
gesture: gesture,
|
gesture: gesture,
|
||||||
|
@ -235,7 +235,8 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
|
|||||||
canSendWhenOnline: sendWhenOnlineAvailable,
|
canSendWhenOnline: sendWhenOnlineAvailable,
|
||||||
forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
||||||
canMakePaidContent: false,
|
canMakePaidContent: false,
|
||||||
currentPrice: nil
|
currentPrice: nil,
|
||||||
|
hasTimers: false
|
||||||
)),
|
)),
|
||||||
hasEntityKeyboard: hasEntityKeyboard,
|
hasEntityKeyboard: hasEntityKeyboard,
|
||||||
gesture: gesture,
|
gesture: gesture,
|
||||||
|
@ -4748,6 +4748,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
isMuted = peerIsMuted
|
isMuted = peerIsMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !"".isEmpty {
|
||||||
items.append(.action(ContextMenuActionItem(text: isMuted ? presentationData.strings.ChatList_Context_Unmute : presentationData.strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
items.append(.action(ContextMenuActionItem(text: isMuted ? presentationData.strings.ChatList_Context_Unmute : presentationData.strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||||
if isMuted {
|
if isMuted {
|
||||||
let _ = (context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: 0)
|
let _ = (context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: 0)
|
||||||
@ -4786,9 +4787,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, action: { _, f in
|
}, action: { _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
||||||
// if let chatListController = chatListController {
|
// if let chatListController = chatListController {
|
||||||
// openCustomMute(context: context, peerId: peerId, threadId: threadId, baseController: chatListController)
|
// openCustomMute(context: context, peerId: peerId, threadId: threadId, baseController: chatListController)
|
||||||
// }
|
// }
|
||||||
})))
|
})))
|
||||||
|
|
||||||
c?.setItems(.single(ContextController.Items(content: .list(subItems))), minHeight: nil, animated: true)
|
c?.setItems(.single(ContextController.Items(content: .list(subItems))), minHeight: nil, animated: true)
|
||||||
@ -4949,6 +4950,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
c?.setItems(.single(ContextController.Items(content: .list(items))), minHeight: nil, animated: true)
|
c?.setItems(.single(ContextController.Items(content: .list(items))), minHeight: nil, animated: true)
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_Search, icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_Search, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Search"), color: theme.actionSheet.primaryTextColor)
|
||||||
@ -4973,13 +4975,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
let _ = context.engine.peers.setForumChannelTopicClosed(id: peer.id, threadId: threadId, isClosed: !threadData.isClosed).startStandalone()
|
let _ = context.engine.peers.setForumChannelTopicClosed(id: peer.id, threadId: threadId, isClosed: !threadData.isClosed).startStandalone()
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
// if channel.hasPermission(.deleteAllMessages) {
|
|
||||||
// items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak chatListController] _, f in
|
|
||||||
// f(.default)
|
|
||||||
//
|
|
||||||
// chatListController?.deletePeerThread(peerId: peerId, threadId: threadId)
|
|
||||||
// })))
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
@ -239,6 +239,15 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
|||||||
useBrowserScreen = true
|
useBrowserScreen = true
|
||||||
}
|
}
|
||||||
if useBrowserScreen {
|
if useBrowserScreen {
|
||||||
|
if let navigationController = params.navigationController, let minimizedContainer = navigationController.minimizedContainer {
|
||||||
|
for controller in minimizedContainer.controllers {
|
||||||
|
if let controller = controller as? BrowserScreen, controller.subject.fileId == file.fileId {
|
||||||
|
navigationController.maximizeViewController(controller, animated: true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let subject: BrowserScreen.Subject
|
let subject: BrowserScreen.Subject
|
||||||
if file.mimeType == "application/pdf" {
|
if file.mimeType == "application/pdf" {
|
||||||
subject = .pdfDocument(file: file, canShare: canShare)
|
subject = .pdfDocument(file: file, canShare: canShare)
|
||||||
|
@ -48,6 +48,14 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
|
|||||||
if let navigationController = controller?.navigationController as? NavigationController {
|
if let navigationController = controller?.navigationController as? NavigationController {
|
||||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botStart: botStart, keepStack: .always))
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botStart: botStart, keepStack: .always))
|
||||||
}
|
}
|
||||||
|
case let .withAttachBot(attachBotStart):
|
||||||
|
if let navigationController = controller?.navigationController as? NavigationController {
|
||||||
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), attachBotStart: attachBotStart))
|
||||||
|
}
|
||||||
|
case let .withBotApp(botAppStart):
|
||||||
|
if let navigationController = controller?.navigationController as? NavigationController {
|
||||||
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botAppStart: botAppStart))
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -92,15 +100,13 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
|
|||||||
let sourceLocation = InstantPageSourceLocation(userLocation: peerId.flatMap(MediaResourceUserLocation.peer) ?? .other, peerType: .group)
|
let sourceLocation = InstantPageSourceLocation(userLocation: peerId.flatMap(MediaResourceUserLocation.peer) ?? .other, peerType: .group)
|
||||||
let browserController = context.sharedContext.makeInstantPageController(context: context, webPage: webPage, anchor: anchor, sourceLocation: sourceLocation)
|
let browserController = context.sharedContext.makeInstantPageController(context: context, webPage: webPage, anchor: anchor, sourceLocation: sourceLocation)
|
||||||
(controller.navigationController as? NavigationController)?.pushViewController(browserController, animated: true)
|
(controller.navigationController as? NavigationController)?.pushViewController(browserController, animated: true)
|
||||||
// case let .join(link):
|
|
||||||
// controller.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in
|
|
||||||
// openResolvedPeerImpl(peer, .chat(textInputState: nil, subject: nil, peekData: peekData))
|
|
||||||
// }, parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root))
|
|
||||||
case .boost, .chatFolder, .join:
|
case .boost, .chatFolder, .join:
|
||||||
if let navigationController = controller.navigationController as? NavigationController {
|
if let navigationController = controller.navigationController as? NavigationController {
|
||||||
openResolvedUrlImpl(result, context: context, urlContext: peerId.flatMap { .chat(peerId: $0, message: nil, updatedPresentationData: nil) } ?? .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigateToPeer in
|
openResolvedUrlImpl(result, context: context, urlContext: peerId.flatMap { .chat(peerId: $0, message: nil, updatedPresentationData: nil) } ?? .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigateToPeer in
|
||||||
openResolvedPeerImpl(peer, navigateToPeer)
|
openResolvedPeerImpl(peer, navigateToPeer)
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, joinVoiceChat: nil, present: { c, a in }, dismissInput: {}, contentContext: nil, progress: Promise(), completion: nil)
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, joinVoiceChat: nil, present: { c, a in
|
||||||
|
controller.present(c, in: .window(.root), with: a)
|
||||||
|
}, dismissInput: {}, contentContext: nil, progress: Promise(), completion: nil)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
Loading…
x
Reference in New Issue
Block a user