// // ResourceDownloadStatusToolbar.swift // KeymanEngine // // Created by Joshua Horton on 8/14/19. // Copyright © 2019 SIL International. All rights reserved. // import Foundation import UIKit public class ResourceDownloadStatusToolbar: UIToolbar { private var statusLabel: UILabel? private var activityIndicator: UIActivityIndicatorView? private var actionButton: UIButton? private var _navigationController: UINavigationController? override init(frame: CGRect) { super.init(frame: frame) setup() } // Only here because it's required by Swift. required init?(coder: NSCoder) { super.init(coder: coder) } public var navigationController: UINavigationController? { get { return _navigationController } set { _navigationController = newValue } } private func setup() { barTintColor = Colors.statusToolbar } /** * Creates a simple text label for indicating current status without allowing interactivity. */ private func setupStatusLabel() -> UILabel { let labelFrame = CGRect(origin: frame.origin, size: CGSize(width: frame.width * 0.95, height: frame.height * 0.7)) let label = UILabel(frame: labelFrame) label.backgroundColor = UIColor.clear label.textColor = UIColor.white label.textAlignment = .center label.center = CGPoint(x: frame.width * 0.5, y: frame.height * 0.5) label.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin, .flexibleWidth, .flexibleHeight] return label } /** * Creates the classic spinning-wheel 'activity in progress' indicator. */ private func setupActivityIndicator() -> UIActivityIndicatorView { let indicatorView = UIActivityIndicatorView(style: .gray) indicatorView.center = CGPoint(x: frame.width - indicatorView.frame.width, y: frame.height * 0.5) indicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin, .flexibleBottomMargin] indicatorView.startAnimating() return indicatorView } private func setupActionButton(_ text: String, for handler: Any?, onClick: Selector) -> UIButton { let button = UIButton(type: .roundedRect) button.addTarget(handler, action: onClick, for: .touchUpInside) button.frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: frame.width * 0.95, height: frame.height * 0.7) button.center = CGPoint(x: frame.width / 2, y: frame.height / 2) button.tintColor = Colors.statusResourceUpdateButton button.setTitleColor(UIColor.white, for: .normal) button.setTitle(text, for: .normal) button.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin, .flexibleWidth, .flexibleHeight] return button } private func clearSubviews() { statusLabel?.removeFromSuperview() activityIndicator?.removeFromSuperview() actionButton?.removeFromSuperview() } public func displayStatus(_ text: String, withIndicator: Bool, duration: TimeInterval? = nil) { clearSubviews() statusLabel = setupStatusLabel() statusLabel!.text = text addSubview(statusLabel!) if withIndicator { activityIndicator = setupActivityIndicator() addSubview(activityIndicator!) } // Automatically display if we're hidden and have access to our owning UINavigationController. if navigationController?.isToolbarHidden ?? false { navigationController!.setToolbarHidden(false, animated: true) } if let timeout = duration { hideAfterDelay(timeout: timeout) } } public func displayButton(_ text: String, with target: Any?, callback: Selector) { clearSubviews() // This forces iOS to create any intervening default UIToolbar subviews that may exist by default. // Anything added afterward will be placed on top of those, enabling interactivity. layoutIfNeeded() actionButton = setupActionButton(text, for: target, onClick: callback) addSubview(actionButton!) bringSubviewToFront(actionButton!) // Automatically display if we're hidden and have access to our owning UINavigationController. if navigationController?.isToolbarHidden ?? false { navigationController!.setToolbarHidden(false, animated: true) } } private func hideAfterDelay(timeout: TimeInterval) { Timer.scheduledTimer(timeInterval: timeout, target: self, selector: #selector(self.delayedHide), userInfo: nil, repeats: false) } @objc private func delayedHide() { // If the navigation controller exists and the toolbar is not hidden. The ! + true literal together // give false for the condition when the navigation controller does not exist. if !(navigationController?.isToolbarHidden ?? true) { navigationController!.setToolbarHidden(true, animated: true) } } }