mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Merge commit 'bd1cbdae5ab641d9b946edafd59e92e21d94f3f9'
This commit is contained in:
commit
2f9d5c41e3
@ -13138,7 +13138,7 @@ Sorry for the inconvenience.";
|
|||||||
"AttachmentMenu.AddDocument" = "Add Document";
|
"AttachmentMenu.AddDocument" = "Add Document";
|
||||||
|
|
||||||
"Chat.BotAd.Title" = "Ad";
|
"Chat.BotAd.Title" = "Ad";
|
||||||
"Chat.BotAd.Remove" = "remove";
|
"Chat.BotAd.WhatIsThis" = "what's this?";
|
||||||
|
|
||||||
"ChatList.Search.TopAppsInfo" = "Which apps are included here? [Learn >]()";
|
"ChatList.Search.TopAppsInfo" = "Which apps are included here? [Learn >]()";
|
||||||
|
|
||||||
|
|||||||
@ -974,7 +974,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal<ChatAvailableMessageActions, NoError>
|
func chatAvailableMessageActions(engine: TelegramEngine, accountPeerId: EnginePeer.Id, messageIds: Set<EngineMessage.Id>, messages: [EngineMessage.Id: EngineMessage], peers: [EnginePeer.Id: EnginePeer]) -> Signal<ChatAvailableMessageActions, NoError>
|
||||||
func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
|
func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
|
||||||
func resolveUrlWithProgress(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolveUrlResult, NoError>
|
func resolveUrlWithProgress(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolveUrlResult, NoError>
|
||||||
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?, completion: (() -> Void)?)
|
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, forceUpdate: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?, completion: (() -> Void)?)
|
||||||
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
||||||
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
|
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
|
||||||
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
||||||
|
|||||||
@ -149,6 +149,7 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
|||||||
@ -965,7 +965,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
|
|||||||
default:
|
default:
|
||||||
strongSelf.loadProgress.set(1.0)
|
strongSelf.loadProgress.set(1.0)
|
||||||
strongSelf.minimize()
|
strongSelf.minimize()
|
||||||
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), forceExternal: false, openPeer: { peer, navigation in
|
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
switch navigation {
|
switch navigation {
|
||||||
case let .chat(_, subject, peekData):
|
case let .chat(_, subject, peekData):
|
||||||
if let navigationController = strongSelf.getNavigationController() {
|
if let navigationController = strongSelf.getNavigationController() {
|
||||||
|
|||||||
@ -203,7 +203,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
let _ = openUserGeneratedUrl(context: context, peerId: nil, url: url, concealed: false, present: { c in
|
let _ = openUserGeneratedUrl(context: context, peerId: nil, url: url, concealed: false, present: { c in
|
||||||
present(c, nil)
|
present(c, nil)
|
||||||
}, openResolved: { [weak self] resolved in
|
}, openResolved: { [weak self] resolved in
|
||||||
context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peerId, navigation in
|
context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peerId, navigation in
|
||||||
|
|
||||||
},
|
},
|
||||||
sendFile: nil,
|
sendFile: nil,
|
||||||
@ -634,6 +634,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
|
|
||||||
override public func searchTextUpdated(text: String) {
|
override public func searchTextUpdated(text: String) {
|
||||||
let searchQuery: String? = !text.isEmpty ? text : nil
|
let searchQuery: String? = !text.isEmpty ? text : nil
|
||||||
|
|
||||||
|
if !text.hasPrefix("#") && self.paneContainerNode.currentPaneKey == .publicPosts {
|
||||||
|
self.paneContainerNode.requestSelectPane(.chats)
|
||||||
|
}
|
||||||
|
|
||||||
self.searchQuery.set(.single(searchQuery))
|
self.searchQuery.set(.single(searchQuery))
|
||||||
self.searchQueryValue = searchQuery
|
self.searchQueryValue = searchQuery
|
||||||
|
|
||||||
|
|||||||
@ -1340,6 +1340,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
private var searchQueryValue: String?
|
private var searchQueryValue: String?
|
||||||
private var searchOptionsValue: ChatListSearchOptions?
|
private var searchOptionsValue: ChatListSearchOptions?
|
||||||
|
|
||||||
|
var isCurrent: Bool = false
|
||||||
|
|
||||||
private let _isSearching = ValuePromise<Bool>(false, ignoreRepeated: true)
|
private let _isSearching = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
public var isSearching: Signal<Bool, NoError> {
|
public var isSearching: Signal<Bool, NoError> {
|
||||||
return self._isSearching.get()
|
return self._isSearching.get()
|
||||||
@ -2188,12 +2190,53 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
|
|
||||||
let foundPublicMessages: Signal<([FoundRemoteMessages], Bool), NoError>
|
let foundPublicMessages: Signal<([FoundRemoteMessages], Bool), NoError>
|
||||||
if key == .chats || key == .publicPosts, let query, query.hasPrefix("#") {
|
if key == .chats || key == .publicPosts, let query, query.hasPrefix("#") {
|
||||||
let searchSignal = context.engine.messages.searchHashtagPosts(hashtag: finalQuery, state: nil, limit: 50)
|
let searchSignal = context.engine.messages.searchHashtagPosts(hashtag: finalQuery, state: nil, limit: 10)
|
||||||
|
|
||||||
|
let loadMore: Signal<([FoundRemoteMessages], Bool), NoError>
|
||||||
|
if key == .publicPosts {
|
||||||
|
loadMore = searchContexts.get()
|
||||||
|
|> mapToSignal { searchContexts -> Signal<([FoundRemoteMessages], Bool), NoError> in
|
||||||
|
let i = 0
|
||||||
|
if let searchContext = searchContexts[i], searchContext.result.hasMore {
|
||||||
|
if let _ = searchContext.loadMoreIndex {
|
||||||
|
return context.engine.messages.searchHashtagPosts(hashtag: finalQuery, state: searchContext.result.state, limit: 80)
|
||||||
|
|> map { result, updatedState -> ChatListSearchMessagesResult in
|
||||||
|
return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.map({ EngineMessage($0) }).sorted(by: { $0.index > $1.index }), readStates: result.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadInfo: result.threadInfo, hasMore: !result.completed, totalCount: result.totalCount, state: updatedState)
|
||||||
|
}
|
||||||
|
|> mapToSignal { foundMessages -> Signal<([FoundRemoteMessages], Bool), NoError> in
|
||||||
|
updateSearchContexts { previous in
|
||||||
|
let updated = ChatListSearchMessagesContext(result: foundMessages, loadMoreIndex: nil)
|
||||||
|
var previous = previous
|
||||||
|
previous[i] = updated
|
||||||
|
return (previous, true)
|
||||||
|
}
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var currentResults: [FoundRemoteMessages] = []
|
||||||
|
if let currentContext = searchContexts[i] {
|
||||||
|
currentResults.append(FoundRemoteMessages(messages: currentContext.result.messages, readCounters: currentContext.result.readStates, threadsData: currentContext.result.threadInfo, totalCount: currentContext.result.totalCount))
|
||||||
|
}
|
||||||
|
return .single((currentResults, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loadMore = .complete()
|
||||||
|
}
|
||||||
|
|
||||||
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], true))
|
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], true))
|
||||||
|> then(
|
|> then(
|
||||||
searchSignal
|
searchSignal
|
||||||
|> map { result -> ([FoundRemoteMessages], Bool) in
|
|> map { result -> ([FoundRemoteMessages], Bool) in
|
||||||
|
updateSearchContexts { _ in
|
||||||
|
var resultContexts: [Int: ChatListSearchMessagesContext] = [:]
|
||||||
|
resultContexts[0] = ChatListSearchMessagesContext(result: ChatListSearchMessagesResult(query: finalQuery, messages: result.0.messages.map({ EngineMessage($0) }).sorted(by: { $0.index > $1.index }), readStates: result.0.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadInfo: result.0.threadInfo, hasMore: !result.0.completed, totalCount: result.0.totalCount, state: result.1), loadMoreIndex: nil)
|
||||||
|
return (resultContexts, true)
|
||||||
|
}
|
||||||
|
|
||||||
let foundMessages = result.0
|
let foundMessages = result.0
|
||||||
let messages: [EngineMessage]
|
let messages: [EngineMessage]
|
||||||
if key == .chats {
|
if key == .chats {
|
||||||
@ -2204,6 +2247,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
return ([FoundRemoteMessages(messages: messages, readCounters: foundMessages.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadsData: foundMessages.threadInfo, totalCount: foundMessages.totalCount)], false)
|
return ([FoundRemoteMessages(messages: messages, readCounters: foundMessages.readStates.mapValues { EnginePeerReadCounters(state: $0, isMuted: false) }, threadsData: foundMessages.threadInfo, totalCount: foundMessages.totalCount)], false)
|
||||||
}
|
}
|
||||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
|> delay(0.2, queue: Queue.concurrentDefaultQueue())
|
||||||
|
|> then(loadMore)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], false))
|
foundPublicMessages = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], false))
|
||||||
@ -2380,7 +2424,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||||||
foundThreads
|
foundThreads
|
||||||
)
|
)
|
||||||
|> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, foundPublicMessages, presentationData, searchState, selectionState, resolvedMessage, recentPeers, allAndFoundThreads -> ([ChatListSearchEntry], Bool)? in
|
|> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, foundPublicMessages, presentationData, searchState, selectionState, resolvedMessage, recentPeers, allAndFoundThreads -> ([ChatListSearchEntry], Bool)? in
|
||||||
let isSearching = foundRemotePeers.2 || foundRemoteMessages.1
|
let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 || foundPublicMessages.1
|
||||||
var entries: [ChatListSearchEntry] = []
|
var entries: [ChatListSearchEntry] = []
|
||||||
var index = 0
|
var index = 0
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import MultiAnimationRenderer
|
|||||||
|
|
||||||
protocol ChatListSearchPaneNode: ASDisplayNode {
|
protocol ChatListSearchPaneNode: ASDisplayNode {
|
||||||
var isReady: Signal<Bool, NoError> { get }
|
var isReady: Signal<Bool, NoError> { get }
|
||||||
|
var isCurrent: Bool { get set }
|
||||||
|
|
||||||
func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition)
|
func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition)
|
||||||
func scrollToTop() -> Bool
|
func scrollToTop() -> Bool
|
||||||
@ -568,6 +569,7 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, ASGestureRecognizerD
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
pane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition)
|
pane.update(size: paneFrame.size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, presentationData: presentationData, synchronous: paneWasAdded, transition: paneTransition)
|
||||||
|
pane.node.isCurrent = key == self.currentPaneKey
|
||||||
if paneWasAdded && key == self.currentPaneKey {
|
if paneWasAdded && key == self.currentPaneKey {
|
||||||
pane.node.didBecomeFocused()
|
pane.node.didBecomeFocused()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -285,7 +285,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
UIPasteboard.general.setData(data, forPasteboardType: dataType)
|
UIPasteboard.general.setData(data, forPasteboardType: dataType)
|
||||||
}
|
}
|
||||||
context.sharedContext.openResolvedUrl(.importStickers, context: context, urlContext: .generic, navigationController: arguments.getNavigationController(), forceExternal: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { c, a in arguments.presentController(c, a as? ViewControllerPresentationArguments) }, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
context.sharedContext.openResolvedUrl(.importStickers, context: context, urlContext: .generic, navigationController: arguments.getNavigationController(), forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { c, a in arguments.presentController(c, a as? ViewControllerPresentationArguments) }, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
case .sendLogs:
|
case .sendLogs:
|
||||||
|
|||||||
@ -1345,7 +1345,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
strongSelf.loadProgress.set(1.0)
|
strongSelf.loadProgress.set(1.0)
|
||||||
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), forceExternal: false, openPeer: { peer, navigation in
|
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
switch navigation {
|
switch navigation {
|
||||||
case let .chat(_, subject, peekData):
|
case let .chat(_, subject, peekData):
|
||||||
if let navigationController = strongSelf.getNavigationController() {
|
if let navigationController = strongSelf.getNavigationController() {
|
||||||
|
|||||||
@ -625,7 +625,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
|||||||
if let signal = signal {
|
if let signal = signal {
|
||||||
let _ = (signal
|
let _ = (signal
|
||||||
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak controller] c, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak controller] c, arguments in
|
||||||
controller?.push(c)
|
controller?.push(c)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
|
|||||||
@ -2736,7 +2736,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
if let signal = signal {
|
if let signal = signal {
|
||||||
let _ = (signal
|
let _ = (signal
|
||||||
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak controller] c, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak controller] c, arguments in
|
||||||
controller?.push(c)
|
controller?.push(c)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
|
|||||||
@ -899,7 +899,7 @@ private final class QrCodeScanScreenNode: ViewControllerTracingNode, ASScrollVie
|
|||||||
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { [weak self] peer, navigation in
|
self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { [weak self] peer, navigation in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -315,7 +315,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
|
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
@ -356,7 +356,7 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
|
|||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
|
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
|
|||||||
@ -222,7 +222,7 @@ public func logoutOptionsController(context: AccountContext, navigationControlle
|
|||||||
controller?.dismiss()
|
controller?.dismiss()
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
|
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
||||||
pushControllerImpl?(controller)
|
pushControllerImpl?(controller)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
|
|||||||
@ -1068,7 +1068,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList
|
|||||||
let faq = SettingsSearchableItem(id: .faq(0), title: strings.Settings_FAQ, alternate: synonyms(strings.SettingsSearch_Synonyms_FAQ), icon: .faq, breadcrumbs: [], present: { context, navigationController, present in
|
let faq = SettingsSearchableItem(id: .faq(0), title: strings.Settings_FAQ, alternate: synonyms(strings.SettingsSearch_Synonyms_FAQ), icon: .faq, breadcrumbs: [], present: { context, navigationController, present in
|
||||||
let _ = (cachedFaqInstantPage(context: context)
|
let _ = (cachedFaqInstantPage(context: context)
|
||||||
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
|> deliverOnMainQueue).start(next: { resolvedUrl in
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
||||||
present(.push, controller)
|
present(.push, controller)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
|
|||||||
@ -389,15 +389,14 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||||||
return updatedOffset
|
return updatedOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ignoreCache = controller?.ignoreCache ?? false
|
||||||
|
|
||||||
let fetchedStickerPacks: Signal<[LoadedStickerPack], NoError> = combineLatest(stickerPacks.map { packReference in
|
let fetchedStickerPacks: Signal<[LoadedStickerPack], NoError> = combineLatest(stickerPacks.map { packReference in
|
||||||
for pack in loadedStickerPacks {
|
for pack in loadedStickerPacks {
|
||||||
if case let .result(info, _, _) = pack, case let .id(id, _) = packReference, info.id.id == id {
|
if case let .result(info, _, _) = pack, case let .id(id, _) = packReference, info.id.id == id {
|
||||||
return .single(pack)
|
return .single(pack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: true)
|
return context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: true, ignoreCache: ignoreCache)
|
||||||
})
|
})
|
||||||
|
|
||||||
self.itemsDisposable = combineLatest(queue: Queue.mainQueue(), fetchedStickerPacks, context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))).start(next: { [weak self] contents, peer in
|
self.itemsDisposable = combineLatest(queue: Queue.mainQueue(), fetchedStickerPacks, context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))).start(next: { [weak self] contents, peer in
|
||||||
@ -2686,13 +2685,14 @@ public final class StickerPackScreenImpl: ViewController, StickerPackScreen {
|
|||||||
private var animatedIn: Bool = false
|
private var animatedIn: Bool = false
|
||||||
fileprivate var initialIsEditing: Bool = false
|
fileprivate var initialIsEditing: Bool = false
|
||||||
fileprivate var expandIfNeeded: Bool = false
|
fileprivate var expandIfNeeded: Bool = false
|
||||||
|
fileprivate let ignoreCache: Bool
|
||||||
|
|
||||||
let animationCache: AnimationCache
|
let animationCache: AnimationCache
|
||||||
let animationRenderer: MultiAnimationRenderer
|
let animationRenderer: MultiAnimationRenderer
|
||||||
|
|
||||||
let mainActionTitle: String?
|
let mainActionTitle: String?
|
||||||
let actionTitle: String?
|
let actionTitle: String?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||||
@ -2703,6 +2703,7 @@ public final class StickerPackScreenImpl: ViewController, StickerPackScreen {
|
|||||||
actionTitle: String? = nil,
|
actionTitle: String? = nil,
|
||||||
isEditing: Bool = false,
|
isEditing: Bool = false,
|
||||||
expandIfNeeded: Bool = false,
|
expandIfNeeded: Bool = false,
|
||||||
|
ignoreCache: Bool = false,
|
||||||
parentNavigationController: NavigationController? = nil,
|
parentNavigationController: NavigationController? = nil,
|
||||||
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil,
|
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil,
|
||||||
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?,
|
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?,
|
||||||
@ -2718,6 +2719,7 @@ public final class StickerPackScreenImpl: ViewController, StickerPackScreen {
|
|||||||
self.actionTitle = actionTitle
|
self.actionTitle = actionTitle
|
||||||
self.initialIsEditing = isEditing
|
self.initialIsEditing = isEditing
|
||||||
self.expandIfNeeded = expandIfNeeded
|
self.expandIfNeeded = expandIfNeeded
|
||||||
|
self.ignoreCache = ignoreCache
|
||||||
self.parentNavigationController = parentNavigationController
|
self.parentNavigationController = parentNavigationController
|
||||||
self.sendSticker = sendSticker
|
self.sendSticker = sendSticker
|
||||||
self.sendEmoji = sendEmoji
|
self.sendEmoji = sendEmoji
|
||||||
@ -2952,6 +2954,7 @@ public func StickerPackScreen(
|
|||||||
actionTitle: String? = nil,
|
actionTitle: String? = nil,
|
||||||
isEditing: Bool = false,
|
isEditing: Bool = false,
|
||||||
expandIfNeeded: Bool = false,
|
expandIfNeeded: Bool = false,
|
||||||
|
ignoreCache: Bool = false,
|
||||||
parentNavigationController: NavigationController? = nil,
|
parentNavigationController: NavigationController? = nil,
|
||||||
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil,
|
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil,
|
||||||
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)? = nil,
|
sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)? = nil,
|
||||||
@ -2969,6 +2972,7 @@ public func StickerPackScreen(
|
|||||||
actionTitle: actionTitle,
|
actionTitle: actionTitle,
|
||||||
isEditing: isEditing,
|
isEditing: isEditing,
|
||||||
expandIfNeeded: expandIfNeeded,
|
expandIfNeeded: expandIfNeeded,
|
||||||
|
ignoreCache: ignoreCache,
|
||||||
parentNavigationController: parentNavigationController,
|
parentNavigationController: parentNavigationController,
|
||||||
sendSticker: sendSticker,
|
sendSticker: sendSticker,
|
||||||
sendEmoji: sendEmoji,
|
sendEmoji: sendEmoji,
|
||||||
|
|||||||
@ -62,10 +62,10 @@ func cacheStickerPack(transaction: Transaction, info: StickerPackCollectionInfo,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference, forceRemote: Bool) -> Signal<CachedStickerPackResult, NoError> {
|
func _internal_cachedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference, forceRemote: Bool, ignoreCache: Bool = false) -> Signal<CachedStickerPackResult, NoError> {
|
||||||
return postbox.transaction { transaction -> CachedStickerPackResult? in
|
return postbox.transaction { transaction -> CachedStickerPackResult? in
|
||||||
if let (info, items, local) = cachedStickerPack(transaction: transaction, reference: reference) {
|
if let (info, items, local) = cachedStickerPack(transaction: transaction, reference: reference) {
|
||||||
if local {
|
if local && !ignoreCache {
|
||||||
return .result(info, items, true)
|
return .result(info, items, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,7 +123,7 @@ func updatedRemoteStickerPack(postbox: Postbox, network: Network, reference: Sti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func _internal_loadedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference, forceActualized: Bool) -> Signal<LoadedStickerPack, NoError> {
|
func _internal_loadedStickerPack(postbox: Postbox, network: Network, reference: StickerPackReference, forceActualized: Bool, ignoreCache: Bool = false) -> Signal<LoadedStickerPack, NoError> {
|
||||||
return _internal_cachedStickerPack(postbox: postbox, network: network, reference: reference, forceRemote: forceActualized)
|
return _internal_cachedStickerPack(postbox: postbox, network: network, reference: reference, forceRemote: forceActualized)
|
||||||
|> map { result -> LoadedStickerPack in
|
|> map { result -> LoadedStickerPack in
|
||||||
switch result {
|
switch result {
|
||||||
|
|||||||
@ -22,8 +22,8 @@ public extension TelegramEngine {
|
|||||||
return _internal_cachedStickerPack(postbox: self.account.postbox, network: self.account.network, reference: reference, forceRemote: forceRemote)
|
return _internal_cachedStickerPack(postbox: self.account.postbox, network: self.account.network, reference: reference, forceRemote: forceRemote)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadedStickerPack(reference: StickerPackReference, forceActualized: Bool) -> Signal<LoadedStickerPack, NoError> {
|
public func loadedStickerPack(reference: StickerPackReference, forceActualized: Bool, ignoreCache: Bool = false) -> Signal<LoadedStickerPack, NoError> {
|
||||||
return _internal_loadedStickerPack(postbox: self.account.postbox, network: self.account.network, reference: reference, forceActualized: forceActualized)
|
return _internal_loadedStickerPack(postbox: self.account.postbox, network: self.account.network, reference: reference, forceActualized: forceActualized, ignoreCache: ignoreCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func randomGreetingSticker() -> Signal<FoundStickerItem?, NoError> {
|
public func randomGreetingSticker() -> Signal<FoundStickerItem?, NoError> {
|
||||||
|
|||||||
@ -29,6 +29,9 @@ swift_library(
|
|||||||
"//submodules/AppBundle",
|
"//submodules/AppBundle",
|
||||||
"//submodules/TelegramStringFormatting",
|
"//submodules/TelegramStringFormatting",
|
||||||
"//submodules/PresentationDataUtils",
|
"//submodules/PresentationDataUtils",
|
||||||
|
"//submodules/ContextUI",
|
||||||
|
"//submodules/UndoUI",
|
||||||
|
"//submodules/TelegramUI/Components/Ads/AdsReportScreen",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -618,6 +618,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
@ -1341,7 +1342,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
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:
|
||||||
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), forceExternal: false, openPeer: { peer, _ in
|
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), forceExternal: false, forceUpdate: false, openPeer: { peer, _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.openPeer(peer: peer)
|
strongSelf.openPeer(peer: peer)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -475,6 +475,7 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
|||||||
@ -254,6 +254,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||||||
public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void
|
public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void
|
||||||
public let activateAdAction: (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void
|
public let activateAdAction: (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void
|
||||||
public let adContextAction: (Message, ASDisplayNode, ContextGesture?) -> Void
|
public let adContextAction: (Message, ASDisplayNode, ContextGesture?) -> Void
|
||||||
|
public let removeAd: (Data) -> Void
|
||||||
public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void
|
public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void
|
||||||
public let saveMediaToFiles: (EngineMessage.Id) -> Void
|
public let saveMediaToFiles: (EngineMessage.Id) -> Void
|
||||||
public let openNoAdsDemo: () -> Void
|
public let openNoAdsDemo: () -> Void
|
||||||
@ -386,6 +387,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||||||
openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void,
|
openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void,
|
||||||
activateAdAction: @escaping (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void,
|
activateAdAction: @escaping (EngineMessage.Id, Promise<Bool>?, Bool, Bool) -> Void,
|
||||||
adContextAction: @escaping (Message, ASDisplayNode, ContextGesture?) -> Void,
|
adContextAction: @escaping (Message, ASDisplayNode, ContextGesture?) -> Void,
|
||||||
|
removeAd: @escaping (Data) -> Void,
|
||||||
openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void,
|
openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void,
|
||||||
saveMediaToFiles: @escaping (EngineMessage.Id) -> Void,
|
saveMediaToFiles: @escaping (EngineMessage.Id) -> Void,
|
||||||
openNoAdsDemo: @escaping () -> Void,
|
openNoAdsDemo: @escaping () -> Void,
|
||||||
@ -497,6 +499,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
|||||||
self.openWebView = openWebView
|
self.openWebView = openWebView
|
||||||
self.activateAdAction = activateAdAction
|
self.activateAdAction = activateAdAction
|
||||||
self.adContextAction = adContextAction
|
self.adContextAction = adContextAction
|
||||||
|
self.removeAd = removeAd
|
||||||
self.openRequestedPeerSelection = openRequestedPeerSelection
|
self.openRequestedPeerSelection = openRequestedPeerSelection
|
||||||
self.saveMediaToFiles = saveMediaToFiles
|
self.saveMediaToFiles = saveMediaToFiles
|
||||||
self.openNoAdsDemo = openNoAdsDemo
|
self.openNoAdsDemo = openNoAdsDemo
|
||||||
|
|||||||
@ -124,6 +124,39 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
private let tabSelector = ComponentView<Empty>()
|
private let tabSelector = ComponentView<Empty>()
|
||||||
private var starsFilter: StarsFilter = .all
|
private var starsFilter: StarsFilter = .all
|
||||||
|
|
||||||
|
private var _effectiveStarGifts: ([StarGift], StarsFilter)?
|
||||||
|
private var effectiveStarGifts: [StarGift]? {
|
||||||
|
get {
|
||||||
|
if case .all = self.starsFilter {
|
||||||
|
return self.state?.starGifts
|
||||||
|
} else {
|
||||||
|
if let (currentGifts, currentFilter) = self._effectiveStarGifts, currentFilter == self.starsFilter {
|
||||||
|
return currentGifts
|
||||||
|
} else if let allGifts = self.state?.starGifts {
|
||||||
|
let filteredGifts: [StarGift] = allGifts.filter {
|
||||||
|
switch self.starsFilter {
|
||||||
|
case .all:
|
||||||
|
return true
|
||||||
|
case .limited:
|
||||||
|
if $0.availability != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case let .stars(stars):
|
||||||
|
if $0.price == stars {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
self._effectiveStarGifts = (filteredGifts, self.starsFilter)
|
||||||
|
return filteredGifts
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var isUpdating: Bool = false
|
private var isUpdating: Bool = false
|
||||||
|
|
||||||
private var starsStateDisposable: Disposable?
|
private var starsStateDisposable: Disposable?
|
||||||
@ -243,7 +276,7 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let visibleBounds = self.scrollView.bounds.insetBy(dx: 0.0, dy: -10.0)
|
let visibleBounds = self.scrollView.bounds.insetBy(dx: 0.0, dy: -10.0)
|
||||||
if let starGifts = self.state?.starGifts {
|
if let starGifts = self.effectiveStarGifts {
|
||||||
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
||||||
|
|
||||||
let optionSpacing: CGFloat = 10.0
|
let optionSpacing: CGFloat = 10.0
|
||||||
@ -262,19 +295,6 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isVisible {
|
if isVisible {
|
||||||
switch self.starsFilter {
|
|
||||||
case .all:
|
|
||||||
break
|
|
||||||
case .limited:
|
|
||||||
if gift.availability == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case let .stars(stars):
|
|
||||||
if gift.price != stars {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let itemId = AnyHashable(gift.id)
|
let itemId = AnyHashable(gift.id)
|
||||||
validIds.append(itemId)
|
validIds.append(itemId)
|
||||||
|
|
||||||
@ -898,9 +918,9 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
contentHeight += tabSelectorSize.height
|
contentHeight += tabSelectorSize.height
|
||||||
contentHeight += 19.0
|
contentHeight += 19.0
|
||||||
|
|
||||||
if let starGifts = state.starGifts {
|
if let starGifts = self.effectiveStarGifts {
|
||||||
self.starsItemsOrigin = contentHeight
|
self.starsItemsOrigin = contentHeight
|
||||||
|
|
||||||
let starsOptionSize = CGSize(width: optionWidth, height: 154.0)
|
let starsOptionSize = CGSize(width: optionWidth, height: 154.0)
|
||||||
contentHeight += ceil(CGFloat(starGifts.count) / 3.0) * starsOptionSize.height
|
contentHeight += ceil(CGFloat(starGifts.count) / 3.0) * starsOptionSize.height
|
||||||
contentHeight += 66.0
|
contentHeight += 66.0
|
||||||
|
|||||||
@ -417,6 +417,33 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func previewTap() {
|
||||||
|
func hasFirstResponder(_ view: UIView) -> Bool {
|
||||||
|
if view.isFirstResponder {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for subview in view.subviews {
|
||||||
|
if hasFirstResponder(subview) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currentInputMode = .keyboard
|
||||||
|
if hasFirstResponder(self) {
|
||||||
|
if let titleView = self.introSection.findTaggedView(tag: self.textInputTag) as? ListMultilineTextFieldItemComponent.View {
|
||||||
|
if titleView.isActive {
|
||||||
|
titleView.deactivateInput()
|
||||||
|
} else {
|
||||||
|
self.endEditing(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.state?.updated(transition: .spring(duration: 0.4))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func update(component: GiftSetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
func update(component: GiftSetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||||
self.isUpdating = true
|
self.isUpdating = true
|
||||||
defer {
|
defer {
|
||||||
@ -693,28 +720,7 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
))))
|
))))
|
||||||
self.resetText = nil
|
self.resetText = nil
|
||||||
|
|
||||||
|
|
||||||
var inputHeight: CGFloat = 0.0
|
|
||||||
inputHeight += self.updateInputMediaNode(
|
|
||||||
component: component,
|
|
||||||
availableSize: availableSize,
|
|
||||||
bottomInset: environment.safeInsets.bottom,
|
|
||||||
inputHeight: 0.0,
|
|
||||||
effectiveInputHeight: environment.deviceMetrics.standardInputHeight(inLandscape: false),
|
|
||||||
metrics: environment.metrics,
|
|
||||||
deviceMetrics: environment.deviceMetrics,
|
|
||||||
transition: transition
|
|
||||||
)
|
|
||||||
if self.inputMediaNode == nil {
|
|
||||||
if environment.inputHeight.isZero && self.textInputState.isEditing, let previousInputHeight = self.previousInputHeight {
|
|
||||||
inputHeight = previousInputHeight
|
|
||||||
} else {
|
|
||||||
inputHeight = environment.inputHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let peerName = self.peerMap[component.peerId]?.compactDisplayTitle ?? ""
|
let peerName = self.peerMap[component.peerId]?.compactDisplayTitle ?? ""
|
||||||
|
|
||||||
let introFooter: AnyComponent<Empty>?
|
let introFooter: AnyComponent<Empty>?
|
||||||
switch component.subject {
|
switch component.subject {
|
||||||
case .premium:
|
case .premium:
|
||||||
@ -751,7 +757,26 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
contentHeight += introSectionSize.height
|
contentHeight += introSectionSize.height
|
||||||
contentHeight += sectionSpacing
|
contentHeight += sectionSpacing
|
||||||
|
|
||||||
|
var inputHeight: CGFloat = 0.0
|
||||||
|
inputHeight += self.updateInputMediaNode(
|
||||||
|
component: component,
|
||||||
|
availableSize: availableSize,
|
||||||
|
bottomInset: environment.safeInsets.bottom,
|
||||||
|
inputHeight: 0.0,
|
||||||
|
effectiveInputHeight: environment.deviceMetrics.standardInputHeight(inLandscape: false),
|
||||||
|
metrics: environment.metrics,
|
||||||
|
deviceMetrics: environment.deviceMetrics,
|
||||||
|
transition: transition
|
||||||
|
)
|
||||||
|
if self.inputMediaNode == nil {
|
||||||
|
if environment.inputHeight.isZero && self.textInputState.isEditing, let previousInputHeight = self.previousInputHeight {
|
||||||
|
inputHeight = previousInputHeight
|
||||||
|
} else {
|
||||||
|
inputHeight = environment.inputHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let listItemParams = ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
let listItemParams = ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true)
|
||||||
if let accountPeer = self.peerMap[component.context.account.peerId] {
|
if let accountPeer = self.peerMap[component.context.account.peerId] {
|
||||||
let subject: ChatGiftPreviewItem.Subject
|
let subject: ChatGiftPreviewItem.Subject
|
||||||
@ -793,6 +818,8 @@ final class GiftSetupScreenComponent: Component {
|
|||||||
if introContentView.superview == nil {
|
if introContentView.superview == nil {
|
||||||
if let placeholderView = self.introSection.findTaggedView(tag: self.introPlaceholderTag) {
|
if let placeholderView = self.introSection.findTaggedView(tag: self.introPlaceholderTag) {
|
||||||
placeholderView.addSubview(introContentView)
|
placeholderView.addSubview(introContentView)
|
||||||
|
|
||||||
|
placeholderView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.previewTap)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transition.setFrame(view: introContentView, frame: CGRect(origin: CGPoint(), size: introContentSize))
|
transition.setFrame(view: introContentView, frame: CGRect(origin: CGPoint(), size: introContentSize))
|
||||||
|
|||||||
@ -227,12 +227,26 @@ public final class ListMultilineTextFieldItemComponent: Component {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var isActive: Bool {
|
||||||
|
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
||||||
|
return textFieldView.isActive
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func activateInput() {
|
public func activateInput() {
|
||||||
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
||||||
textFieldView.activateInput()
|
textFieldView.activateInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func deactivateInput() {
|
||||||
|
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
||||||
|
textFieldView.deactivateInput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func insertText(text: NSAttributedString) {
|
public func insertText(text: NSAttributedString) {
|
||||||
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
||||||
textFieldView.insertText(text)
|
textFieldView.insertText(text)
|
||||||
|
|||||||
@ -3499,6 +3499,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
@ -5222,7 +5223,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: .chat(peerId: self.peerId, message: nil, updatedPresentationData: self.controller?.updatedPresentationData), navigationController: navigationController, forceExternal: false, openPeer: { [weak self] peer, navigation in
|
self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: .chat(peerId: self.peerId, message: nil, updatedPresentationData: self.controller?.updatedPresentationData), navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { [weak self] peer, navigation in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -5268,7 +5269,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
|
|
||||||
let result: ResolvedUrl = external ? .externalUrl(url) : tempResolved
|
let result: ResolvedUrl = external ? .externalUrl(url) : tempResolved
|
||||||
|
|
||||||
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: forceExternal, openPeer: { peer, navigation in
|
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: forceExternal, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
self?.openPeer(peerId: peer.id, navigation: navigation)
|
self?.openPeer(peerId: peer.id, navigation: navigation)
|
||||||
commit()
|
commit()
|
||||||
}, sendFile: nil,
|
}, sendFile: nil,
|
||||||
@ -5445,11 +5446,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
let peerId = self.peerId
|
let peerId = self.peerId
|
||||||
let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings), fullSize: true)
|
let params = WebAppParameters(source: .settings, peerId: self.context.account.peerId, botId: bot.peer.id, botName: bot.peer.compactDisplayTitle, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: nil, buttonText: nil, keepAliveSignal: nil, forceHasSettings: bot.flags.contains(.hasSettings), fullSize: true)
|
||||||
|
|
||||||
var openUrlImpl: ((String, Bool, @escaping () -> Void) -> Void)?
|
var openUrlImpl: ((String, Bool, Bool, @escaping () -> Void) -> Void)?
|
||||||
var presentImpl: ((ViewController, Any?) -> Void)?
|
var presentImpl: ((ViewController, Any?) -> Void)?
|
||||||
|
|
||||||
let controller = standaloneWebAppController(context: context, updatedPresentationData: self.controller?.updatedPresentationData, params: params, threadId: nil, openUrl: { url, concealed, commit in
|
let controller = standaloneWebAppController(context: context, updatedPresentationData: self.controller?.updatedPresentationData, params: params, threadId: nil, openUrl: { url, concealed, forceUpdate, commit in
|
||||||
openUrlImpl?(url, concealed, commit)
|
openUrlImpl?(url, concealed, forceUpdate, commit)
|
||||||
}, requestSwitchInline: { _, _, _ in
|
}, requestSwitchInline: { _, _, _ in
|
||||||
}, getNavigationController: { [weak self] in
|
}, getNavigationController: { [weak self] in
|
||||||
return (self?.controller?.navigationController as? NavigationController) ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
return (self?.controller?.navigationController as? NavigationController) ?? context.sharedContext.mainWindow?.viewController as? NavigationController
|
||||||
@ -5457,7 +5458,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
controller.navigationPresentation = .flatModal
|
controller.navigationPresentation = .flatModal
|
||||||
self.controller?.push(controller)
|
self.controller?.push(controller)
|
||||||
|
|
||||||
openUrlImpl = { [weak self, weak controller] url, concealed, commit in
|
openUrlImpl = { [weak self, weak controller] url, concealed, forceUpdate, commit in
|
||||||
let _ = openUserGeneratedUrl(context: context, peerId: peerId, url: url, concealed: concealed, present: { [weak self] c in
|
let _ = openUserGeneratedUrl(context: context, peerId: peerId, url: url, concealed: concealed, present: { [weak self] c in
|
||||||
self?.controller?.present(c, in: .window(.root))
|
self?.controller?.present(c, in: .window(.root))
|
||||||
}, openResolved: { result in
|
}, openResolved: { result in
|
||||||
@ -5467,7 +5468,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
} else if let current = controller?.navigationController as? NavigationController {
|
} else if let current = controller?.navigationController as? NavigationController {
|
||||||
navigationController = current
|
navigationController = current
|
||||||
}
|
}
|
||||||
context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: forceUpdate, openPeer: { peer, navigation in
|
||||||
if let navigationController {
|
if let navigationController {
|
||||||
PeerInfoScreenImpl.openPeer(context: context, peerId: peer.id, navigation: navigation, navigationController: navigationController)
|
PeerInfoScreenImpl.openPeer(context: context, peerId: peer.id, navigation: navigation, navigationController: navigationController)
|
||||||
}
|
}
|
||||||
@ -6228,7 +6229,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -6437,7 +6438,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -6567,7 +6568,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -8433,7 +8434,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(.groupBotStart(peerId: peerId, payload: "", adminRights: nil), context: self.context, urlContext: .generic, navigationController: controller.navigationController as? NavigationController, forceExternal: false, openPeer: { id, navigation in
|
self.context.sharedContext.openResolvedUrl(.groupBotStart(peerId: peerId, payload: "", adminRights: nil), context: self.context, urlContext: .generic, navigationController: controller.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { id, navigation in
|
||||||
},
|
},
|
||||||
sendFile: nil,
|
sendFile: nil,
|
||||||
sendSticker: nil,
|
sendSticker: nil,
|
||||||
@ -10367,7 +10368,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
if case let .instantView(webPage, _) = resolvedUrl, let customAnchor = anchor {
|
if case let .instantView(webPage, _) = resolvedUrl, let customAnchor = anchor {
|
||||||
resolvedUrl = .instantView(webPage, customAnchor)
|
resolvedUrl = .instantView(webPage, customAnchor)
|
||||||
}
|
}
|
||||||
strongSelf.context.sharedContext.openResolvedUrl(resolvedUrl, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: false, openPeer: { peer, navigation in
|
strongSelf.context.sharedContext.openResolvedUrl(resolvedUrl, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] controller, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] controller, arguments in
|
||||||
self?.controller?.push(controller)
|
self?.controller?.push(controller)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
|
|||||||
@ -4339,6 +4339,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
urlContext: .generic,
|
urlContext: .generic,
|
||||||
navigationController: nextController?.navigationController as? NavigationController,
|
navigationController: nextController?.navigationController as? NavigationController,
|
||||||
forceExternal: false,
|
forceExternal: false,
|
||||||
|
forceUpdate: false,
|
||||||
openPeer: { _, _ in
|
openPeer: { _, _ in
|
||||||
},
|
},
|
||||||
sendFile: nil,
|
sendFile: nil,
|
||||||
|
|||||||
@ -1812,7 +1812,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
let theme = component.theme
|
let theme = component.theme
|
||||||
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
||||||
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)
|
let controller = WebAppController(context: component.context, updatedPresentationData: updatedPresentationData, params: params, replyToMessageId: nil, threadId: nil)
|
||||||
controller.openUrl = { [weak self] url, _, _ in
|
controller.openUrl = { [weak self] url, _, _, _ in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2676,6 +2676,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
urlContext: .chat(peerId: peerId, message: nil, updatedPresentationData: updatedPresentationData),
|
urlContext: .chat(peerId: peerId, message: nil, updatedPresentationData: updatedPresentationData),
|
||||||
navigationController: navigationController,
|
navigationController: navigationController,
|
||||||
forceExternal: forceExternal,
|
forceExternal: forceExternal,
|
||||||
|
forceUpdate: false,
|
||||||
openPeer: { [weak self, weak view] peerId, navigation in
|
openPeer: { [weak self, weak view] peerId, navigation in
|
||||||
guard let self, let view, let component = view.component, let controller = component.controller() as? StoryContainerScreen else {
|
guard let self, let view, let component = view.component, let controller = component.controller() as? StoryContainerScreen else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -109,8 +109,8 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
|
|||||||
|
|
||||||
var presentImpl: ((ViewController, Any?) -> Void)?
|
var presentImpl: ((ViewController, Any?) -> Void)?
|
||||||
let params = WebAppParameters(source: .menu, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize)
|
let params = WebAppParameters(source: .menu, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: url, queryId: nil, payload: nil, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: fullSize)
|
||||||
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, commit in
|
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, forceUpdate, commit in
|
||||||
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, present: { c, a in
|
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
|
||||||
presentImpl?(c, a)
|
presentImpl?(c, a)
|
||||||
}, commit: commit)
|
}, commit: commit)
|
||||||
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
|
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
|
||||||
@ -197,8 +197,8 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
|
|||||||
source = url.isEmpty ? .generic : .simple
|
source = url.isEmpty ? .generic : .simple
|
||||||
}
|
}
|
||||||
let params = WebAppParameters(source: source, peerId: peer.id, botId: botId, botName: botName, botVerified: botVerified, url: result.url, queryId: nil, payload: payload, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
|
let params = WebAppParameters(source: source, peerId: peer.id, botId: botId, botName: botName, botVerified: botVerified, url: result.url, queryId: nil, payload: payload, buttonText: buttonText, keepAliveSignal: nil, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
|
||||||
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, commit in
|
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, forceUpdate, commit in
|
||||||
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, present: { c, a in
|
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
|
||||||
presentImpl?(c, a)
|
presentImpl?(c, a)
|
||||||
}, commit: commit)
|
}, commit: commit)
|
||||||
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
|
}, requestSwitchInline: { [weak parentController] query, chatTypes, completion in
|
||||||
@ -243,8 +243,8 @@ func openWebAppImpl(context: AccountContext, parentController: ViewController, u
|
|||||||
}
|
}
|
||||||
var presentImpl: ((ViewController, Any?) -> Void)?
|
var presentImpl: ((ViewController, Any?) -> Void)?
|
||||||
let params = WebAppParameters(source: .button, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
|
let params = WebAppParameters(source: .button, peerId: peer.id, botId: peer.id, botName: botName, botVerified: botVerified, url: result.url, queryId: result.queryId, payload: nil, buttonText: buttonText, keepAliveSignal: result.keepAliveSignal, forceHasSettings: false, fullSize: result.flags.contains(.fullSize))
|
||||||
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, commit in
|
let controller = standaloneWebAppController(context: context, updatedPresentationData: updatedPresentationData, params: params, threadId: threadId, openUrl: { [weak parentController] url, concealed, forceUpdate, commit in
|
||||||
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, present: { c, a in
|
ChatControllerImpl.botOpenUrl(context: context, peerId: peer.id, controller: parentController as? ChatControllerImpl, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
|
||||||
presentImpl?(c, a)
|
presentImpl?(c, a)
|
||||||
}, commit: commit)
|
}, commit: commit)
|
||||||
}, completion: { [weak parentController] in
|
}, completion: { [weak parentController] in
|
||||||
@ -378,7 +378,7 @@ public extension ChatControllerImpl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static func botOpenUrl(context: AccountContext, peerId: EnginePeer.Id, controller: ChatControllerImpl?, url: String, concealed: Bool, present: @escaping (ViewController, Any?) -> Void, commit: @escaping () -> Void = {}) {
|
static func botOpenUrl(context: AccountContext, peerId: EnginePeer.Id, controller: ChatControllerImpl?, url: String, concealed: Bool, forceUpdate: Bool, present: @escaping (ViewController, Any?) -> Void, commit: @escaping () -> Void = {}) {
|
||||||
if let controller {
|
if let controller {
|
||||||
controller.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
controller.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
||||||
} else {
|
} else {
|
||||||
@ -391,7 +391,7 @@ public extension ChatControllerImpl {
|
|||||||
} else if let main = context.sharedContext.mainWindow?.viewController as? NavigationController {
|
} else if let main = context.sharedContext.mainWindow?.viewController as? NavigationController {
|
||||||
navigationController = main
|
navigationController = main
|
||||||
}
|
}
|
||||||
context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(result, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: forceUpdate, openPeer: { peer, navigation in
|
||||||
if let navigationController {
|
if let navigationController {
|
||||||
ChatControllerImpl.botOpenPeer(context: context, peerId: peer.id, navigation: navigation, navigationController: navigationController)
|
ChatControllerImpl.botOpenPeer(context: context, peerId: peer.id, navigation: navigation, navigationController: navigationController)
|
||||||
}
|
}
|
||||||
@ -474,8 +474,8 @@ public extension ChatControllerImpl {
|
|||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, botVerified: botPeer.isVerified, url: result.url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings), fullSize: result.flags.contains(.fullSize))
|
let params = WebAppParameters(source: .generic, peerId: peerId, botId: botPeer.id, botName: botApp.title, botVerified: botPeer.isVerified, url: result.url, queryId: 0, payload: payload, buttonText: "", keepAliveSignal: nil, forceHasSettings: botApp.flags.contains(.hasSettings), fullSize: result.flags.contains(.fullSize))
|
||||||
var presentImpl: ((ViewController, Any?) -> Void)?
|
var presentImpl: ((ViewController, Any?) -> Void)?
|
||||||
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, commit in
|
let controller = standaloneWebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, threadId: strongSelf.chatLocation.threadId, openUrl: { [weak self] url, concealed, forceUpdate, commit in
|
||||||
ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, present: { c, a in
|
ChatControllerImpl.botOpenUrl(context: context, peerId: peerId, controller: self, url: url, concealed: concealed, forceUpdate: forceUpdate, present: { c, a in
|
||||||
presentImpl?(c, a)
|
presentImpl?(c, a)
|
||||||
}, commit: commit)
|
}, commit: commit)
|
||||||
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
}, requestSwitchInline: { [weak self] query, chatTypes, completion in
|
||||||
|
|||||||
@ -48,6 +48,8 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
private let removeBackgroundNode: ASImageNode
|
private let removeBackgroundNode: ASImageNode
|
||||||
private let removeTextNode: ImmediateTextNode
|
private let removeTextNode: ImmediateTextNode
|
||||||
|
|
||||||
|
private let closeButton: HighlightableButtonNode
|
||||||
|
|
||||||
private let imageNode: TransformImageNode
|
private let imageNode: TransformImageNode
|
||||||
private let imageNodeContainer: ASDisplayNode
|
private let imageNodeContainer: ASDisplayNode
|
||||||
|
|
||||||
@ -104,6 +106,10 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.imageNodeContainer = ASDisplayNode()
|
self.imageNodeContainer = ASDisplayNode()
|
||||||
|
|
||||||
|
self.closeButton = HighlightableButtonNode()
|
||||||
|
self.closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||||
|
self.closeButton.displaysAsynchronously = false
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.contextContainer)
|
self.addSubnode(self.contextContainer)
|
||||||
@ -183,6 +189,9 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.controllerInteraction?.adContextAction(message, self.contextContainer, gesture)
|
self.controllerInteraction?.adContextAction(message, self.contextContainer, gesture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside])
|
||||||
|
self.addSubnode(self.closeButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -191,6 +200,14 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var theme: PresentationTheme?
|
private var theme: PresentationTheme?
|
||||||
|
|
||||||
|
@objc private func closePressed() {
|
||||||
|
if self.context.isPremium, let adAttribute = self.message?.adAttribute {
|
||||||
|
self.controllerInteraction?.removeAd(adAttribute.opaqueId)
|
||||||
|
} else {
|
||||||
|
self.controllerInteraction?.openNoAdsDemo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
|
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
|
||||||
self.message = interfaceState.adMessage
|
self.message = interfaceState.adMessage
|
||||||
|
|
||||||
@ -198,14 +215,17 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
self.theme = interfaceState.theme
|
self.theme = interfaceState.theme
|
||||||
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
|
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
|
||||||
self.removeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 15.0, color: interfaceState.theme.chat.inputPanel.panelControlAccentColor.withMultipliedAlpha(0.1))
|
self.removeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 15.0, color: interfaceState.theme.chat.inputPanel.panelControlAccentColor.withMultipliedAlpha(0.1))
|
||||||
self.removeTextNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_BotAd_Remove, font: Font.regular(11.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
|
self.removeTextNode.attributedText = NSAttributedString(string: interfaceState.strings.Chat_BotAd_WhatIsThis, font: Font.regular(11.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
|
||||||
|
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(interfaceState.theme), for: [])
|
||||||
}
|
}
|
||||||
|
|
||||||
self.contextContainer.isGestureEnabled = true
|
self.contextContainer.isGestureEnabled = false
|
||||||
|
|
||||||
let panelHeight: CGFloat
|
let panelHeight: CGFloat
|
||||||
|
var hasCloseButton = true
|
||||||
if let message = interfaceState.adMessage {
|
if let message = interfaceState.adMessage {
|
||||||
panelHeight = self.enqueueTransition(width: width, leftInset: leftInset, rightInset: rightInset, transition: .immediate, animation: nil, message: message, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: false, isReplyThread: false, translateToLanguage: nil)
|
panelHeight = self.enqueueTransition(width: width, leftInset: leftInset, rightInset: rightInset, transition: .immediate, animation: nil, message: message, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: false, isReplyThread: false, translateToLanguage: nil)
|
||||||
|
hasCloseButton = message.media.isEmpty
|
||||||
} else {
|
} else {
|
||||||
panelHeight = 50.0
|
panelHeight = 50.0
|
||||||
}
|
}
|
||||||
@ -218,6 +238,12 @@ final class ChatAdPanelNode: ASDisplayNode {
|
|||||||
self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
||||||
self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
|
||||||
|
|
||||||
|
let contentRightInset: CGFloat = 14.0 + rightInset
|
||||||
|
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
|
||||||
|
self.closeButton.frame = CGRect(origin: CGPoint(x: width - contentRightInset - closeButtonSize.width, y: floorToScreenPixels((panelHeight - closeButtonSize.height) / 2.0)), size: closeButtonSize)
|
||||||
|
|
||||||
|
self.closeButton.isHidden = !hasCloseButton
|
||||||
|
|
||||||
self.currentLayout = (width, leftInset, rightInset)
|
self.currentLayout = (width, leftInset, rightInset)
|
||||||
|
|
||||||
return panelHeight
|
return panelHeight
|
||||||
|
|||||||
@ -3966,189 +3966,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId, media: media, fullscreen: fullscreen)
|
self.chatDisplayNode.historyNode.adMessagesContext?.markAction(opaqueId: adAttribute.opaqueId, media: media, fullscreen: fullscreen)
|
||||||
self.controllerInteraction?.openUrl(ChatControllerInteraction.OpenUrl(url: adAttribute.url, concealed: false, external: true, progress: progress))
|
self.controllerInteraction?.openUrl(ChatControllerInteraction.OpenUrl(url: adAttribute.url, concealed: false, external: true, progress: progress))
|
||||||
}, adContextAction: { [weak self] message, sourceNode, gesture in
|
}, adContextAction: { [weak self] message, sourceNode, gesture in
|
||||||
guard let self, let adAttribute = message.adAttribute else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var isBot = false
|
||||||
let controllerInteraction = self.controllerInteraction
|
if let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
||||||
let chatPresentationInterfaceState = self.presentationInterfaceState
|
isBot = true
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
|
|
||||||
var actions: [ContextMenuItem] = []
|
|
||||||
if adAttribute.sponsorInfo != nil || adAttribute.additionalInfo != nil {
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfo, textColor: .primary, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Channels"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, iconSource: nil, action: { c, _ in
|
|
||||||
var subItems: [ContextMenuItem] = []
|
|
||||||
|
|
||||||
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, textColor: .primary, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, iconSource: nil, iconPosition: .left, action: { c, _ in
|
|
||||||
c?.popItems()
|
|
||||||
})))
|
|
||||||
|
|
||||||
subItems.append(.separator)
|
|
||||||
|
|
||||||
if let sponsorInfo = adAttribute.sponsorInfo {
|
|
||||||
subItems.append(.action(ContextMenuActionItem(text: sponsorInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
|
||||||
return nil
|
|
||||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
|
||||||
c?.dismiss(completion: {
|
|
||||||
UIPasteboard.general.string = sponsorInfo
|
|
||||||
|
|
||||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied)
|
|
||||||
controllerInteraction?.displayUndo(content)
|
|
||||||
})
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
if let additionalInfo = adAttribute.additionalInfo {
|
|
||||||
subItems.append(.action(ContextMenuActionItem(text: additionalInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
|
||||||
return nil
|
|
||||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
|
||||||
c?.dismiss(completion: {
|
|
||||||
UIPasteboard.general.string = additionalInfo
|
|
||||||
|
|
||||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied)
|
|
||||||
controllerInteraction?.displayUndo(content)
|
|
||||||
})
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
|
||||||
})))
|
|
||||||
actions.append(.separator)
|
|
||||||
}
|
}
|
||||||
|
let controller = AdsInfoScreen(
|
||||||
if adAttribute.canReport {
|
context: context,
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_AboutAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
mode: isBot ? .bot : .channel,
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
|
message: message
|
||||||
}, iconSource: nil, action: { [weak self] _, f in
|
)
|
||||||
f(.dismissWithoutContent)
|
controller.removeAd = { [weak self] opaqueId in
|
||||||
|
self?.removeAd(opaqueId: opaqueId)
|
||||||
var isBot = false
|
|
||||||
if let self, let user = self.presentationInterfaceState.renderedPeer?.peer as? TelegramUser, user.botInfo != nil {
|
|
||||||
isBot = true
|
|
||||||
}
|
|
||||||
self?.effectiveNavigationController?.pushViewController(AdsInfoScreen(context: context, mode: isBot ? .bot : .channel))
|
|
||||||
})))
|
|
||||||
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_ReportAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, iconSource: nil, action: { [weak self] _, f in
|
|
||||||
f(.default)
|
|
||||||
|
|
||||||
let _ = (context.engine.messages.reportAdMessage(peerId: message.id.peerId, opaqueId: adAttribute.opaqueId, option: nil)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
|
||||||
if case let .options(title, options) = result {
|
|
||||||
self?.effectiveNavigationController?.pushViewController(
|
|
||||||
AdsReportScreen(
|
|
||||||
context: context,
|
|
||||||
peerId: message.id.peerId,
|
|
||||||
opaqueId: adAttribute.opaqueId,
|
|
||||||
title: title,
|
|
||||||
options: options,
|
|
||||||
completed: { [weak self] in
|
|
||||||
self?.removeAd(opaqueId: adAttribute.opaqueId)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})))
|
|
||||||
|
|
||||||
actions.append(.separator)
|
|
||||||
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_RemoveAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
|
||||||
c?.dismiss(completion: {
|
|
||||||
controllerInteraction?.openNoAdsDemo()
|
|
||||||
})
|
|
||||||
})))
|
|
||||||
} else {
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Info, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, iconSource: nil, action: { [weak self] _, f in
|
|
||||||
f(.dismissWithoutContent)
|
|
||||||
self?.effectiveNavigationController?.pushViewController(AdInfoScreen(context: context, forceDark: true))
|
|
||||||
})))
|
|
||||||
|
|
||||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
|
||||||
if !chatPresentationInterfaceState.isPremium && !premiumConfiguration.isPremiumDisabled {
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Hide, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, iconSource: nil, action: { [weak self] c, _ in
|
|
||||||
c?.dismiss(completion: {
|
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
|
||||||
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: false, action: {
|
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: false, dismissed: nil)
|
|
||||||
replaceImpl?(controller)
|
|
||||||
}, dismissed: nil)
|
|
||||||
replaceImpl = { [weak controller] c in
|
|
||||||
controller?.replace(with: c)
|
|
||||||
}
|
|
||||||
self?.effectiveNavigationController?.pushViewController(controller)
|
|
||||||
})
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.append(.separator)
|
|
||||||
|
|
||||||
if chatPresentationInterfaceState.copyProtectionEnabled {
|
|
||||||
} else {
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuCopy, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, action: { [weak controllerInteraction] _, f in
|
|
||||||
var messageEntities: [MessageTextEntity]?
|
|
||||||
var restrictedText: String?
|
|
||||||
for attribute in message.attributes {
|
|
||||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
|
||||||
messageEntities = attribute.entities
|
|
||||||
}
|
|
||||||
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
|
||||||
restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let restrictedText = restrictedText {
|
|
||||||
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
|
||||||
} else {
|
|
||||||
if let translationState = chatPresentationInterfaceState.translationState, translationState.isEnabled,
|
|
||||||
let translation = message.attributes.first(where: { ($0 as? TranslationMessageAttribute)?.toLang == translationState.toLang }) as? TranslationMessageAttribute, !translation.text.isEmpty {
|
|
||||||
storeMessageTextInPasteboard(translation.text, entities: translation.entities)
|
|
||||||
} else {
|
|
||||||
storeMessageTextInPasteboard(message.text, entities: messageEntities)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Queue.mainQueue().after(0.2, {
|
|
||||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_MessageCopied)
|
|
||||||
controllerInteraction?.displayUndo(content)
|
|
||||||
})
|
|
||||||
|
|
||||||
f(.default)
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
if let author = message.author, let addressName = author.addressName {
|
|
||||||
let link = "https://t.me/\(addressName)"
|
|
||||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in
|
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.actionSheet.primaryTextColor)
|
|
||||||
}, action: { [weak controllerInteraction] _, f in
|
|
||||||
UIPasteboard.general.string = link
|
|
||||||
|
|
||||||
Queue.mainQueue().after(0.2, {
|
|
||||||
controllerInteraction?.displayUndo(.linkCopied(text: presentationData.strings.Conversation_LinkCopied))
|
|
||||||
})
|
|
||||||
|
|
||||||
f(.default)
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.effectiveNavigationController?.pushViewController(controller)
|
||||||
let contextController = ContextController(presentationData: presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: self, sourceView: sourceNode.view, insets: .zero, contentInsets: .zero)), items: .single(ContextController.Items(content: .list(actions))), gesture: gesture)
|
}, removeAd: { [weak self] opaqueId in
|
||||||
self.presentInGlobalOverlay(contextController)
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.removeAd(opaqueId: opaqueId)
|
||||||
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in
|
}, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
@ -9962,7 +9800,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
} else {
|
} else {
|
||||||
urlContext = .generic
|
urlContext = .generic
|
||||||
}
|
}
|
||||||
self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: urlContext, navigationController: self.effectiveNavigationController, forceExternal: forceExternal, openPeer: { [weak self] peerId, navigation in
|
self.context.sharedContext.openResolvedUrl(result, context: self.context, urlContext: urlContext, navigationController: self.effectiveNavigationController, forceExternal: forceExternal, forceUpdate: false, openPeer: { [weak self] peerId, navigation in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -10058,7 +9896,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, contentContext: nil, progress: progress, completion: nil)
|
}, contentContext: nil, progress: progress, completion: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openUrl(_ url: String, concealed: Bool, forceExternal: Bool = false, skipUrlAuth: Bool = false, skipConcealedAlert: Bool = false, message: Message? = nil, allowInlineWebpageResolution: Bool = false, progress: Promise<Bool>? = nil, commit: @escaping () -> Void = {}) {
|
func openUrl(
|
||||||
|
_ url: String,
|
||||||
|
concealed: Bool,
|
||||||
|
forceExternal: Bool = false,
|
||||||
|
forceUpdate: Bool = false,
|
||||||
|
skipUrlAuth: Bool = false,
|
||||||
|
skipConcealedAlert: Bool = false,
|
||||||
|
message: Message? = nil,
|
||||||
|
allowInlineWebpageResolution: Bool = false,
|
||||||
|
progress: Promise<Bool>? = nil,
|
||||||
|
commit: @escaping () -> Void = {}
|
||||||
|
) {
|
||||||
self.commitPurposefulAction()
|
self.commitPurposefulAction()
|
||||||
|
|
||||||
if allowInlineWebpageResolution, let message, let webpage = message.media.first(where: { $0 is TelegramMediaWebpage }) as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, content.url == url {
|
if allowInlineWebpageResolution, let message, let webpage = message.media.first(where: { $0 is TelegramMediaWebpage }) as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, content.url == url {
|
||||||
|
|||||||
@ -616,8 +616,8 @@ extension ChatControllerImpl {
|
|||||||
let params = WebAppParameters(source: fromAttachMenu ? .attachMenu : .generic, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: false)
|
let params = WebAppParameters(source: fromAttachMenu ? .attachMenu : .generic, peerId: peer.id, botId: bot.peer.id, botName: bot.shortName, botVerified: bot.peer.isVerified, url: nil, queryId: nil, payload: payload, buttonText: nil, keepAliveSignal: nil, forceHasSettings: false, fullSize: false)
|
||||||
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
let replyMessageSubject = strongSelf.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||||
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageSubject?.messageId, threadId: strongSelf.chatLocation.threadId)
|
let controller = WebAppController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, params: params, replyToMessageId: replyMessageSubject?.messageId, threadId: strongSelf.chatLocation.threadId)
|
||||||
controller.openUrl = { [weak self] url, concealed, commit in
|
controller.openUrl = { [weak self] url, concealed, forceUpdate, commit in
|
||||||
self?.openUrl(url, concealed: concealed, forceExternal: true, commit: commit)
|
self?.openUrl(url, concealed: concealed, forceExternal: true, forceUpdate: forceUpdate, commit: commit)
|
||||||
}
|
}
|
||||||
controller.getNavigationController = { [weak self] in
|
controller.getNavigationController = { [weak self] in
|
||||||
return self?.effectiveNavigationController
|
return self?.effectiveNavigationController
|
||||||
|
|||||||
@ -326,6 +326,7 @@ final class ChatManagingBotTitlePanelNode: ChatTitleAccessoryPanelNode {
|
|||||||
urlContext: .generic,
|
urlContext: .generic,
|
||||||
navigationController: chatController.navigationController as? NavigationController,
|
navigationController: chatController.navigationController as? NavigationController,
|
||||||
forceExternal: false,
|
forceExternal: false,
|
||||||
|
forceUpdate: false,
|
||||||
openPeer: { [weak self] peer, navigation in
|
openPeer: { [weak self] peer, navigation in
|
||||||
guard let self, let chatController = interfaceInteraction.chatController() else {
|
guard let self, let chatController = interfaceInteraction.chatController() else {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -58,6 +58,7 @@ func openResolvedUrlImpl(
|
|||||||
urlContext: OpenURLContext,
|
urlContext: OpenURLContext,
|
||||||
navigationController: NavigationController?,
|
navigationController: NavigationController?,
|
||||||
forceExternal: Bool,
|
forceExternal: Bool,
|
||||||
|
forceUpdate: Bool,
|
||||||
openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void,
|
openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void,
|
||||||
sendFile: ((FileMediaReference) -> Void)?,
|
sendFile: ((FileMediaReference) -> Void)?,
|
||||||
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?,
|
sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?,
|
||||||
@ -222,7 +223,16 @@ func openResolvedUrlImpl(
|
|||||||
case let .stickerPack(name, _):
|
case let .stickerPack(name, _):
|
||||||
dismissInput()
|
dismissInput()
|
||||||
|
|
||||||
let controller = StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: .name(name), stickerPacks: [.name(name)], parentNavigationController: navigationController, sendSticker: sendSticker, sendEmoji: sendEmoji, actionPerformed: { actions in
|
let controller = StickerPackScreen(
|
||||||
|
context: context,
|
||||||
|
updatedPresentationData: updatedPresentationData,
|
||||||
|
mainStickerPack: .name(name),
|
||||||
|
stickerPacks: [.name(name)],
|
||||||
|
ignoreCache: forceUpdate,
|
||||||
|
parentNavigationController: navigationController,
|
||||||
|
sendSticker: sendSticker,
|
||||||
|
sendEmoji: sendEmoji,
|
||||||
|
actionPerformed: { actions in
|
||||||
if actions.count > 1, let first = actions.first {
|
if actions.count > 1, let first = actions.first {
|
||||||
if case .add = first.2 {
|
if case .add = first.2 {
|
||||||
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
|
present(UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.EmojiPackActionInfo_AddedTitle, text: presentationData.strings.EmojiPackActionInfo_MultipleAddedText(Int32(actions.count)), undo: false, info: first.0, topItem: first.1.first, context: context), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
|
||||||
|
|||||||
@ -197,7 +197,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||||||
if case let .externalUrl(value) = resolved {
|
if case let .externalUrl(value) = resolved {
|
||||||
context.sharedContext.applicationBindings.openUrl(value)
|
context.sharedContext.applicationBindings.openUrl(value)
|
||||||
} else {
|
} else {
|
||||||
context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
switch navigation {
|
switch navigation {
|
||||||
case .info:
|
case .info:
|
||||||
if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
||||||
|
|||||||
@ -167,6 +167,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
|||||||
@ -1614,8 +1614,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return resolveUrlImpl(context: context, peerId: peerId, url: url, skipUrlAuth: skipUrlAuth)
|
return resolveUrlImpl(context: context, peerId: peerId, url: url, skipUrlAuth: skipUrlAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?, completion: (() -> Void)?) {
|
public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, forceUpdate: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?, sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?, completion: (() -> Void)?) {
|
||||||
openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, forceExternal: forceExternal, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, sendEmoji: sendEmoji, requestMessageActionUrlAuth: requestMessageActionUrlAuth, joinVoiceChat: joinVoiceChat, present: present, dismissInput: dismissInput, contentContext: contentContext, progress: progress, completion: completion)
|
openResolvedUrlImpl(resolvedUrl, context: context, urlContext: urlContext, navigationController: navigationController, forceExternal: forceExternal, forceUpdate: forceUpdate, openPeer: openPeer, sendFile: sendFile, sendSticker: sendSticker, sendEmoji: sendEmoji, requestMessageActionUrlAuth: requestMessageActionUrlAuth, joinVoiceChat: joinVoiceChat, present: present, dismissInput: dismissInput, contentContext: contentContext, progress: progress, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeDeviceContactInfoController(context: ShareControllerAccountContext, environment: ShareControllerEnvironment, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
public func makeDeviceContactInfoController(context: ShareControllerAccountContext, environment: ShareControllerEnvironment, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController {
|
||||||
@ -1782,6 +1782,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}, openWebView: { _, _, _, _ in
|
}, openWebView: { _, _, _, _ in
|
||||||
}, activateAdAction: { _, _, _, _ in
|
}, activateAdAction: { _, _, _, _ in
|
||||||
}, adContextAction: { _, _, _ in
|
}, adContextAction: { _, _, _ in
|
||||||
|
}, removeAd: { _ in
|
||||||
}, openRequestedPeerSelection: { _, _, _, _ in
|
}, openRequestedPeerSelection: { _, _, _, _ in
|
||||||
}, saveMediaToFiles: { _ in
|
}, saveMediaToFiles: { _ in
|
||||||
}, openNoAdsDemo: {
|
}, openNoAdsDemo: {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
|
|||||||
guard let peer = peer else {
|
guard let peer = peer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.sharedContext.openResolvedUrl(.peer(peer._asPeer(), navigation), context: context, urlContext: .generic, navigationController: (controller?.navigationController as? NavigationController), forceExternal: false, openPeer: { (peer, navigation) in
|
context.sharedContext.openResolvedUrl(.peer(peer._asPeer(), navigation), context: context, urlContext: .generic, navigationController: (controller?.navigationController as? NavigationController), forceExternal: false, forceUpdate: false, openPeer: { (peer, navigation) in
|
||||||
switch navigation {
|
switch navigation {
|
||||||
case let .chat(_, subject, peekData):
|
case let .chat(_, subject, peekData):
|
||||||
if let navigationController = controller?.navigationController as? NavigationController {
|
if let navigationController = controller?.navigationController as? NavigationController {
|
||||||
@ -102,7 +102,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, n
|
|||||||
(controller.navigationController as? NavigationController)?.pushViewController(browserController, animated: true)
|
(controller.navigationController as? NavigationController)?.pushViewController(browserController, animated: true)
|
||||||
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, forceUpdate: false, openPeer: { peer, navigateToPeer in
|
||||||
openResolvedPeerImpl(peer, navigateToPeer)
|
openResolvedPeerImpl(peer, navigateToPeer)
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, joinVoiceChat: nil, present: { c, a in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, joinVoiceChat: nil, present: { c, a in
|
||||||
controller.present(c, in: .window(.root), with: a)
|
controller.present(c, in: .window(.root), with: a)
|
||||||
|
|||||||
@ -452,7 +452,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
if let url = navigationAction.request.url?.absoluteString {
|
if let url = navigationAction.request.url?.absoluteString {
|
||||||
if isTelegramMeLink(url) || isTelegraPhLink(url) {
|
if isTelegramMeLink(url) || isTelegraPhLink(url) {
|
||||||
decisionHandler(.cancel)
|
decisionHandler(.cancel)
|
||||||
self.controller?.openUrl(url, true, {})
|
self.controller?.openUrl(url, true, false, {})
|
||||||
} else {
|
} else {
|
||||||
decisionHandler(.allow)
|
decisionHandler(.allow)
|
||||||
}
|
}
|
||||||
@ -463,7 +463,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
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, let url = navigationAction.request.url {
|
if navigationAction.targetFrame == nil, let url = navigationAction.request.url {
|
||||||
self.controller?.openUrl(url.absoluteString, true, {})
|
self.controller?.openUrl(url.absoluteString, true, false, {})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -803,8 +803,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
case "web_app_open_tg_link":
|
case "web_app_open_tg_link":
|
||||||
if let json = json, let path = json["path_full"] as? String {
|
if let json = json, let path = json["path_full"] as? String {
|
||||||
let forceRequest = json["force_request"] as? Bool ?? false
|
let forceRequest = json["force_request"] as? Bool ?? false
|
||||||
let _ = forceRequest
|
controller.openUrl("https://t.me\(path)", false, forceRequest, { [weak controller] in
|
||||||
controller.openUrl("https://t.me\(path)", false, { [weak controller] in
|
|
||||||
let _ = controller
|
let _ = controller
|
||||||
// controller?.dismiss()
|
// controller?.dismiss()
|
||||||
})
|
})
|
||||||
@ -1890,7 +1889,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
private var hasSettings = false
|
private var hasSettings = false
|
||||||
|
|
||||||
public var openUrl: (String, Bool, @escaping () -> Void) -> Void = { _, _, _ in }
|
public var openUrl: (String, Bool, Bool, @escaping () -> Void) -> Void = { _, _, _, _ in }
|
||||||
public var getNavigationController: () -> NavigationController? = { return nil }
|
public var getNavigationController: () -> NavigationController? = { return nil }
|
||||||
public var completion: () -> Void = {}
|
public var completion: () -> Void = {}
|
||||||
public var requestSwitchInline: (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in }
|
public var requestSwitchInline: (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in }
|
||||||
@ -2142,7 +2141,7 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
let context = self.context
|
let context = self.context
|
||||||
let _ = (cachedWebAppTermsPage(context: context)
|
let _ = (cachedWebAppTermsPage(context: context)
|
||||||
|> deliverOnMainQueue).startStandalone(next: { resolvedUrl in
|
|> deliverOnMainQueue).startStandalone(next: { resolvedUrl in
|
||||||
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: true, openPeer: { peer, navigation in
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: true, forceUpdate: false, openPeer: { peer, navigation in
|
||||||
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] c, arguments in
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] c, arguments in
|
||||||
self?.push(c)
|
self?.push(c)
|
||||||
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
||||||
@ -2371,7 +2370,7 @@ public func standaloneWebAppController(
|
|||||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||||
params: WebAppParameters,
|
params: WebAppParameters,
|
||||||
threadId: Int64?,
|
threadId: Int64?,
|
||||||
openUrl: @escaping (String, Bool, @escaping () -> Void) -> Void,
|
openUrl: @escaping (String, Bool, Bool, @escaping () -> Void) -> Void,
|
||||||
requestSwitchInline: @escaping (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in },
|
requestSwitchInline: @escaping (String, [ReplyMarkupButtonRequestPeerType]?, @escaping () -> Void) -> Void = { _, _, _ in },
|
||||||
getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil },
|
getInputContainerNode: @escaping () -> (CGFloat, ASDisplayNode, () -> AttachmentController.InputPanelTransition?)? = { return nil },
|
||||||
completion: @escaping () -> Void = {},
|
completion: @escaping () -> Void = {},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user