mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Browser improvements
This commit is contained in:
parent
f56903608c
commit
bbe90fcadb
@ -9,7 +9,6 @@ import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import WebKit
|
||||
import AppBundle
|
||||
import PromptUI
|
||||
import SafariServices
|
||||
@ -18,11 +17,11 @@ import UndoUI
|
||||
import UrlEscaping
|
||||
import PDFKit
|
||||
|
||||
final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKUIDelegate, UIScrollViewDelegate {
|
||||
final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDFDocumentDelegate {
|
||||
private let context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private let webView: PDFView
|
||||
private let pdfView: PDFView
|
||||
private let scrollView: UIScrollView!
|
||||
|
||||
let uuid: UUID
|
||||
@ -53,10 +52,10 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
self.uuid = UUID()
|
||||
self.presentationData = presentationData
|
||||
|
||||
self.webView = PDFView()
|
||||
self.pdfView = PDFView()
|
||||
|
||||
var scrollView: UIScrollView?
|
||||
for view in self.webView.subviews {
|
||||
for view in self.pdfView.subviews {
|
||||
if let view = view as? UIScrollView {
|
||||
scrollView = view
|
||||
} else {
|
||||
@ -69,12 +68,12 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
}
|
||||
self.scrollView = scrollView
|
||||
|
||||
self.webView.displayDirection = .vertical
|
||||
self.webView.autoScales = true
|
||||
self.pdfView.displayDirection = .vertical
|
||||
self.pdfView.autoScales = true
|
||||
|
||||
var title: String = "file"
|
||||
if let path = self.context.account.postbox.mediaBox.completedResourcePath(file.resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) {
|
||||
self.webView.document = PDFDocument(data: data)
|
||||
self.pdfView.document = PDFDocument(data: data)
|
||||
title = file.fileName ?? "file"
|
||||
}
|
||||
|
||||
@ -86,13 +85,13 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
if #available(iOS 15.0, *) {
|
||||
self.backgroundColor = presentationData.theme.list.plainBackgroundColor
|
||||
}
|
||||
self.addSubview(self.webView)
|
||||
self.addSubview(self.pdfView)
|
||||
|
||||
// Queue.mainQueue().after(1.0) {
|
||||
// if let scrollView = self.scrollView {
|
||||
// scrollView.delegate = self
|
||||
// }
|
||||
// }
|
||||
Queue.mainQueue().after(1.0) {
|
||||
if let scrollView = self.scrollView {
|
||||
scrollView.delegate = self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -109,134 +108,172 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
}
|
||||
}
|
||||
|
||||
var currentFontState = BrowserPresentationState.FontState(size: 100, isSerif: false)
|
||||
|
||||
func updateFontState(_ state: BrowserPresentationState.FontState) {
|
||||
self.updateFontState(state, force: false)
|
||||
|
||||
}
|
||||
func updateFontState(_ state: BrowserPresentationState.FontState, force: Bool) {
|
||||
self.currentFontState = state
|
||||
}
|
||||
|
||||
// let fontFamily = state.isSerif ? "'Georgia, serif'" : "null"
|
||||
// let textSizeAdjust = state.size != 100 ? "'\(state.size)%'" : "null"
|
||||
// let js = "\(setupFontFunctions) setTelegramFontOverrides(\(fontFamily), \(textSizeAdjust))";
|
||||
// self.webView.evaluateJavaScript(js) { _, _ in }
|
||||
}
|
||||
|
||||
private var didSetupSearch = false
|
||||
private func setupSearch(completion: @escaping () -> Void) {
|
||||
// guard !self.didSetupSearch else {
|
||||
// completion()
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// let bundle = getAppBundle()
|
||||
// guard let scriptPath = bundle.path(forResource: "UIWebViewSearch", ofType: "js") else {
|
||||
// return
|
||||
// }
|
||||
// guard let scriptData = try? Data(contentsOf: URL(fileURLWithPath: scriptPath)) else {
|
||||
// return
|
||||
// }
|
||||
// guard let script = String(data: scriptData, encoding: .utf8) else {
|
||||
// return
|
||||
// }
|
||||
// self.didSetupSearch = true
|
||||
// self.webView.evaluateJavaScript(script, completionHandler: { _, error in
|
||||
// if error != nil {
|
||||
// print()
|
||||
// }
|
||||
// completion()
|
||||
// })
|
||||
}
|
||||
|
||||
private var findSession: Any?
|
||||
private var previousQuery: String?
|
||||
func setSearch(_ query: String?, completion: ((Int) -> Void)?) {
|
||||
// guard self.previousQuery != query else {
|
||||
// return
|
||||
// }
|
||||
// self.previousQuery = query
|
||||
// self.setupSearch { [weak self] in
|
||||
// if let query = query {
|
||||
// let js = "uiWebview_HighlightAllOccurencesOfString('\(query)')"
|
||||
// self?.webView.evaluateJavaScript(js, completionHandler: { [weak self] _, _ in
|
||||
// let js = "uiWebview_SearchResultCount"
|
||||
// self?.webView.evaluateJavaScript(js, completionHandler: { [weak self] result, _ in
|
||||
// if let result = result as? NSNumber {
|
||||
// self?.searchResultsCount = result.intValue
|
||||
// completion?(result.intValue)
|
||||
// } else {
|
||||
// completion?(0)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// } else {
|
||||
// let js = "uiWebview_RemoveAllHighlights()"
|
||||
// self?.webView.evaluateJavaScript(js, completionHandler: nil)
|
||||
//
|
||||
// self?.currentSearchResult = 0
|
||||
// self?.searchResultsCount = 0
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private var currentSearchResult: Int = 0
|
||||
private var searchResultsCount: Int = 0
|
||||
private var searchResults: [PDFSelection] = []
|
||||
private var searchCompletion: ((Int) -> Void)?
|
||||
private var searchDimmingView: UIView?
|
||||
|
||||
private let matchColor = UIColor(rgb: 0xd4d4d, alpha: 0.2)
|
||||
private let selectedColor = UIColor(rgb: 0xffe438)
|
||||
|
||||
func didMatchString(_ instance: PDFSelection) {
|
||||
instance.color = self.matchColor
|
||||
self.searchResults.append(instance)
|
||||
}
|
||||
|
||||
func documentDidEndDocumentFind(_ notification: Notification) {
|
||||
self.searchResultsCount = self.searchResults.count
|
||||
|
||||
if let searchCompletion = self.searchCompletion {
|
||||
self.searchCompletion = nil
|
||||
searchCompletion(self.searchResultsCount)
|
||||
}
|
||||
|
||||
self.updateSearchHighlights(highlightedSelection: self.searchResults.first)
|
||||
}
|
||||
|
||||
func updateSearchHighlights(highlightedSelection: PDFSelection?) {
|
||||
self.pdfView.highlightedSelections = nil
|
||||
if let highlightedSelection {
|
||||
for selection in self.searchResults {
|
||||
if selection === highlightedSelection {
|
||||
selection.color = self.selectedColor
|
||||
} else {
|
||||
selection.color = self.matchColor
|
||||
}
|
||||
}
|
||||
self.pdfView.highlightedSelections = self.searchResults
|
||||
}
|
||||
}
|
||||
|
||||
func setSearch(_ query: String?, completion: ((Int) -> Void)?) {
|
||||
guard let document = self.pdfView.document, self.previousQuery != query else {
|
||||
return
|
||||
}
|
||||
self.previousQuery = query
|
||||
|
||||
if #available(iOS 16.0, *), !"".isEmpty {
|
||||
if let query {
|
||||
var findSession: UIFindSession?
|
||||
if let current = self.findSession as? UIFindSession {
|
||||
findSession = current
|
||||
} else {
|
||||
self.pdfView.isFindInteractionEnabled = true
|
||||
|
||||
if let session = self.pdfView.findInteraction(self.pdfView.findInteraction, sessionFor: self.pdfView) {
|
||||
findSession = session
|
||||
self.findSession = session
|
||||
|
||||
self.pdfView.findInteraction(self.pdfView.findInteraction, didBegin: session)
|
||||
}
|
||||
}
|
||||
if let findSession {
|
||||
findSession.performSearch(query: query, options: BrowserSearchOptions())
|
||||
self.pdfView.findInteraction.updateResultCount()
|
||||
completion?(findSession.resultCount)
|
||||
}
|
||||
} else {
|
||||
if let session = self.findSession as? UIFindSession {
|
||||
self.pdfView.findInteraction(self.pdfView.findInteraction, didEnd: session)
|
||||
self.findSession = nil
|
||||
self.pdfView.isFindInteractionEnabled = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let query {
|
||||
self.currentSearchResult = 0
|
||||
self.searchCompletion = completion
|
||||
|
||||
document.cancelFindString()
|
||||
document.delegate = self
|
||||
document.beginFindString(query, withOptions: .caseInsensitive)
|
||||
} else {
|
||||
self.searchResults = []
|
||||
self.currentSearchResult = 0
|
||||
self.searchResultsCount = 0
|
||||
|
||||
self.updateSearchHighlights(highlightedSelection: nil)
|
||||
|
||||
document.cancelFindString()
|
||||
document.delegate = nil
|
||||
|
||||
completion?(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scrollToPreviousSearchResult(completion: ((Int, Int) -> Void)?) {
|
||||
// let searchResultsCount = self.searchResultsCount
|
||||
// var index = self.currentSearchResult - 1
|
||||
// if index < 0 {
|
||||
// index = searchResultsCount - 1
|
||||
// }
|
||||
// self.currentSearchResult = index
|
||||
//
|
||||
// let js = "uiWebview_ScrollTo('\(searchResultsCount - index - 1)')"
|
||||
// self.webView.evaluateJavaScript(js, completionHandler: { _, _ in
|
||||
// completion?(index, searchResultsCount)
|
||||
// })
|
||||
if #available(iOS 16.0, *), !"".isEmpty {
|
||||
if let session = self.findSession as? UIFindSession {
|
||||
session.highlightNextResult(in: .backward)
|
||||
completion?(session.highlightedResultIndex, session.resultCount)
|
||||
}
|
||||
} else {
|
||||
let searchResultsCount = self.searchResultsCount
|
||||
var index = self.currentSearchResult - 1
|
||||
if index < 0 {
|
||||
index = searchResultsCount - 1
|
||||
}
|
||||
self.currentSearchResult = index
|
||||
|
||||
if index >= 0 && index < self.searchResults.count {
|
||||
self.updateSearchHighlights(highlightedSelection: self.searchResults[index])
|
||||
|
||||
self.pdfView.go(to: self.searchResults[index])
|
||||
completion?(index, searchResultsCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scrollToNextSearchResult(completion: ((Int, Int) -> Void)?) {
|
||||
// let searchResultsCount = self.searchResultsCount
|
||||
// var index = self.currentSearchResult + 1
|
||||
// if index >= searchResultsCount {
|
||||
// index = 0
|
||||
// }
|
||||
// self.currentSearchResult = index
|
||||
//
|
||||
// let js = "uiWebview_ScrollTo('\(searchResultsCount - index - 1)')"
|
||||
// self.webView.evaluateJavaScript(js, completionHandler: { _, _ in
|
||||
// completion?(index, searchResultsCount)
|
||||
// })
|
||||
if #available(iOS 16.0, *), !"".isEmpty {
|
||||
if let session = self.findSession as? UIFindSession {
|
||||
session.highlightNextResult(in: .forward)
|
||||
completion?(session.highlightedResultIndex, session.resultCount)
|
||||
}
|
||||
} else {
|
||||
let searchResultsCount = self.searchResultsCount
|
||||
var index = self.currentSearchResult + 1
|
||||
if index >= searchResultsCount {
|
||||
index = 0
|
||||
}
|
||||
self.currentSearchResult = index
|
||||
|
||||
if index >= 0 && index < self.searchResults.count {
|
||||
self.updateSearchHighlights(highlightedSelection: self.searchResults[index])
|
||||
|
||||
self.pdfView.go(to: self.searchResults[index])
|
||||
completion?(index, searchResultsCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stop() {
|
||||
// self.webView.stopLoading()
|
||||
}
|
||||
|
||||
func reload() {
|
||||
// self.webView.reload()
|
||||
}
|
||||
|
||||
func navigateBack() {
|
||||
// self.webView.goBack()
|
||||
}
|
||||
|
||||
func navigateForward() {
|
||||
// self.webView.goForward()
|
||||
}
|
||||
|
||||
func navigateTo(historyItem: BrowserContentState.HistoryItem) {
|
||||
// if let webItem = historyItem.webItem {
|
||||
// self.webView.go(to: webItem)
|
||||
// }
|
||||
}
|
||||
|
||||
func navigateTo(address: String) {
|
||||
// let finalUrl = explicitUrl(address)
|
||||
// guard let url = URL(string: finalUrl) else {
|
||||
// return
|
||||
// }
|
||||
// self.webView.load(URLRequest(url: url))
|
||||
}
|
||||
|
||||
func scrollToTop() {
|
||||
@ -250,14 +287,16 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
|
||||
self.previousScrollingOffset = ScrollingOffsetState(value: self.scrollView.contentOffset.y, isDraggingOrDecelerating: self.scrollView.isDragging || self.scrollView.isDecelerating)
|
||||
|
||||
let webViewFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: size.width - insets.left - insets.right, height: size.height - insets.top - insets.bottom))
|
||||
transition.setFrame(view: self.webView, frame: webViewFrame)
|
||||
let pdfViewFrame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: CGSize(width: size.width - insets.left - insets.right, height: size.height - insets.top - insets.bottom))
|
||||
transition.setFrame(view: self.pdfView, frame: pdfViewFrame)
|
||||
if let searchDimmingView = self.searchDimmingView {
|
||||
transition.setFrame(view: searchDimmingView, frame: CGRect(origin: .zero, size: self.pdfView.bounds.size))
|
||||
}
|
||||
|
||||
if isFirstTime {
|
||||
self.webView.setNeedsLayout()
|
||||
self.webView.layoutIfNeeded()
|
||||
self.webView.minScaleFactor = self.webView.scaleFactorForSizeToFit
|
||||
|
||||
self.pdfView.setNeedsLayout()
|
||||
self.pdfView.layoutIfNeeded()
|
||||
self.pdfView.minScaleFactor = self.pdfView.scaleFactorForSizeToFit
|
||||
}
|
||||
}
|
||||
|
||||
@ -279,16 +318,29 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
self.updateScrollingOffset(isReset: false, transition: transition)
|
||||
}
|
||||
|
||||
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
|
||||
if let scrollViewDelegate = scrollView as? UIScrollViewDelegate {
|
||||
return scrollViewDelegate.viewForZooming?(in: scrollView)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
|
||||
if let scrollViewDelegate = scrollView as? UIScrollViewDelegate {
|
||||
scrollViewDelegate.scrollViewWillBeginZooming?(scrollView, with: view)
|
||||
}
|
||||
self.resetScrolling()
|
||||
self.wasZooming = true
|
||||
}
|
||||
|
||||
private var wasZooming = false
|
||||
func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
|
||||
if let scrollViewDelegate = scrollView as? UIScrollViewDelegate {
|
||||
scrollViewDelegate.scrollViewDidEndZooming?(scrollView, with: view, atScale: scale)
|
||||
}
|
||||
Queue.mainQueue().after(0.1, {
|
||||
self.wasZooming = false
|
||||
})
|
||||
}
|
||||
|
||||
func scrollViewDidZoom(_ scrollView: UIScrollView) {
|
||||
@ -298,7 +350,12 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
self.updateScrollingOffset(isReset: false, transition: .immediate)
|
||||
if let scrollViewDelegate = scrollView as? UIScrollViewDelegate {
|
||||
scrollViewDelegate.scrollViewDidScroll?(scrollView)
|
||||
}
|
||||
if !scrollView.isZooming && !self.wasZooming {
|
||||
self.updateScrollingOffset(isReset: false, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
@ -353,90 +410,6 @@ final class BrowserPdfContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
self.updateScrollingOffset(isReset: true, transition: .spring(duration: 0.4))
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
|
||||
// self.currentError = nil
|
||||
self.updateFontState(self.currentFontState, force: true)
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
self.updateState {
|
||||
$0
|
||||
.withUpdatedBackList(webView.backForwardList.backList.map { BrowserContentState.HistoryItem(webItem: $0) })
|
||||
.withUpdatedForwardList(webView.backForwardList.forwardList.map { BrowserContentState.HistoryItem(webItem: $0) })
|
||||
}
|
||||
}
|
||||
|
||||
// func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||
// if (error as NSError).code != -999 {
|
||||
// self.currentError = error
|
||||
// } else {
|
||||
// self.currentError = nil
|
||||
// }
|
||||
// if let (size, insets) = self.validLayout {
|
||||
// self.updateLayout(size: size, insets: insets, transition: .immediate)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
||||
// if (error as NSError).code != -999 {
|
||||
// self.currentError = error
|
||||
// } else {
|
||||
// self.currentError = nil
|
||||
// }
|
||||
// if let (size, insets) = self.validLayout {
|
||||
// self.updateLayout(size: size, insets: insets, transition: .immediate)
|
||||
// }
|
||||
// }
|
||||
|
||||
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
|
||||
if navigationAction.targetFrame == nil {
|
||||
if let url = navigationAction.request.url?.absoluteString {
|
||||
self.open(url: url, new: true)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func webViewDidClose(_ webView: WKWebView) {
|
||||
self.close()
|
||||
}
|
||||
|
||||
@available(iOSApplicationExtension 15.0, iOS 15.0, *)
|
||||
func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) {
|
||||
decisionHandler(.prompt)
|
||||
}
|
||||
|
||||
|
||||
// @available(iOS 13.0, *)
|
||||
// func webView(_ webView: WKWebView, contextMenuConfigurationForElement elementInfo: WKContextMenuElementInfo, completionHandler: @escaping (UIContextMenuConfiguration?) -> Void) {
|
||||
// guard let url = elementInfo.linkURL else {
|
||||
// completionHandler(nil)
|
||||
// return
|
||||
// }
|
||||
// let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
// let configuration = UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in
|
||||
// return UIMenu(title: "", children: [
|
||||
// UIAction(title: presentationData.strings.Browser_ContextMenu_Open, image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Browser"), color: presentationData.theme.contextMenu.primaryColor), handler: { [weak self] _ in
|
||||
// self?.open(url: url.absoluteString, new: false)
|
||||
// }),
|
||||
// UIAction(title: presentationData.strings.Browser_ContextMenu_OpenInNewTab, image: generateTintedImage(image: UIImage(bundleImageName: "Instant View/NewTab"), color: presentationData.theme.contextMenu.primaryColor), handler: { [weak self] _ in
|
||||
// self?.open(url: url.absoluteString, new: true)
|
||||
// }),
|
||||
// UIAction(title: presentationData.strings.Browser_ContextMenu_AddToReadingList, image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReadingList"), color: presentationData.theme.contextMenu.primaryColor), handler: { _ in
|
||||
// let _ = try? SSReadingList.default()?.addItem(with: url, title: nil, previewText: nil)
|
||||
// }),
|
||||
// UIAction(title: presentationData.strings.Browser_ContextMenu_CopyLink, image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: presentationData.theme.contextMenu.primaryColor), handler: { [weak self] _ in
|
||||
// UIPasteboard.general.string = url.absoluteString
|
||||
// self?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
// }),
|
||||
// UIAction(title: presentationData.strings.Browser_ContextMenu_Share, image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: presentationData.theme.contextMenu.primaryColor), handler: { [weak self] _ in
|
||||
// self?.share(url: url.absoluteString)
|
||||
// })
|
||||
// ])
|
||||
// }
|
||||
// completionHandler(configuration)
|
||||
// }
|
||||
|
||||
private func open(url: String, new: Bool) {
|
||||
let subject: BrowserScreen.Subject = .webPage(url: url)
|
||||
if new, let navigationController = self.getNavigationController() {
|
||||
|
@ -641,6 +641,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
})
|
||||
})
|
||||
case .scrollToPreviousSearchResult:
|
||||
self.view.window?.endEditing(true)
|
||||
content.scrollToPreviousSearchResult(completion: { [weak self] index, count in
|
||||
self?.updatePresentationState({ state in
|
||||
var updatedState = state
|
||||
@ -650,6 +651,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
})
|
||||
})
|
||||
case .scrollToNextSearchResult:
|
||||
self.view.window?.endEditing(true)
|
||||
content.scrollToNextSearchResult(completion: { [weak self] index, count in
|
||||
self?.updatePresentationState({ state in
|
||||
var updatedState = state
|
||||
@ -1089,11 +1091,11 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
let canOpenIn = !(self.contentState?.url.hasPrefix("tonsite") ?? false)
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.custom(fontItem, false))
|
||||
|
||||
if contentState.contentType == .document, contentState.title.lowercased().hasSuffix(".pdf") {
|
||||
|
||||
} else {
|
||||
items.append(.custom(fontItem, false))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.InstantPage_FontSanFrancisco, icon: forceIsSerif ? emptyIcon : checkIcon, action: { (controller, action) in
|
||||
performAction.invoke(.updateFontIsSerif(false))
|
||||
action(.default)
|
||||
@ -1105,7 +1107,9 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
})))
|
||||
}
|
||||
|
||||
items.append(.separator)
|
||||
if !items.isEmpty {
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
if case .webPage = contentState.contentType {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.WebBrowser_Reload, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Instant View/Settings/Reload"), color: theme.contextMenu.primaryColor) }, action: { (controller, action) in
|
||||
@ -1113,7 +1117,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
||||
action(.default)
|
||||
})))
|
||||
}
|
||||
if [.webPage].contains(contentState.contentType) {
|
||||
if [.webPage, .document].contains(contentState.contentType) {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.InstantPage_Search, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Instant View/Settings/Search"), color: theme.contextMenu.primaryColor) }, action: { (controller, action) in
|
||||
performAction.invoke(.updateSearchActive(true))
|
||||
action(.default)
|
||||
|
@ -2,6 +2,7 @@ import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import ComponentFlow
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
@ -60,9 +61,8 @@ final class SearchBarContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private let activated: (Bool) -> Void = { _ in }
|
||||
private let deactivated: (Bool) -> Void = { _ in }
|
||||
private let updateQuery: (String?) -> Void = { _ in }
|
||||
private let queryPromise = ValuePromise<String>()
|
||||
private var queryDisposable: Disposable?
|
||||
|
||||
private let backgroundLayer: SimpleLayer
|
||||
|
||||
@ -145,6 +145,23 @@ final class SearchBarContentComponent: Component {
|
||||
}
|
||||
}
|
||||
self.clearIconButton.addTarget(self, action: #selector(self.clearPressed), for: .touchUpInside)
|
||||
|
||||
let throttledSearchQuery = self.queryPromise.get()
|
||||
|> mapToSignal { query -> Signal<String, NoError> in
|
||||
if !query.isEmpty {
|
||||
return (.complete() |> delay(0.6, queue: Queue.mainQueue()))
|
||||
|> then(.single(query))
|
||||
} else {
|
||||
return .single(query)
|
||||
}
|
||||
}
|
||||
|
||||
self.queryDisposable = (throttledSearchQuery
|
||||
|> deliverOnMainQueue).start(next: { [weak self] query in
|
||||
if let self {
|
||||
self.component?.performAction.invoke(.updateSearchQuery(query))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
@ -174,23 +191,17 @@ final class SearchBarContentComponent: Component {
|
||||
guard !(self.textField?.isFirstResponder ?? false) else {
|
||||
return
|
||||
}
|
||||
|
||||
self.activated(true)
|
||||
|
||||
|
||||
self.textField?.becomeFirstResponder()
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.updateQuery(nil)
|
||||
|
||||
self.clearIconView.isHidden = true
|
||||
self.clearIconButton.isHidden = true
|
||||
|
||||
let textField = self.textField
|
||||
self.textField = nil
|
||||
|
||||
self.deactivated(textField?.isFirstResponder ?? false)
|
||||
|
||||
|
||||
self.component?.performAction.invoke(.updateSearchActive(false))
|
||||
|
||||
if let textField {
|
||||
@ -200,11 +211,11 @@ final class SearchBarContentComponent: Component {
|
||||
}
|
||||
|
||||
@objc private func clearPressed() {
|
||||
self.updateQuery(nil)
|
||||
self.textField?.text = ""
|
||||
|
||||
self.clearIconView.isHidden = true
|
||||
self.clearIconButton.isHidden = true
|
||||
guard let textField = self.textField else {
|
||||
return
|
||||
}
|
||||
textField.text = ""
|
||||
self.textFieldChanged(textField)
|
||||
}
|
||||
|
||||
func deactivate() {
|
||||
@ -232,10 +243,8 @@ final class SearchBarContentComponent: Component {
|
||||
self.clearIconView.isHidden = text.isEmpty
|
||||
self.clearIconButton.isHidden = text.isEmpty
|
||||
self.placeholderContent.view?.isHidden = !text.isEmpty
|
||||
|
||||
self.updateQuery(text)
|
||||
|
||||
self.component?.performAction.invoke(.updateSearchQuery(text))
|
||||
|
||||
self.queryPromise.set(text)
|
||||
|
||||
if let params = self.params {
|
||||
self.update(theme: params.theme, strings: params.strings, size: params.size, transition: .immediate)
|
||||
|
@ -177,6 +177,8 @@ final class NavigationToolbarContentComponent: CombinedComponent {
|
||||
let share = Child(Button.self)
|
||||
let bookmark = Child(Button.self)
|
||||
let openIn = Child(Button.self)
|
||||
let search = Child(Button.self)
|
||||
let quickLook = Child(Button.self)
|
||||
|
||||
return { context in
|
||||
let availableSize = context.availableSize
|
||||
@ -211,7 +213,45 @@ final class NavigationToolbarContentComponent: CombinedComponent {
|
||||
|
||||
if context.component.isDocument {
|
||||
context.add(share
|
||||
.position(CGPoint(x: sideInset + share.size.width / 2.0, y: availableSize.height / 2.0))
|
||||
.position(CGPoint(x: availableSize.width / 2.0, y: availableSize.height / 2.0))
|
||||
)
|
||||
|
||||
let search = search.update(
|
||||
component: Button(
|
||||
content: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Chat List/SearchIcon",
|
||||
tintColor: context.component.accentColor
|
||||
)
|
||||
),
|
||||
action: {
|
||||
performAction.invoke(.updateSearchActive(true))
|
||||
}
|
||||
).minSize(buttonSize),
|
||||
availableSize: buttonSize,
|
||||
transition: .easeInOut(duration: 0.2)
|
||||
)
|
||||
context.add(search
|
||||
.position(CGPoint(x: sideInset + search.size.width / 2.0, y: availableSize.height / 2.0))
|
||||
)
|
||||
|
||||
let quickLook = quickLook.update(
|
||||
component: Button(
|
||||
content: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Stories/EmbeddedViewIcon",
|
||||
tintColor: context.component.accentColor
|
||||
)
|
||||
),
|
||||
action: {
|
||||
performAction.invoke(.openIn)
|
||||
}
|
||||
).minSize(buttonSize),
|
||||
availableSize: buttonSize,
|
||||
transition: .easeInOut(duration: 0.2)
|
||||
)
|
||||
context.add(quickLook
|
||||
.position(CGPoint(x: context.availableSize.width - sideInset - quickLook.size.width / 2.0, y: availableSize.height / 2.0))
|
||||
)
|
||||
} else {
|
||||
let canGoBack = context.component.canGoBack
|
||||
|
@ -460,6 +460,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
||||
|
||||
self?.currentSearchResult = 0
|
||||
self?.searchResultsCount = 0
|
||||
completion?(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user