spiegel-keyman/ios/engine/KMEI/KeymanEngine/Classes/ResourceDownloadStatusToolbar.swift
Shawn Schantz 610ccc11c2 Revert "maint(ios): resolved warnings for Xcode 26"
This reverts commit a91f098ed6.
Apply these changes in a separate PR.
2026-02-23 13:38:01 -05:00

156 lines
5.4 KiB
Swift

//
// 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
// For scenarios where the system wants to make the toolbar translucent,
// we additionally need the actual background color to be set.
let appearance = UIToolbarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = Colors.statusToolbar
standardAppearance = appearance
// And, for good measure, try to prevent special scrolling-edge appearance changes outright.
scrollEdgeAppearance = appearance
}
/**
* 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)
}
}
}