<commit_before>/* 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 Shared
import SnapKit
import UIKit
import Storage

private struct LibraryViewControllerUX {
    // Height of the top panel switcher button toolbar.
    static let ButtonContainerHeight: CGFloat = 50
}

class LibraryViewController: UIViewController {
    let profile: Profile
    let panelDescriptors: [LibraryPanelDescriptor]

    weak var delegate: LibraryPanelDelegate?

    fileprivate lazy var buttonContainerView: UIStackView = {
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.alignment = .fill
        stackView.distribution = .fillEqually
        stackView.spacing = 14
        stackView.clipsToBounds = true
        stackView.accessibilityNavigationStyle = .combined
        stackView.accessibilityLabel = NSLocalizedString("Panel Chooser", comment: "Accessibility label for the Library panel's bottom toolbar containing a list of the home panels (top sites, bookmarks, history, remote tabs, reading list).")
        return stackView
    }()

    fileprivate var controllerContainerView = UIView()
    fileprivate var buttons: [LibraryPanelButton] = []

    fileprivate var buttonTintColor: UIColor?
    fileprivate var buttonSelectedTintColor: UIColor?

    init(profile: Profile) {
        self.profile = profile

        self.panelDescriptors = LibraryPanels(profile: profile).enabledPanels

        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.theme.browser.background
        self.edgesForExtendedLayout = []

        view.addSubview(buttonContainerView)
        view.addSubview(controllerContainerView)

        buttonContainerView.snp.makeConstraints { make in
            make.bottom.equalTo(self.view.safeArea.bottom)
            make.leading.trailing.equalTo(self.view).inset(14)
            make.height.equalTo(LibraryViewControllerUX.ButtonContainerHeight)
        }

        controllerContainerView.snp.makeConstraints { make in
            make.leading.trailing.top.equalTo(self.view)
            make.bottom.equalTo(buttonContainerView.snp.top)
        }

        updateButtons()
        applyTheme()
        if selectedPanel == nil {
            selectedPanel = .bookmarks
        }
    }

    var selectedPanel: LibraryPanelType? = nil {
        didSet {
            if oldValue == selectedPanel {
                // Prevent flicker, allocations, and disk access: avoid duplicate view controllers.
                return
            }

            if let index = oldValue?.rawValue {
                if index < buttons.count {
                    let currentButton = buttons[index]
                    currentButton.isSelected = false
                    currentButton.isUserInteractionEnabled = true
                }
            }

            hideCurrentPanel()

            if let index = selectedPanel?.rawValue {
                if index < buttons.count {
                    let newButton = buttons[index]
                    newButton.isSelected = true
                    newButton.isUserInteractionEnabled = false
                }

                if index < panelDescriptors.count {
                    let panel = self.panelDescriptors[index].viewController
                    let navigationController = self.panelDescriptors[index].navigationController
                    let accessibilityLabel = self.panelDescriptors[index].accessibilityLabel
                    setupLibraryPanel(panel, accessibilityLabel: accessibilityLabel)
                    self.showPanel(navigationController)
                }
            }
            self.updateButtonTints()
        }
    }

    func setupLibraryPanel(_ panel: UIViewController, accessibilityLabel: String) {
        (panel as? LibraryPanel)?.libraryPanelDelegate = self
        panel.view.accessibilityNavigationStyle = .combined
        panel.view.accessibilityLabel = accessibilityLabel
        panel.title = accessibilityLabel
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

    fileprivate func hideCurrentPanel() {
        if let panel = children.first {
            panel.willMove(toParent: nil)
            panel.beginAppearanceTransition(false, animated: false)
            panel.view.removeFromSuperview()
            panel.endAppearanceTransition()
            panel.removeFromParent()
        }
    }

    fileprivate func showPanel(_ panel: UIViewController) {
        addChild(panel)
        panel.beginAppearanceTransition(true, animated: false)
        controllerContainerView.addSubview(panel.view)
        panel.endAppearanceTransition()
        panel.view.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        panel.didMove(toParent: self)
    }

    @objc func tappedButton(_ sender: UIButton!) {
        for (index, button) in buttons.enumerated() where button == sender {
            selectedPanel = LibraryPanelType(rawValue: index)
            if selectedPanel == .bookmarks {
                UnifiedTelemetry.recordEvent(category: .action, method: .view, object: .bookmarksPanel, value: .homePanelTabButton)<commit_msg>Fix #4916 - Add second tap to return to root in Library tabs (#4922)<commit_after>/* 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 Shared
import SnapKit
import UIKit
import Storage

private struct LibraryViewControllerUX {
    // Height of the top panel switcher button toolbar.
    static let ButtonContainerHeight: CGFloat = 50
}

class LibraryViewController: UIViewController {
    let profile: Profile
    let panelDescriptors: [LibraryPanelDescriptor]

    weak var delegate: LibraryPanelDelegate?

    fileprivate lazy var buttonContainerView: UIStackView = {
        let stackView = UIStackView()
        stackView.axis = .horizontal
        stackView.alignment = .fill
        stackView.distribution = .fillEqually
        stackView.spacing = 14
        stackView.clipsToBounds = true
        stackView.accessibilityNavigationStyle = .combined
        stackView.accessibilityLabel = NSLocalizedString("Panel Chooser", comment: "Accessibility label for the Library panel's bottom toolbar containing a list of the home panels (top sites, bookmarks, history, remote tabs, reading list).")
        return stackView
    }()

    fileprivate var controllerContainerView = UIView()
    fileprivate var buttons: [LibraryPanelButton] = []

    fileprivate var buttonTintColor: UIColor?
    fileprivate var buttonSelectedTintColor: UIColor?

    init(profile: Profile) {
        self.profile = profile

        self.panelDescriptors = LibraryPanels(profile: profile).enabledPanels

        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.theme.browser.background
        self.edgesForExtendedLayout = []

        view.addSubview(buttonContainerView)
        view.addSubview(controllerContainerView)

        buttonContainerView.snp.makeConstraints { make in
            make.bottom.equalTo(self.view.safeArea.bottom)
            make.leading.trailing.equalTo(self.view).inset(14)
            make.height.equalTo(LibraryViewControllerUX.ButtonContainerHeight)
        }

        controllerContainerView.snp.makeConstraints { make in
            make.leading.trailing.top.equalTo(self.view)
            make.bottom.equalTo(buttonContainerView.snp.top)
        }

        updateButtons()
        applyTheme()
        if selectedPanel == nil {
            selectedPanel = .bookmarks
        }
    }

    var selectedPanel: LibraryPanelType? = nil {
        didSet {
            if oldValue == selectedPanel {
                // Prevent flicker, allocations, and disk access: avoid duplicate view controllers.
                return
            }

            if let index = oldValue?.rawValue {
                if index < buttons.count {
                    let currentButton = buttons[index]
                    currentButton.isSelected = false
                }
            }

            hideCurrentPanel()

            if let index = selectedPanel?.rawValue {
                if index < buttons.count {
                    let newButton = buttons[index]
                    newButton.isSelected = true
                }

                if index < panelDescriptors.count {
                    let panel = self.panelDescriptors[index].viewController
                    let navigationController = self.panelDescriptors[index].navigationController
                    let accessibilityLabel = self.panelDescriptors[index].accessibilityLabel
                    setupLibraryPanel(panel, accessibilityLabel: accessibilityLabel)
                    self.showPanel(navigationController)
                }
            }
            self.updateButtonTints()
        }
    }

    func setupLibraryPanel(_ panel: UIViewController, accessibilityLabel: String) {
        (panel as? LibraryPanel)?.libraryPanelDelegate = self
        panel.view.accessibilityNavigationStyle = .combined
        panel.view.accessibilityLabel = accessibilityLabel
        panel.title = accessibilityLabel
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

    fileprivate func hideCurrentPanel() {
        if let panel = children.first {
            panel.willMove(toParent: nil)
            panel.beginAppearanceTransition(false, animated: false)
            panel.view.removeFromSuperview()
            panel.endAppearanceTransition()
            panel.removeFromParent()
        }
    }

    fileprivate func showPanel(_ panel: UIViewController) {
        addChild(panel)
        panel.beginAppearanceTransition(true, animated: false)
        controllerContainerView.addSubview(panel.view)
        panel.endAppearanceTransition()
        panel.view.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        panel.didMove(toParent: self)
    }

    @objc func tappedButton(_ sender: UIButton!) {
        for (index, button) in buttons.enumerated() where button == sender {
            let newSelectedPanel = LibraryPanelType(rawValue: index)

            // If we're already on the selected panel and the user has
            // tapped for a second time, pop it to the root view controller.
            if newSelectedPanel == selectedPanel {
                let panel = self.panelDescriptors[safe: index]?.navigationController
                panel?.popToRootViewController(animated: true)
            }

            selectedPanel = newSelectedPanel
            if selectedPanel == .bookmarks {
                UnifiedTelemetry.recordEvent(category: .action, method: .view, object: .bookmarksPanel, value: .homePanelTabButton)
{'fraction_non_alphanumeric': 0.07293041259787103, 'fraction_numerical': 0.0024632708718219406, 'mean_word_length': 2.319124087591241, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2761940', 'n_tokens_mistral': 2869, 'n_tokens_neox': 2724, 'n_words': 702}