mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 00:08:39 +09:00
315 lines
13 KiB
Swift
315 lines
13 KiB
Swift
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import SnapKit
|
|
import Shared
|
|
import XCGLogger
|
|
|
|
private let log = Logger.browserLogger
|
|
|
|
protocol TabToolbarProtocol: class {
|
|
weak var tabToolbarDelegate: TabToolbarDelegate? { get set }
|
|
var tabsButton: TabsButton { get }
|
|
var menuButton: ToolbarButton { get }
|
|
var forwardButton: ToolbarButton { get }
|
|
var backButton: ToolbarButton { get }
|
|
var stopReloadButton: ToolbarButton { get }
|
|
var actionButtons: [Themeable & UIButton] { get }
|
|
|
|
func updateBackStatus(_ canGoBack: Bool)
|
|
func updateForwardStatus(_ canGoForward: Bool)
|
|
func updateReloadStatus(_ isLoading: Bool)
|
|
func updatePageStatus(_ isWebPage: Bool)
|
|
func updateTabCount(_ count: Int, animated: Bool)
|
|
}
|
|
|
|
protocol TabToolbarDelegate: class {
|
|
func tabToolbarDidPressBack(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidPressForward(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidLongPressBack(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidLongPressForward(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidPressReload(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidLongPressReload(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidPressStop(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidPressMenu(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidPressTabs(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
func tabToolbarDidLongPressTabs(_ tabToolbar: TabToolbarProtocol, button: UIButton)
|
|
}
|
|
|
|
@objc
|
|
open class TabToolbarHelper: NSObject {
|
|
let toolbar: TabToolbarProtocol
|
|
|
|
let ImageReload = UIImage.templateImageNamed("nav-refresh")
|
|
let ImageStop = UIImage.templateImageNamed("nav-stop")
|
|
|
|
var loading: Bool = false {
|
|
didSet {
|
|
if loading {
|
|
toolbar.stopReloadButton.setImage(ImageStop, for: .normal)
|
|
toolbar.stopReloadButton.accessibilityLabel = NSLocalizedString("Stop", comment: "Accessibility Label for the tab toolbar Stop button")
|
|
} else {
|
|
toolbar.stopReloadButton.setImage(ImageReload, for: .normal)
|
|
toolbar.stopReloadButton.accessibilityLabel = NSLocalizedString("Reload", comment: "Accessibility Label for the tab toolbar Reload button")
|
|
}
|
|
}
|
|
}
|
|
|
|
fileprivate func setTheme(theme: String, forButtons buttons: [Themeable]) {
|
|
buttons.forEach { $0.applyTheme(theme) }
|
|
}
|
|
|
|
init(toolbar: TabToolbarProtocol) {
|
|
self.toolbar = toolbar
|
|
super.init()
|
|
|
|
toolbar.backButton.setImage(UIImage.templateImageNamed("nav-back"), for: .normal)
|
|
toolbar.backButton.accessibilityLabel = NSLocalizedString("Back", comment: "Accessibility label for the Back button in the tab toolbar.")
|
|
let longPressGestureBackButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressBack(_:)))
|
|
toolbar.backButton.addGestureRecognizer(longPressGestureBackButton)
|
|
toolbar.backButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickBack), for: UIControlEvents.touchUpInside)
|
|
|
|
toolbar.forwardButton.setImage(UIImage.templateImageNamed("nav-forward"), for: .normal)
|
|
toolbar.forwardButton.accessibilityLabel = NSLocalizedString("Forward", comment: "Accessibility Label for the tab toolbar Forward button")
|
|
let longPressGestureForwardButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressForward(_:)))
|
|
toolbar.forwardButton.addGestureRecognizer(longPressGestureForwardButton)
|
|
toolbar.forwardButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickForward), for: UIControlEvents.touchUpInside)
|
|
|
|
toolbar.stopReloadButton.setImage(UIImage.templateImageNamed("nav-refresh"), for: .normal)
|
|
toolbar.stopReloadButton.accessibilityLabel = NSLocalizedString("Reload", comment: "Accessibility Label for the tab toolbar Reload button")
|
|
let longPressGestureStopReloadButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressStopReload(_:)))
|
|
toolbar.stopReloadButton.addGestureRecognizer(longPressGestureStopReloadButton)
|
|
toolbar.stopReloadButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickStopReload), for: UIControlEvents.touchUpInside)
|
|
|
|
toolbar.tabsButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickTabs), for: .touchUpInside)
|
|
let longPressGestureTabsButton = UILongPressGestureRecognizer(target: self, action: #selector(TabToolbarHelper.SELdidLongPressTabs(_:)))
|
|
toolbar.tabsButton.addGestureRecognizer(longPressGestureTabsButton)
|
|
|
|
toolbar.menuButton.contentMode = UIViewContentMode.center
|
|
toolbar.menuButton.setImage(UIImage.templateImageNamed("nav-menu"), for: .normal)
|
|
toolbar.menuButton.accessibilityLabel = Strings.AppMenuButtonAccessibilityLabel
|
|
toolbar.menuButton.addTarget(self, action: #selector(TabToolbarHelper.SELdidClickMenu), for: UIControlEvents.touchUpInside)
|
|
toolbar.menuButton.accessibilityIdentifier = "TabToolbar.menuButton"
|
|
setTheme(theme: Theme.NormalMode, forButtons: toolbar.actionButtons)
|
|
}
|
|
|
|
func SELdidClickBack() {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidPressBack(toolbar, button: toolbar.backButton)
|
|
}
|
|
|
|
func SELdidLongPressBack(_ recognizer: UILongPressGestureRecognizer) {
|
|
if recognizer.state == UIGestureRecognizerState.began {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidLongPressBack(toolbar, button: toolbar.backButton)
|
|
}
|
|
}
|
|
|
|
func SELdidClickTabs() {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidPressTabs(toolbar, button: toolbar.tabsButton)
|
|
}
|
|
|
|
func SELdidLongPressTabs(_ recognizer: UILongPressGestureRecognizer) {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidLongPressTabs(toolbar, button: toolbar.tabsButton)
|
|
}
|
|
|
|
func SELdidClickForward() {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidPressForward(toolbar, button: toolbar.forwardButton)
|
|
}
|
|
|
|
func SELdidLongPressForward(_ recognizer: UILongPressGestureRecognizer) {
|
|
if recognizer.state == UIGestureRecognizerState.began {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidLongPressForward(toolbar, button: toolbar.forwardButton)
|
|
}
|
|
}
|
|
|
|
func SELdidClickMenu() {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidPressMenu(toolbar, button: toolbar.menuButton)
|
|
}
|
|
|
|
func SELdidClickStopReload() {
|
|
if loading {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidPressStop(toolbar, button: toolbar.stopReloadButton)
|
|
} else {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidPressReload(toolbar, button: toolbar.stopReloadButton)
|
|
}
|
|
}
|
|
|
|
func SELdidLongPressStopReload(_ recognizer: UILongPressGestureRecognizer) {
|
|
if recognizer.state == UIGestureRecognizerState.began && !loading {
|
|
toolbar.tabToolbarDelegate?.tabToolbarDidLongPressReload(toolbar, button: toolbar.stopReloadButton)
|
|
}
|
|
}
|
|
|
|
func updateReloadStatus(_ isLoading: Bool) {
|
|
loading = isLoading
|
|
}
|
|
}
|
|
|
|
class ToolbarButton: UIButton {
|
|
static let Themes: [String: Theme] = {
|
|
var themes = [String: Theme]()
|
|
var theme = Theme()
|
|
theme.buttonTintColor = UIColor(rgb: 0xd2d2d4)
|
|
theme.highlightButtonColor = UIColor(rgb: 0xAC39FF)
|
|
theme.disabledButtonColor = UIColor.gray
|
|
themes[Theme.PrivateMode] = theme
|
|
|
|
theme = Theme()
|
|
theme.buttonTintColor = UIColor(rgb: 0x272727)
|
|
theme.highlightButtonColor = UIColor(rgb: 0x00A2FE)
|
|
theme.disabledButtonColor = UIColor.lightGray
|
|
themes[Theme.NormalMode] = theme
|
|
|
|
return themes
|
|
}()
|
|
|
|
var selectedTintColor: UIColor!
|
|
var unselectedTintColor: UIColor!
|
|
var disabledTintColor: UIColor!
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
adjustsImageWhenHighlighted = false
|
|
selectedTintColor = tintColor
|
|
unselectedTintColor = tintColor
|
|
disabledTintColor = UIColor.gray
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override open var isHighlighted: Bool {
|
|
didSet {
|
|
self.tintColor = isHighlighted ? selectedTintColor : unselectedTintColor
|
|
}
|
|
}
|
|
|
|
override open var isEnabled: Bool {
|
|
didSet {
|
|
self.tintColor = isEnabled ? unselectedTintColor : disabledTintColor
|
|
}
|
|
}
|
|
|
|
override var tintColor: UIColor! {
|
|
didSet {
|
|
self.imageView?.tintColor = self.tintColor
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
extension ToolbarButton: Themeable {
|
|
func applyTheme(_ themeName: String) {
|
|
guard let theme = ToolbarButton.Themes[themeName] else {
|
|
log.error("Unable to apply unknown theme \(themeName)")
|
|
return
|
|
}
|
|
selectedTintColor = theme.highlightButtonColor
|
|
disabledTintColor = theme.disabledButtonColor
|
|
unselectedTintColor = theme.buttonTintColor
|
|
tintColor = isEnabled ? unselectedTintColor : disabledTintColor
|
|
imageView?.tintColor = tintColor
|
|
}
|
|
}
|
|
|
|
class TabToolbar: Toolbar, TabToolbarProtocol {
|
|
weak var tabToolbarDelegate: TabToolbarDelegate?
|
|
|
|
let tabsButton: TabsButton
|
|
let menuButton: ToolbarButton
|
|
let forwardButton: ToolbarButton
|
|
let backButton: ToolbarButton
|
|
let stopReloadButton: ToolbarButton
|
|
let actionButtons: [Themeable & UIButton]
|
|
|
|
var helper: TabToolbarHelper?
|
|
|
|
static let Themes: [String: Theme] = {
|
|
var themes = [String: Theme]()
|
|
var theme = Theme()
|
|
theme.backgroundColor = UIColor(rgb: 0x38383D)
|
|
themes[Theme.PrivateMode] = theme
|
|
|
|
theme = Theme()
|
|
theme.backgroundColor = UIConstants.AppBackgroundColor
|
|
themes[Theme.NormalMode] = theme
|
|
|
|
return themes
|
|
}()
|
|
|
|
// This has to be here since init() calls it
|
|
fileprivate override init(frame: CGRect) {
|
|
// And these have to be initialized in here or the compiler will get angry
|
|
backButton = ToolbarButton()
|
|
backButton.accessibilityIdentifier = "TabToolbar.backButton"
|
|
forwardButton = ToolbarButton()
|
|
forwardButton.accessibilityIdentifier = "TabToolbar.forwardButton"
|
|
stopReloadButton = ToolbarButton()
|
|
stopReloadButton.accessibilityIdentifier = "TabToolbar.stopReloadButton"
|
|
tabsButton = TabsButton()
|
|
tabsButton.accessibilityIdentifier = "TabToolbar.tabsButton"
|
|
menuButton = ToolbarButton()
|
|
menuButton.accessibilityIdentifier = "TabToolbar.menuButton"
|
|
actionButtons = [backButton, forwardButton, stopReloadButton, tabsButton, menuButton]
|
|
|
|
super.init(frame: frame)
|
|
|
|
helper = TabToolbarHelper(toolbar: self)
|
|
addButtons(actionButtons)
|
|
|
|
accessibilityNavigationStyle = .combined
|
|
accessibilityLabel = NSLocalizedString("Navigation Toolbar", comment: "Accessibility label for the navigation toolbar displayed at the bottom of the screen.")
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func updateBackStatus(_ canGoBack: Bool) {
|
|
backButton.isEnabled = canGoBack
|
|
}
|
|
|
|
func updateForwardStatus(_ canGoForward: Bool) {
|
|
forwardButton.isEnabled = canGoForward
|
|
}
|
|
|
|
func updateReloadStatus(_ isLoading: Bool) {
|
|
helper?.updateReloadStatus(isLoading)
|
|
}
|
|
|
|
func updatePageStatus(_ isWebPage: Bool) {
|
|
stopReloadButton.isEnabled = isWebPage
|
|
}
|
|
|
|
func updateTabCount(_ count: Int, animated: Bool) {
|
|
tabsButton.updateTabCount(count, animated: animated)
|
|
}
|
|
|
|
override func draw(_ rect: CGRect) {
|
|
if let context = UIGraphicsGetCurrentContext() {
|
|
drawLine(context, start: CGPoint(x: 0, y: 0), end: CGPoint(x: frame.width, y: 0))
|
|
}
|
|
}
|
|
|
|
fileprivate func drawLine(_ context: CGContext, start: CGPoint, end: CGPoint) {
|
|
context.setStrokeColor(UIColor.black.withAlphaComponent(0.05).cgColor)
|
|
context.setLineWidth(2)
|
|
context.move(to: CGPoint(x: start.x, y: start.y))
|
|
context.addLine(to: CGPoint(x: end.x, y: end.y))
|
|
context.strokePath()
|
|
}
|
|
}
|
|
|
|
extension TabToolbar: Themeable {
|
|
func applyTheme(_ themeName: String) {
|
|
guard let theme = TabToolbar.Themes[themeName] else {
|
|
log.error("Unable to apply unknown theme \(themeName)")
|
|
return
|
|
}
|
|
backgroundColor = theme.backgroundColor!
|
|
helper?.setTheme(theme: themeName, forButtons: actionButtons)
|
|
}
|
|
}
|