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_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_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_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.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.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.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.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 }
|
||||
func setPrice(_ price: Int64) -> Void
|
||||
|
||||
var hasTimers: Bool { get }
|
||||
|
||||
var loadingProgress: Signal<CGFloat?, NoError> { get }
|
||||
var mainButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||
var secondaryButtonState: Signal<AttachmentMainButtonState?, NoError> { get }
|
||||
@ -257,6 +259,10 @@ public extension AttachmentMediaPickerContext {
|
||||
func setPrice(_ price: Int64) -> Void {
|
||||
}
|
||||
|
||||
var hasTimers: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var loadingProgress: Signal<CGFloat?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
|
@ -1004,10 +1004,12 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
var captionIsAboveMedia: Signal<Bool, NoError> = .single(false)
|
||||
var canMakePaidContent = false
|
||||
var currentPrice: Int64?
|
||||
var hasTimers = false
|
||||
if let controller = strongSelf.controller, let mediaPickerContext = controller.mediaPickerContext {
|
||||
captionIsAboveMedia = mediaPickerContext.captionIsAboveMedia
|
||||
canMakePaidContent = mediaPickerContext.canMakePaidContent
|
||||
currentPrice = mediaPickerContext.price
|
||||
hasTimers = mediaPickerContext.hasTimers
|
||||
}
|
||||
|
||||
let _ = (combineLatest(
|
||||
@ -1039,7 +1041,8 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
canSendWhenOnline: sendWhenOnlineAvailable,
|
||||
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
||||
canMakePaidContent: canMakePaidContent,
|
||||
currentPrice: currentPrice
|
||||
currentPrice: currentPrice,
|
||||
hasTimers: hasTimers
|
||||
)),
|
||||
hasEntityKeyboard: hasEntityKeyboard,
|
||||
gesture: gesture,
|
||||
|
@ -92,6 +92,17 @@ final class BrowserDocumentContent: UIView, BrowserContent, WKNavigationDelegate
|
||||
self.webView.underPageBackgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||
}
|
||||
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) {
|
||||
@ -416,3 +427,14 @@ final class BrowserDocumentContent: UIView, BrowserContent, WKNavigationDelegate
|
||||
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.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) {
|
||||
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) {
|
||||
self.presentationData = presentationData
|
||||
if #available(iOS 15.0, *) {
|
||||
@ -421,16 +450,6 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
|
||||
}
|
||||
if !scrollView.isZooming && !self.wasZooming {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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 SwiftSignalKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import ComponentFlow
|
||||
@ -1473,10 +1474,19 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
case instantPage(webPage: TelegramMediaWebpage, anchor: String?, sourceLocation: InstantPageSourceLocation, preloadedResources: [Any]?)
|
||||
case document(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
|
||||
fileprivate let subject: Subject
|
||||
public let subject: Subject
|
||||
private var preferredConfiguration: WKWebViewConfiguration?
|
||||
private var openPreviousOnClose = false
|
||||
|
||||
|
@ -740,7 +740,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
// })
|
||||
// } else {
|
||||
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)
|
||||
self.minimize()
|
||||
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) {
|
||||
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)
|
||||
self.minimize()
|
||||
self.openAppUrl(url)
|
||||
@ -858,7 +858,10 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
|
||||
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||
if [-1003, -1100, 102].contains((error as NSError).code) {
|
||||
self.currentError = error
|
||||
if let url = (error as NSError).userInfo["NSErrorFailingURLKey"] as? URL, url.absoluteString.hasPrefix("itms-appss:") {
|
||||
} else {
|
||||
self.currentError = error
|
||||
}
|
||||
} else {
|
||||
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? {
|
||||
if navigationAction.targetFrame == nil {
|
||||
if let url = navigationAction.request.url?.absoluteString {
|
||||
if isTelegramMeLink(url) || isTelegraPhLink(url) {
|
||||
if isTelegramMeLink(url) || isTelegraPhLink(url) || url.hasPrefix("tg://") {
|
||||
self.minimize()
|
||||
self.openAppUrl(url)
|
||||
} else {
|
||||
@ -1350,7 +1353,7 @@ let setupFontFunctions = """
|
||||
"""
|
||||
|
||||
private let videoSource = """
|
||||
function disableWebkitEnterFullscreen(videoElement) {
|
||||
function tgBrowserDisableWebkitEnterFullscreen(videoElement) {
|
||||
if (videoElement && videoElement.webkitEnterFullscreen) {
|
||||
Object.defineProperty(videoElement, 'webkitEnterFullscreen', {
|
||||
value: undefined
|
||||
@ -1358,11 +1361,11 @@ function disableWebkitEnterFullscreen(videoElement) {
|
||||
}
|
||||
}
|
||||
|
||||
function disableFullscreenOnExistingVideos() {
|
||||
document.querySelectorAll('video').forEach(disableWebkitEnterFullscreen);
|
||||
function tgBrowserDisableFullscreenOnExistingVideos() {
|
||||
document.querySelectorAll('video').forEach(tgBrowserDisableWebkitEnterFullscreen);
|
||||
}
|
||||
|
||||
function handleMutations(mutations) {
|
||||
function tgBrowserHandleMutations(mutations) {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.addedNodes && mutation.addedNodes.length > 0) {
|
||||
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,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
function disconnectObserver() {
|
||||
observer.disconnect();
|
||||
function tgBrowserDisconnectObserver() {
|
||||
_tgbrowser_observer.disconnect();
|
||||
}
|
||||
"""
|
||||
|
||||
|
@ -22,6 +22,7 @@ public enum SendMessageActionSheetControllerParams {
|
||||
public let forwardMessageIds: [EngineMessage.Id]
|
||||
public let canMakePaidContent: Bool
|
||||
public let currentPrice: Int64?
|
||||
public let hasTimers: Bool
|
||||
|
||||
public init(
|
||||
isScheduledMessages: Bool,
|
||||
@ -32,7 +33,8 @@ public enum SendMessageActionSheetControllerParams {
|
||||
canSendWhenOnline: Bool,
|
||||
forwardMessageIds: [EngineMessage.Id],
|
||||
canMakePaidContent: Bool,
|
||||
currentPrice: Int64?
|
||||
currentPrice: Int64?,
|
||||
hasTimers: Bool
|
||||
) {
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.mediaPreview = mediaPreview
|
||||
@ -43,6 +45,7 @@ public enum SendMessageActionSheetControllerParams {
|
||||
self.forwardMessageIds = forwardMessageIds
|
||||
self.canMakePaidContent = canMakePaidContent
|
||||
self.currentPrice = currentPrice
|
||||
self.hasTimers = hasTimers
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,6 +452,9 @@ final class ChatSendMessageContextScreenComponent: Component {
|
||||
if sendMessage.isScheduledMessages {
|
||||
canSchedule = false
|
||||
}
|
||||
if sendMessage.hasTimers {
|
||||
canSchedule = false
|
||||
}
|
||||
canMakePaidContent = sendMessage.canMakePaidContent
|
||||
currentPrice = sendMessage.currentPrice
|
||||
case .editMessage:
|
||||
|
@ -488,6 +488,8 @@ final class ComposePollScreenComponent: Component {
|
||||
self.environment = environment
|
||||
|
||||
if self.component == nil {
|
||||
self.isQuiz = component.isQuiz ?? false
|
||||
|
||||
self.pollOptions.append(ComposePollScreenComponent.PollOption(
|
||||
id: self.nextPollOptionId
|
||||
))
|
||||
@ -1002,28 +1004,35 @@ final class ComposePollScreenComponent: Component {
|
||||
contentHeight += pollOptionsSectionFooterSize.height
|
||||
contentHeight += sectionSpacing
|
||||
|
||||
var canBePublic = true
|
||||
if case let .channel(channel) = component.peer, case .broadcast = channel.info {
|
||||
canBePublic = false
|
||||
}
|
||||
|
||||
var pollSettingsSectionItems: [AnyComponentWithIdentity<Empty>] = []
|
||||
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "anonymous", component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.CreatePoll_Anonymous,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.isAnonymous, action: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isAnonymous = !self.isAnonymous
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
})),
|
||||
action: nil
|
||||
))))
|
||||
if canBePublic {
|
||||
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "anonymous", component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.CreatePoll_Anonymous,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.isAnonymous, action: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isAnonymous = !self.isAnonymous
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
})),
|
||||
action: nil
|
||||
))))
|
||||
}
|
||||
pollSettingsSectionItems.append(AnyComponentWithIdentity(id: "multiAnswer", component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
@ -1569,7 +1578,7 @@ public class ComposePollScreen: ViewControllerComponentContainer, AttachmentCont
|
||||
|
||||
public static func initialData(context: AccountContext) -> InitialData {
|
||||
return InitialData(
|
||||
maxPollTextLength: Int(255),
|
||||
maxPollTextLength: Int(200),
|
||||
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 maxOptionCount = 10
|
||||
|
||||
|
@ -1714,6 +1714,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
if let strongSelf = self, let actionCompletionText = actionCompletionText {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
@ -259,6 +259,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
private let dataDisposable = MetaDisposable()
|
||||
private let recognitionDisposable = MetaDisposable()
|
||||
private var status: MediaResourceStatus?
|
||||
private var fetchedDimensions: PixelDimensions?
|
||||
|
||||
private let pagingEnabledPromise = ValuePromise<Bool>(true)
|
||||
|
||||
@ -806,9 +807,9 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
})
|
||||
}
|
||||
|
||||
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) {
|
||||
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) {
|
||||
if var largestSize = fileReference.media.dimensions {
|
||||
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, force: Bool = false) {
|
||||
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) || force {
|
||||
if var largestSize = (fileReference.media.dimensions ?? self.fetchedDimensions) {
|
||||
var displaySize = largestSize.cgSize.dividedByScreenScale()
|
||||
if let previewDimensions = largestImageRepresentation(fileReference.media.previewRepresentations)?.dimensions {
|
||||
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())
|
||||
} 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()))
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
return Signal { [weak self] subscriber in
|
||||
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 fullSizeResource = fileReference.media.resource
|
||||
|
||||
|
@ -784,6 +784,7 @@ private func createGiveawayControllerEntries(
|
||||
entries.append(.prepaid(presentationData.theme, title, text, prepaidGiveaway))
|
||||
}
|
||||
|
||||
var starsPerUser: Int64 = 0
|
||||
if case .starsGiveaway = state.mode, !starsGiveawayOptions.isEmpty {
|
||||
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()))
|
||||
@ -800,6 +801,7 @@ private func createGiveawayControllerEntries(
|
||||
|
||||
let subtitle = presentationData.strings.BoostGift_Stars_PerUser("\(winners.starsPerUser)").string
|
||||
let label = product.storeProduct.price
|
||||
starsPerUser = winners.starsPerUser
|
||||
|
||||
let isSelected = product.giveawayOption.count == state.stars
|
||||
entries.append(.stars(i, presentationData.theme, Int32(product.giveawayOption.count), giftTitle, subtitle, label, isSelected, maxWinners))
|
||||
@ -933,14 +935,24 @@ private func createGiveawayControllerEntries(
|
||||
if state.showPrizeDescription {
|
||||
entries.append(.prizeDescriptionText(presentationData.theme, presentationData.strings.BoostGift_AdditionalPrizesPlaceholder, state.prizeDescription, state.subscriptions))
|
||||
|
||||
let monthsString = presentationData.strings.BoostGift_AdditionalPrizesInfoForMonths(state.selectedMonths ?? 12)
|
||||
if state.prizeDescription.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
let subscriptionsString = presentationData.strings.BoostGift_AdditionalPrizesInfoSubscriptions(state.subscriptions).replacingOccurrences(of: "\(state.subscriptions) ", with: "")
|
||||
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOn("\(state.subscriptions)", subscriptionsString, monthsString).string
|
||||
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 subscriptionsString = presentationData.strings.BoostGift_AdditionalPrizesInfoWithSubscriptions(state.subscriptions).replacingOccurrences(of: "\(state.subscriptions) ", with: "")
|
||||
let description = "\(state.prizeDescription) \(subscriptionsString)"
|
||||
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOn("\(state.subscriptions)", description, monthsString).string
|
||||
let monthsString = presentationData.strings.BoostGift_AdditionalPrizesInfoForMonths(state.selectedMonths ?? 12)
|
||||
if state.prizeDescription.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
let subscriptionsString = presentationData.strings.BoostGift_AdditionalPrizesInfoSubscriptions(state.subscriptions).replacingOccurrences(of: "\(state.subscriptions) ", with: "")
|
||||
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOn("\(state.subscriptions)", subscriptionsString, monthsString).string
|
||||
} else {
|
||||
let subscriptionsString = presentationData.strings.BoostGift_AdditionalPrizesInfoWithSubscriptions(state.subscriptions).replacingOccurrences(of: "\(state.subscriptions) ", with: "")
|
||||
let description = "\(state.prizeDescription) \(subscriptionsString)"
|
||||
prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOn("\(state.subscriptions)", description, monthsString).string
|
||||
}
|
||||
}
|
||||
}
|
||||
entries.append(.prizeDescriptionInfo(presentationData.theme, prizeDescriptionInfoText))
|
||||
|
@ -241,7 +241,6 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
} else {
|
||||
type = .video
|
||||
}
|
||||
break inner
|
||||
case let .Audio(isVoice, _, _, _, _):
|
||||
if isVoice {
|
||||
type = .audio
|
||||
@ -981,12 +980,21 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
|
||||
case .joinedChannel:
|
||||
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 {
|
||||
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 {
|
||||
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)
|
||||
combinedString.append(NSAttributedString(string: "\n"))
|
||||
combinedString.append(unclaimedString)
|
||||
|
@ -289,9 +289,10 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
|
||||
badgeString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: badgeString.string))
|
||||
}
|
||||
|
||||
let badgeBackgroundColor = !incoming || !isStars ? accentColor : UIColor(rgb: 0xffaf0a)
|
||||
var updatedBadgeImage: UIImage?
|
||||
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
|
||||
|
@ -995,7 +995,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
return ChatMessageBubbleContentTapAction(content: .none)
|
||||
} else {
|
||||
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 {
|
||||
return ChatMessageBubbleContentTapAction(content: .none)
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
self.expandedDeletedMessages.insert(messageId)
|
||||
}
|
||||
}, 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
|
||||
if let strongSelf = self, let navigationController = strongSelf.getNavigationController() {
|
||||
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
|
||||
}, editMessageFactCheck: { _ in
|
||||
}, requestMessageUpdate: { _, _ in
|
||||
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, dismissTextInput: {
|
||||
}, 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
|
||||
if let strongSelf = self {
|
||||
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))
|
||||
strongSelf.pushController(browserController)
|
||||
case let .join(link):
|
||||
strongSelf.presentController(JoinLinkPreviewController(context: strongSelf.context, link: link, navigateToPeer: { peer, peekData in
|
||||
if let strongSelf = self {
|
||||
strongSelf.openPeer(peer: peer, peekData: peekData)
|
||||
let context = strongSelf.context
|
||||
let navigationController = strongSelf.getNavigationController()
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, parentNavigationController: strongSelf.getNavigationController()), .window(.root), nil)
|
||||
|> 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)
|
||||
}
|
||||
case let .localization(identifier):
|
||||
strongSelf.presentController(LanguageLinkPreviewController(context: strongSelf.context, identifier: identifier), .window(.root), nil)
|
||||
case .proxy, .confirmationCode, .cancelAccountReset, .share:
|
||||
|
@ -1746,7 +1746,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
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 {
|
||||
itemCountString = "\(topPeer.count - myCountAddition) +\(myCountAddition)"
|
||||
}*/
|
||||
|
@ -711,7 +711,8 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
canSendWhenOnline: false,
|
||||
forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
||||
canMakePaidContent: false,
|
||||
currentPrice: nil
|
||||
currentPrice: nil,
|
||||
hasTimers: false
|
||||
)),
|
||||
hasEntityKeyboard: hasEntityKeyboard,
|
||||
gesture: gesture,
|
||||
|
@ -235,7 +235,8 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
|
||||
canSendWhenOnline: sendWhenOnlineAvailable,
|
||||
forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? [],
|
||||
canMakePaidContent: false,
|
||||
currentPrice: nil
|
||||
currentPrice: nil,
|
||||
hasTimers: false
|
||||
)),
|
||||
hasEntityKeyboard: hasEntityKeyboard,
|
||||
gesture: gesture,
|
||||
|
@ -4748,207 +4748,209 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
isMuted = peerIsMuted
|
||||
}
|
||||
|
||||
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 {
|
||||
let _ = (context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: 0)
|
||||
|> deliverOnMainQueue).startStandalone(completed: {
|
||||
f(.default)
|
||||
})
|
||||
} else {
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteFor, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Mute2d"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
let presetValues: [Int32] = [
|
||||
1 * 60 * 60,
|
||||
8 * 60 * 60,
|
||||
1 * 24 * 60 * 60,
|
||||
7 * 24 * 60 * 60
|
||||
]
|
||||
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
|
||||
if isMuted {
|
||||
let _ = (context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: 0)
|
||||
|> deliverOnMainQueue).startStandalone(completed: {
|
||||
f(.default)
|
||||
})
|
||||
} else {
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
for value in presetValues {
|
||||
subItems.append(.action(ContextMenuActionItem(text: muteForIntervalString(strings: presentationData.strings, value: value), icon: { _ in
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteFor, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Mute2d"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
let presetValues: [Int32] = [
|
||||
1 * 60 * 60,
|
||||
8 * 60 * 60,
|
||||
1 * 24 * 60 * 60,
|
||||
7 * 24 * 60 * 60
|
||||
]
|
||||
|
||||
for value in presetValues {
|
||||
subItems.append(.action(ContextMenuActionItem(text: muteForIntervalString(strings: presentationData.strings, value: value), icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: value).startStandalone()
|
||||
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedFor(mutedForTimeIntervalString(strings: presentationData.strings, value: value)).string, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
}
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteForCustom, icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: value).startStandalone()
|
||||
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_mute_for", scale: 0.066, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedFor(mutedForTimeIntervalString(strings: presentationData.strings, value: value)).string, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
// if let chatListController = chatListController {
|
||||
// openCustomMute(context: context, peerId: peerId, threadId: threadId, baseController: chatListController)
|
||||
// }
|
||||
})))
|
||||
}
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteForCustom, icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
// if let chatListController = 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)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
|
||||
var isSoundEnabled = true
|
||||
switch threadData.notificationSettings.messageSound {
|
||||
case .none:
|
||||
isSoundEnabled = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if case .muted = threadData.notificationSettings.muteState {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: nil).startStandalone()
|
||||
|
||||
let iconColor: UIColor = .white
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
|
||||
items.append(.separator)
|
||||
|
||||
var isSoundEnabled = true
|
||||
switch threadData.notificationSettings.messageSound {
|
||||
case .none:
|
||||
isSoundEnabled = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if case .muted = threadData.notificationSettings.muteState {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: nil).startStandalone()
|
||||
|
||||
let iconColor: UIColor = .white
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [
|
||||
"Middle.Group 1.Fill 1": iconColor,
|
||||
"Top.Group 1.Fill 1": iconColor,
|
||||
"Bottom.Group 1.Fill 1": iconColor,
|
||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
||||
"Line.Group 1.Stroke 1": iconColor
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipUnmuted, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
} else if !isSoundEnabled {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_EnableSound, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: .default).startStandalone()
|
||||
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_DisableSound, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: .none).startStandalone()
|
||||
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_NotificationsCustomize, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipUnmuted, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
} else if !isSoundEnabled {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_EnableSound, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: .default).startStandalone()
|
||||
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_DisableSound, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: .none).startStandalone()
|
||||
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
}
|
||||
|
||||
let _ = (context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global()
|
||||
)
|
||||
|> deliverOnMainQueue).startStandalone(next: { globalSettings in
|
||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_NotificationsCustomize, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerDisplayPreviews: (PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||
peerId, displayPreviews in
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerStoriesMuted: (PeerId, PeerStoryNotificationSettings.Mute) -> Signal<Void, NoError> = {
|
||||
peerId, mute in
|
||||
return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerStoriesHideSender: (PeerId, PeerStoryNotificationSettings.HideSender) -> Signal<Void, NoError> = {
|
||||
peerId, hideSender in
|
||||
return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerStorySound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let defaultSound: PeerMessageSound
|
||||
|
||||
if case .broadcast = channel.info {
|
||||
defaultSound = globalSettings.channels.sound._asMessageSound()
|
||||
} else {
|
||||
defaultSound = globalSettings.groupChats.sound._asMessageSound()
|
||||
}
|
||||
|
||||
let canRemove = false
|
||||
|
||||
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: nil, peer: .channel(channel), threadId: threadId, isStories: nil, canRemove: canRemove, defaultSound: defaultSound, defaultStoriesSound: defaultSound, edit: true, updatePeerSound: { peerId, sound in
|
||||
let _ = (updatePeerSound(peerId, sound)
|
||||
|> deliverOnMainQueue).startStandalone(next: { _ in
|
||||
let _ = (context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global()
|
||||
)
|
||||
|> deliverOnMainQueue).startStandalone(next: { globalSettings in
|
||||
let updatePeerSound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: threadId, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerNotificationInterval: (PeerId, Int32?) -> Signal<Void, NoError> = { peerId, muteInterval in
|
||||
return context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: muteInterval) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerDisplayPreviews: (PeerId, PeerNotificationDisplayPreviews) -> Signal<Void, NoError> = {
|
||||
peerId, displayPreviews in
|
||||
return context.engine.peers.updatePeerDisplayPreviewsSetting(peerId: peerId, threadId: threadId, displayPreviews: displayPreviews) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerStoriesMuted: (PeerId, PeerStoryNotificationSettings.Mute) -> Signal<Void, NoError> = {
|
||||
peerId, mute in
|
||||
return context.engine.peers.updatePeerStoriesMutedSetting(peerId: peerId, mute: mute) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerStoriesHideSender: (PeerId, PeerStoryNotificationSettings.HideSender) -> Signal<Void, NoError> = {
|
||||
peerId, hideSender in
|
||||
return context.engine.peers.updatePeerStoriesHideSenderSetting(peerId: peerId, hideSender: hideSender) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let updatePeerStorySound: (PeerId, PeerMessageSound) -> Signal<Void, NoError> = { peerId, sound in
|
||||
return context.engine.peers.updatePeerStorySoundInteractive(peerId: peerId, sound: sound) |> deliverOnMainQueue
|
||||
}
|
||||
|
||||
let defaultSound: PeerMessageSound
|
||||
|
||||
if case .broadcast = channel.info {
|
||||
defaultSound = globalSettings.channels.sound._asMessageSound()
|
||||
} else {
|
||||
defaultSound = globalSettings.groupChats.sound._asMessageSound()
|
||||
}
|
||||
|
||||
let canRemove = false
|
||||
|
||||
let exceptionController = notificationPeerExceptionController(context: context, updatedPresentationData: nil, peer: .channel(channel), threadId: threadId, isStories: nil, canRemove: canRemove, defaultSound: defaultSound, defaultStoriesSound: defaultSound, edit: true, updatePeerSound: { peerId, sound in
|
||||
let _ = (updatePeerSound(peerId, sound)
|
||||
|> deliverOnMainQueue).startStandalone(next: { _ in
|
||||
})
|
||||
}, updatePeerNotificationInterval: { [weak self] peerId, muteInterval in
|
||||
let _ = (updatePeerNotificationInterval(peerId, muteInterval)
|
||||
|> deliverOnMainQueue).startStandalone(next: { _ in
|
||||
if let muteInterval = muteInterval, muteInterval == Int32.max {
|
||||
let iconColor: UIColor = .white
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
||||
"Middle.Group 1.Fill 1": iconColor,
|
||||
"Top.Group 1.Fill 1": iconColor,
|
||||
"Bottom.Group 1.Fill 1": iconColor,
|
||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
||||
"Line.Group 1.Stroke 1": iconColor
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}, updatePeerDisplayPreviews: { peerId, displayPreviews in
|
||||
let _ = (updatePeerDisplayPreviews(peerId, displayPreviews)
|
||||
|> deliverOnMainQueue).startStandalone(next: { _ in
|
||||
|
||||
})
|
||||
}, updatePeerStoriesMuted: { peerId, mute in
|
||||
let _ = (updatePeerStoriesMuted(peerId, mute)
|
||||
|> deliverOnMainQueue).startStandalone()
|
||||
}, updatePeerStoriesHideSender: { peerId, hideSender in
|
||||
let _ = (updatePeerStoriesHideSender(peerId, hideSender)
|
||||
|> deliverOnMainQueue).startStandalone()
|
||||
}, updatePeerStorySound: { peerId, sound in
|
||||
let _ = (updatePeerStorySound(peerId, sound)
|
||||
|> deliverOnMainQueue).startStandalone()
|
||||
}, removePeerFromExceptions: {
|
||||
}, modifiedPeer: {
|
||||
})
|
||||
}, updatePeerNotificationInterval: { [weak self] peerId, muteInterval in
|
||||
let _ = (updatePeerNotificationInterval(peerId, muteInterval)
|
||||
|> deliverOnMainQueue).startStandalone(next: { _ in
|
||||
if let muteInterval = muteInterval, muteInterval == Int32.max {
|
||||
let iconColor: UIColor = .white
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
||||
"Middle.Group 1.Fill 1": iconColor,
|
||||
"Top.Group 1.Fill 1": iconColor,
|
||||
"Bottom.Group 1.Fill 1": iconColor,
|
||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
||||
"Line.Group 1.Stroke 1": iconColor
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}, updatePeerDisplayPreviews: { peerId, displayPreviews in
|
||||
let _ = (updatePeerDisplayPreviews(peerId, displayPreviews)
|
||||
|> deliverOnMainQueue).startStandalone(next: { _ in
|
||||
|
||||
})
|
||||
}, updatePeerStoriesMuted: { peerId, mute in
|
||||
let _ = (updatePeerStoriesMuted(peerId, mute)
|
||||
|> deliverOnMainQueue).startStandalone()
|
||||
}, updatePeerStoriesHideSender: { peerId, hideSender in
|
||||
let _ = (updatePeerStoriesHideSender(peerId, hideSender)
|
||||
|> deliverOnMainQueue).startStandalone()
|
||||
}, updatePeerStorySound: { peerId, sound in
|
||||
let _ = (updatePeerStorySound(peerId, sound)
|
||||
|> deliverOnMainQueue).startStandalone()
|
||||
}, removePeerFromExceptions: {
|
||||
}, modifiedPeer: {
|
||||
exceptionController.navigationPresentation = .modal
|
||||
self?.push(exceptionController)
|
||||
})
|
||||
exceptionController.navigationPresentation = .modal
|
||||
self?.push(exceptionController)
|
||||
})
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: Int32.max).startStandalone()
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor)
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: threadId, muteInterval: Int32.max).startStandalone()
|
||||
|
||||
let iconColor: UIColor = .white
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
||||
"Middle.Group 1.Fill 1": iconColor,
|
||||
"Top.Group 1.Fill 1": iconColor,
|
||||
"Bottom.Group 1.Fill 1": iconColor,
|
||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
||||
"Line.Group 1.Stroke 1": iconColor
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
|
||||
let iconColor: UIColor = .white
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [
|
||||
"Middle.Group 1.Fill 1": iconColor,
|
||||
"Top.Group 1.Fill 1": iconColor,
|
||||
"Bottom.Group 1.Fill 1": iconColor,
|
||||
"EXAMPLE.Group 1.Fill 1": iconColor,
|
||||
"Line.Group 1.Stroke 1": iconColor
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
|
||||
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
|
||||
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()
|
||||
})))
|
||||
}
|
||||
// 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
|
||||
|
@ -239,6 +239,15 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
|
||||
useBrowserScreen = true
|
||||
}
|
||||
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
|
||||
if file.mimeType == "application/pdf" {
|
||||
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 {
|
||||
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:
|
||||
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 browserController = context.sharedContext.makeInstantPageController(context: context, webPage: webPage, anchor: anchor, sourceLocation: sourceLocation)
|
||||
(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:
|
||||
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
|
||||
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:
|
||||
break
|
||||
|
Loading…
x
Reference in New Issue
Block a user