Implemented find on page UI
This commit is contained in:
71
App/Find on Page/FindOnPageView.swift
Normal file
71
App/Find on Page/FindOnPageView.swift
Normal file
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// FindOnPageView.swift
|
||||
// App
|
||||
//
|
||||
// Created by James Magahern on 9/30/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FindOnPageView: UIView
|
||||
{
|
||||
let textField = UISearchTextField(frame: .zero)
|
||||
|
||||
let doneButton = ReliefButton()
|
||||
let nextResultButton = ReliefButton()
|
||||
let prevResultButton = ReliefButton()
|
||||
|
||||
private let arrowControls = SegmentedReliefButton(children: [])
|
||||
|
||||
let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial))
|
||||
|
||||
convenience init() {
|
||||
self.init(frame: .zero)
|
||||
|
||||
arrowControls.children = [ prevResultButton, nextResultButton ]
|
||||
|
||||
addSubview(backgroundView)
|
||||
addSubview(textField)
|
||||
addSubview(doneButton)
|
||||
addSubview(arrowControls)
|
||||
|
||||
textField.autocapitalizationType = .none
|
||||
textField.autocorrectionType = .no
|
||||
|
||||
doneButton.setTitle("Done", for: .normal)
|
||||
doneButton.setTitleColor(.label, for: .normal)
|
||||
doneButton.constrainedToSquare = false
|
||||
|
||||
nextResultButton.setImage(UIImage(systemName: "chevron.down"), for: .normal)
|
||||
prevResultButton.setImage(UIImage(systemName: "chevron.up"), for: .normal)
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
backgroundView.frame = bounds
|
||||
|
||||
let bounds = self.bounds
|
||||
.insetBy(dx: 8.0, dy: 8.0)
|
||||
.inset(by: safeAreaInsets)
|
||||
|
||||
let doneButtonPadding: CGFloat = 8.0
|
||||
let doneButtonSize = doneButton.sizeThatFits(bounds.size)
|
||||
doneButton.frame = CGRect(
|
||||
x: bounds.width - doneButtonSize.width, y: bounds.minY,
|
||||
width: doneButtonSize.width + doneButtonPadding, height: bounds.height
|
||||
)
|
||||
|
||||
let arrowControlsSize = arrowControls.sizeThatFits(bounds.size)
|
||||
arrowControls.frame = CGRect(
|
||||
x: doneButton.frame.minX - doneButtonPadding - arrowControlsSize.width, y: bounds.minY,
|
||||
width: arrowControlsSize.width, height: bounds.height
|
||||
)
|
||||
|
||||
textField.frame = CGRect(
|
||||
x: bounds.minX, y: bounds.minY,
|
||||
width: arrowControls.frame.minX - bounds.minX - doneButtonPadding,
|
||||
height: bounds.height
|
||||
)
|
||||
}
|
||||
}
|
||||
98
App/Find on Page/FindOnPageViewController.swift
Normal file
98
App/Find on Page/FindOnPageViewController.swift
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// FindOnPageViewController.swift
|
||||
// App
|
||||
//
|
||||
// Created by James Magahern on 9/30/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class FindOnPageViewController: UIViewController, _WKFindDelegate
|
||||
{
|
||||
let findOnPageView = FindOnPageView()
|
||||
weak var webView: WKWebView? {
|
||||
didSet { webView?._findDelegate = self }
|
||||
}
|
||||
|
||||
private var findString: String?
|
||||
private let findOptions: _WKFindOptions = [
|
||||
.caseInsensitive,
|
||||
.atWordStarts,
|
||||
.treatMedialCapitalAsWordStart,
|
||||
.wrapAround,
|
||||
.showFindIndicator,
|
||||
.showOverlay,
|
||||
.showHighlight,
|
||||
.determineMatchIndex,
|
||||
]
|
||||
|
||||
private let maxCount: UInt = 1000
|
||||
|
||||
convenience init() {
|
||||
self.init(nibName: nil, bundle: nil)
|
||||
|
||||
findOnPageView.textField.addAction(UIAction(handler: { [unowned self] _ in
|
||||
self.findString = findOnPageView.textField.text
|
||||
webView?._find(self.findString, options: self.findOptions, maxCount: self.maxCount)
|
||||
}), for: .editingChanged)
|
||||
|
||||
findOnPageView.prevResultButton.addAction(UIAction(handler: { [unowned self] _ in
|
||||
findPrevious(nil)
|
||||
}), for: .touchUpInside)
|
||||
|
||||
findOnPageView.nextResultButton.addAction(UIAction(handler: { [unowned self] _ in
|
||||
findNext(nil)
|
||||
}), for: .touchUpInside)
|
||||
|
||||
findOnPageView.doneButton.addAction(UIAction(handler: { [unowned self] _ in
|
||||
doneFinding(nil)
|
||||
}), for: .touchUpInside)
|
||||
|
||||
// Escape to cancel
|
||||
addKeyCommand(UIKeyCommand(input: UIKeyCommand.inputEscape, modifierFlags: [], action: #selector(Self.doneFinding)))
|
||||
|
||||
// Return goes to next
|
||||
addKeyCommand(UIKeyCommand(input: "\n", modifierFlags: [], action: #selector(Self.findNext)))
|
||||
|
||||
// Cmd+G next
|
||||
addKeyCommand(UIKeyCommand(input: "G", modifierFlags: [.command], action: #selector(Self.findNext)))
|
||||
|
||||
// Shift return goes to prev
|
||||
addKeyCommand(UIKeyCommand(input: "\n", modifierFlags: [.shift], action: #selector(Self.findPrevious)))
|
||||
|
||||
// Shift+Cmd+G prev
|
||||
addKeyCommand(UIKeyCommand(input: "G", modifierFlags: [.command, .shift], action: #selector(Self.findPrevious)))
|
||||
|
||||
self.view = findOnPageView
|
||||
}
|
||||
|
||||
@objc
|
||||
func doneFinding(_ sender: Any?) {
|
||||
findOnPageView.textField.resignFirstResponder()
|
||||
webView?._hideFindUI()
|
||||
}
|
||||
|
||||
@objc
|
||||
func findNext(_ sender: Any?) {
|
||||
webView?._find(self.findString, options: self.findOptions, maxCount: self.maxCount)
|
||||
}
|
||||
|
||||
@objc
|
||||
func findPrevious(_ sender: Any?) {
|
||||
let options: _WKFindOptions = self.findOptions.union(.backwards)
|
||||
webView?._find(self.findString, options: options, maxCount: self.maxCount)
|
||||
}
|
||||
|
||||
func _webView(_ webView: WKWebView!, didFailToFind string: String!) {
|
||||
// ??
|
||||
}
|
||||
|
||||
func _webView(_ webView: WKWebView!, didCountMatches matches: UInt, for string: String!) {
|
||||
// TODO: Update a label
|
||||
}
|
||||
|
||||
func _webView(_ webView: WKWebView!, didFindMatches matches: UInt, for string: String!, withMatch matchIndex: Int) {
|
||||
findOnPageView.nextResultButton.isEnabled = matches > 0
|
||||
findOnPageView.prevResultButton.isEnabled = matches > 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user