From bbe90fcadb0b1b67b08d20a57748b8c76bcd313c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 9 Aug 2024 05:53:59 +0200 Subject: [PATCH] Browser improvements --- .../BrowserUI/Sources/BrowserPdfContent.swift | 379 ++++++++---------- .../BrowserUI/Sources/BrowserScreen.swift | 12 +- .../Sources/BrowserSearchBarComponent.swift | 49 ++- .../Sources/BrowserToolbarComponent.swift | 42 +- .../BrowserUI/Sources/BrowserWebContent.swift | 1 + 5 files changed, 255 insertions(+), 228 deletions(-) diff --git a/submodules/BrowserUI/Sources/BrowserPdfContent.swift b/submodules/BrowserUI/Sources/BrowserPdfContent.swift index de081dc670..ca6d4cf4f7 100644 --- a/submodules/BrowserUI/Sources/BrowserPdfContent.swift +++ b/submodules/BrowserUI/Sources/BrowserPdfContent.swift @@ -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() { diff --git a/submodules/BrowserUI/Sources/BrowserScreen.swift b/submodules/BrowserUI/Sources/BrowserScreen.swift index cce2d9375d..c9c060419d 100644 --- a/submodules/BrowserUI/Sources/BrowserScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserScreen.swift @@ -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) diff --git a/submodules/BrowserUI/Sources/BrowserSearchBarComponent.swift b/submodules/BrowserUI/Sources/BrowserSearchBarComponent.swift index 6e8974667f..538e42344e 100644 --- a/submodules/BrowserUI/Sources/BrowserSearchBarComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserSearchBarComponent.swift @@ -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() + 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 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) diff --git a/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift b/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift index c1b476d84c..30a699f101 100644 --- a/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift +++ b/submodules/BrowserUI/Sources/BrowserToolbarComponent.swift @@ -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 diff --git a/submodules/BrowserUI/Sources/BrowserWebContent.swift b/submodules/BrowserUI/Sources/BrowserWebContent.swift index f17665077e..c2b9d1ae67 100644 --- a/submodules/BrowserUI/Sources/BrowserWebContent.swift +++ b/submodules/BrowserUI/Sources/BrowserWebContent.swift @@ -460,6 +460,7 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU self?.currentSearchResult = 0 self?.searchResultsCount = 0 + completion?(0) } } }