Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix #627 Add brave://search URL scheme #3582

Merged
merged 5 commits into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 43 additions & 19 deletions BraveShareTo/ShareToBraveViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,47 @@ import MobileCoreServices
import BraveShared

class ShareToBraveViewController: SLComposeServiceViewController {
private struct Scheme {
private enum SchemeType {
case url, query
}

private let type: SchemeType
private let urlOrQuery: String

init?(item: NSSecureCoding) {
if let text = item as? String {
urlOrQuery = text
type = .query
} else if let url = (item as? URL)?.absoluteString.firstURL?.absoluteString {
urlOrQuery = url
type = .url
} else {
return nil
}
}

var schemeUrl: URL? {
var components = URLComponents()
let queryItem: URLQueryItem

components.scheme = "brave"

switch type {
case .url:
components.host = "open-url"
queryItem = URLQueryItem(name: "url", value: urlOrQuery)
case .query:
components.host = "search"
queryItem = URLQueryItem(name: "q", value: urlOrQuery)
}

components.queryItems = [queryItem]
return components.url
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried to added URLComponents logic you've mentioned, what do you think?
I also deleted ".addingPercentEncoding" part since encoding is solved by URLComponents type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's even better, nice find

}

// TODO: Separate scheme for debug builds, so it can be tested without need to uninstall production app.
private func urlScheme(for url: String) -> URL? {
return URL(string: "brave://open-url?url=\(url)")
}

override func configurationItems() -> [Any]! {
guard let inputItems = extensionContext?.inputItems as? [NSExtensionItem] else {
Expand All @@ -34,24 +70,12 @@ class ShareToBraveViewController: SLComposeServiceViewController {
}

provider.loadItem(of: provider.isUrl ? kUTTypeURL : kUTTypeText) { item, error in
var urlItem: URL?

// We can get urls from other apps as a kUTTypeText type, for example from Apple's mail.app.
if let text = item as? String {
urlItem = text.firstURL
} else if let url = item as? URL {
urlItem = url.absoluteString.firstURL
} else {
guard let item = item, let schemeUrl = Scheme(item: item)?.schemeUrl else {
self.cancel()
return
}

// Just open the app if we don't find a url. In the future we could
// use this entry point to search instead of open a given URL
let urlString = urlItem?.absoluteString ?? ""
if let braveUrl = urlString.addingPercentEncoding(withAllowedCharacters: .alphanumerics).flatMap(self.urlScheme) {
self.handleUrl(braveUrl)
}
}

self.handleUrl(schemeUrl)
}

return []
Expand Down
3 changes: 3 additions & 0 deletions Client/Application/NavigationRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ enum NavigationPath: Equatable {
} else if urlString.starts(with: "\(scheme)://open-text") {
let text = components.valueForQuery("text")
self = .text(text ?? "")
} else if urlString.starts(with: "\(scheme)://search") {
let text = components.valueForQuery("q")
self = .text(text ?? "")
} else {
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion Client/Frontend/Browser/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ class BrowserViewController: UIViewController {
// This let's the user spam the Cmd+T button without lots of responder changes.
guard freshTab == self.tabManager.selectedTab else { return }
if let text = searchText {
self.topToolbar.setLocation(text, search: true)
self.topToolbar.submitLocation(text)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,15 @@ class TopToolbarView: UIView, ToolbarProtocol {
}
}

func submitLocation(_ location: String?) {
locationTextField?.text = location
guard let text = location, !text.isEmpty else {
return
}
// Not notifying when empty agrees with AutocompleteTextField.textDidChange.
delegate?.topToolbar(self, didSubmitText: text)
}

func enterOverlayMode(_ locationText: String?, pasted: Bool, search: Bool) {
createLocationTextField()

Expand Down
8 changes: 8 additions & 0 deletions ClientTests/NavigationRouterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ class NavigationRouterTests: XCTestCase {
XCTAssertEqual(badNav, NavigationPath.url(webURL: URL(string: "blah"), isPrivate: false))
}

func testSearchScheme() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding unit test for it

let query = "Foo Bar".addingPercentEncoding(withAllowedCharacters: .alphanumerics)!
let appURL = "\(appScheme)://search?q="+query
let navItem = NavigationPath(url: URL(string: appURL)!)!

XCTAssertEqual(navItem, NavigationPath.text("Foo Bar"))
}

func testDefaultNavigationPath() {
let url = URL(string: "https://duckduckgo.com")!
let appURL = URL(string: "\(self.appScheme)://open-url?url=\(url.absoluteString.escape()!)")!
Expand Down