160 lines
5.5 KiB
Swift
160 lines
5.5 KiB
Swift
//
|
|
// URLBar.swift
|
|
// SBrowser
|
|
//
|
|
// Created by James Magahern on 7/23/20.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
class URLBar: UIView
|
|
{
|
|
let textField = UITextField(frame: .zero)
|
|
let refreshButton = UIButton(frame: .zero)
|
|
|
|
public enum LoadProgress {
|
|
case complete
|
|
case loading(progress: Double)
|
|
}
|
|
|
|
public var loadProgress: LoadProgress = .complete {
|
|
didSet { updateProgressIndicator() }
|
|
}
|
|
|
|
private let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemThickMaterial))
|
|
private let progressIndicatorView = ProgressIndicatorView()
|
|
private let fadeMaskView = UIImageView(frame: .zero)
|
|
|
|
private let refreshImage = UIImage(systemName: "arrow.clockwise")
|
|
private let stopImage = UIImage(systemName: "xmark")
|
|
|
|
private let backgroundCornerRadius: CGFloat = 8
|
|
|
|
convenience init() {
|
|
self.init(frame: .zero)
|
|
|
|
backgroundColor = .clear
|
|
|
|
backgroundView.layer.masksToBounds = true
|
|
backgroundView.layer.cornerRadius = backgroundCornerRadius
|
|
backgroundView.layer.borderWidth = 1
|
|
backgroundView.layer.borderColor = UIColor.systemFill.cgColor
|
|
backgroundView.isUserInteractionEnabled = false
|
|
addSubview(backgroundView)
|
|
|
|
backgroundView.contentView.addSubview(progressIndicatorView)
|
|
|
|
textField.backgroundColor = .clear
|
|
textField.textContentType = .URL
|
|
textField.keyboardType = .webSearch
|
|
textField.autocorrectionType = .no
|
|
textField.autocapitalizationType = .none
|
|
textField.font = .systemFont(ofSize: 14.0)
|
|
textField.clearingBehavior = .clearOnInsertionAndShowSelectionTint
|
|
textField.clearButtonMode = .whileEditing
|
|
addSubview(textField)
|
|
|
|
textField.addAction(.init(handler: { _ in
|
|
self.refreshButton.isHidden = self.textField.isFirstResponder
|
|
}), for: [ .editingDidBegin, .editingDidEnd ])
|
|
|
|
refreshButton.tintColor = .secondaryLabel
|
|
refreshButton.setImage(refreshImage, for: .normal)
|
|
addSubview(refreshButton)
|
|
}
|
|
|
|
private func updateProgressIndicator() {
|
|
UIView.animate(withDuration: 0.4) {
|
|
switch self.loadProgress {
|
|
case .complete:
|
|
self.refreshButton.setImage(self.refreshImage, for: .normal)
|
|
self.progressIndicatorView.progress = 1.0
|
|
UIView.animate(withDuration: 0.5, delay: 0.5, options: AnimationOptions()) {
|
|
self.progressIndicatorView.alpha = 0.0
|
|
} completion: { _ in
|
|
// Reset back to zero
|
|
self.progressIndicatorView.progress = 0.0
|
|
}
|
|
case .loading(let progress):
|
|
self.refreshButton.setImage(self.stopImage, for: .normal)
|
|
self.progressIndicatorView.progress = progress
|
|
self.progressIndicatorView.alpha = 1.0
|
|
}
|
|
}
|
|
}
|
|
|
|
override var intrinsicContentSize: CGSize {
|
|
let preferredHeight = CGFloat(34)
|
|
return CGSize(width: 1000.0, height: preferredHeight)
|
|
}
|
|
|
|
private func fadeBackgroundImageForSize(_ size: CGSize) -> UIImage? {
|
|
var image: UIImage? = nil
|
|
|
|
UIGraphicsBeginImageContext(CGSize(width: size.width, height: 1.0))
|
|
if let context = UIGraphicsGetCurrentContext() {
|
|
let gradientColorsArray = [
|
|
UIColor(white: 1.0, alpha: 1.0).cgColor,
|
|
UIColor(white: 1.0, alpha: 1.0).cgColor,
|
|
UIColor(white: 1.0, alpha: 0.08).cgColor,
|
|
UIColor(white: 1.0, alpha: 0.08).cgColor
|
|
]
|
|
|
|
let locations: [CGFloat] = [
|
|
0.0, 0.80, 0.90, 1.0
|
|
]
|
|
|
|
if let gradient = CGGradient(colorsSpace: nil, colors: gradientColorsArray as CFArray, locations: locations) {
|
|
context.drawLinearGradient(gradient, start: .zero, end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
|
}
|
|
|
|
image = UIGraphicsGetImageFromCurrentImageContext()
|
|
UIGraphicsEndImageContext();
|
|
}
|
|
|
|
return image
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
backgroundView.frame = bounds
|
|
progressIndicatorView.frame = backgroundView.contentView.bounds
|
|
textField.frame = bounds.insetBy(dx: 6.0, dy: 0)
|
|
|
|
fadeMaskView.frame = textField.bounds
|
|
fadeMaskView.image = fadeBackgroundImageForSize(fadeMaskView.frame.size)
|
|
if !textField.isFirstResponder {
|
|
textField.mask = fadeMaskView
|
|
} else {
|
|
textField.mask = nil
|
|
}
|
|
|
|
let refreshButtonSize = CGSize(width: textField.frame.height, height: textField.frame.height)
|
|
refreshButton.frame = CGRect(origin: CGPoint(x: bounds.width - refreshButtonSize.width, y: 0), size: refreshButtonSize)
|
|
}
|
|
}
|
|
|
|
class ProgressIndicatorView: UIView
|
|
{
|
|
public var progress: Double = 0.0 {
|
|
didSet { layoutSubviews() }
|
|
}
|
|
|
|
private let progressFillView = UIView(frame: .zero)
|
|
|
|
convenience init() {
|
|
self.init(frame: .zero)
|
|
|
|
progressFillView.backgroundColor = .systemBlue
|
|
progressFillView.alpha = 0.3
|
|
addSubview(progressFillView)
|
|
}
|
|
|
|
override func layoutSubviews() {
|
|
super.layoutSubviews()
|
|
|
|
let width = CGFloat(progress) * bounds.width
|
|
progressFillView.frame = CGRect(origin: .zero, size: CGSize(width: width, height: bounds.height))
|
|
}
|
|
}
|