Error state in URL bar

This commit is contained in:
James Magahern
2020-07-31 18:29:44 -07:00
parent 2a64636d61
commit 29c416374f
2 changed files with 100 additions and 7 deletions

View File

@@ -11,10 +11,12 @@ class URLBar: UIView
{
let textField = UITextField(frame: .zero)
let refreshButton = UIButton(frame: .zero)
let errorButton = UIButton(frame: .zero)
public enum LoadProgress {
case complete
case loading(progress: Double)
case error(error: Error)
}
public var loadProgress: LoadProgress = .complete {
@@ -65,9 +67,21 @@ class URLBar: UIView
refreshButton.tintColor = .secondaryLabel
refreshButton.setImage(refreshImage, for: .normal)
addSubview(refreshButton)
errorButton.backgroundColor = .systemRed
errorButton.layer.cornerRadius = 3.0
errorButton.layer.masksToBounds = true
errorButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11.0)
errorButton.setTitleColor(.white, for: .normal)
errorButton.setTitle("ERR", for: .normal)
addSubview(errorButton)
setErrorButtonAnimating(false)
}
private func updateProgressIndicator() {
setErrorButtonAnimating(false)
UIView.animate(withDuration: 0.4) {
switch self.loadProgress {
case .complete:
@@ -79,12 +93,26 @@ class URLBar: UIView
// 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
case .error(let error):
self.setErrorButtonAnimating(true)
self.progressIndicatorView.alpha = 0.0
self.progressIndicatorView.progress = 0.0
if let nserror = error as NSError? {
self.errorButton.setTitle("\(nserror.code)", for: .normal)
} else {
self.errorButton.setTitle("ERR", for: .normal)
}
}
}
self.setNeedsLayout()
}
override var intrinsicContentSize: CGSize {
@@ -92,7 +120,7 @@ class URLBar: UIView
return CGSize(width: 1000.0, height: preferredHeight)
}
private func fadeBackgroundImageForSize(_ size: CGSize) -> UIImage? {
private func fadeBackgroundImageForSize(_ size: CGSize, cutoffLocation: CGFloat) -> UIImage? {
var image: UIImage? = nil
UIGraphicsBeginImageContext(CGSize(width: size.width, height: 1.0))
@@ -105,7 +133,7 @@ class URLBar: UIView
]
let locations: [CGFloat] = [
0.0, 0.80, 0.90, 1.0
0.0, cutoffLocation, cutoffLocation + 0.10, 1.0
]
if let gradient = CGGradient(colorsSpace: nil, colors: gradientColorsArray as CFArray, locations: locations) {
@@ -119,22 +147,57 @@ class URLBar: UIView
return image
}
private func setErrorButtonAnimating(_ animating: Bool) {
let animationKey = "blinkAnimation"
if animating {
let blinkAnimation = CAKeyframeAnimation(keyPath: "opacity")
blinkAnimation.calculationMode = .discrete
blinkAnimation.values = [ 1.0, 0.1, 1.0 ]
blinkAnimation.keyTimes = [ 0.0, 0.5, 1.0 ]
blinkAnimation.duration = 1.0
blinkAnimation.repeatCount = .infinity
self.errorButton.isHidden = false
self.errorButton.layer.add(blinkAnimation, forKey: animationKey)
} else {
self.errorButton.isHidden = true
self.errorButton.layer.removeAnimation(forKey: animationKey)
}
}
override func layoutSubviews() {
super.layoutSubviews()
backgroundView.frame = bounds
progressIndicatorView.frame = backgroundView.contentView.bounds
textField.frame = bounds.insetBy(dx: 6.0, dy: 0)
var fadeCutoffLocation: CGFloat = 0.8
// Refresh button
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)
// Error button
if case .error(error: _) = loadProgress {
errorButton.sizeToFit()
errorButton.frame = CGRect(
x: refreshButton.frame.minX - errorButton.frame.width - 8.0,
y: 0.0,
width: errorButton.frame.width + 8.0,
height: 22.0
)
errorButton.frame = errorButton.frame.centeredY(inRect: bounds)
fadeCutoffLocation = (errorButton.frame.minX / bounds.width) - 0.1
}
// Fade mask
fadeMaskView.frame = textField.bounds
fadeMaskView.image = fadeBackgroundImageForSize(fadeMaskView.frame.size)
fadeMaskView.image = fadeBackgroundImageForSize(fadeMaskView.frame.size, cutoffLocation: fadeCutoffLocation)
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)
}
}