<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 UIKit
import Shared
import XCGLogger
import Storage
import WebImage
import Deferred

private let log = Logger.browserLogger

private let ThumbnailIdentifier = "Thumbnail"

extension CGSize {
    public func widthLargerOrEqualThanHalfIPad() -> Bool {
        let halfIPadSize: CGFloat = 507
        return width >= halfIPadSize
    }
}

struct TopSitesPanelUX {
    fileprivate static let EmptyStateTitleTextColor = UIColor.darkGray
    fileprivate static let EmptyStateTopPaddingInBetweenItems: CGFloat = 15
    fileprivate static let WelcomeScreenPadding: CGFloat = 15
    fileprivate static let WelcomeScreenItemTextColor = UIColor.gray
    fileprivate static let WelcomeScreenItemWidth = 170
}

class TopSitesPanel: UIViewController {
    weak var homePanelDelegate: HomePanelDelegate?
    fileprivate lazy var emptyStateOverlayView: UIView = self.createEmptyStateOverlayView()
    fileprivate var collection: TopSitesCollectionView? = nil
    fileprivate var privateTabMessageContainer: UIView!
    fileprivate var privateTabGraphic: UIImageView!
    fileprivate var privateTabTitleLabel: UILabel!
    fileprivate var privateTabInfoLabel: UILabel!
    fileprivate var privateTabLinkButton: UIButton!
    fileprivate var braveShieldStatsView: BraveShieldStatsView? = nil
    fileprivate lazy var dataSource: TopSitesDataSource = {
        return TopSitesDataSource()
    }()
    fileprivate lazy var layout: TopSitesLayout = { return TopSitesLayout() }()

    fileprivate lazy var maxFrecencyLimit: Int = {
        return max(
            self.calculateApproxThumbnailCountForOrientation(UIInterfaceOrientation.landscapeLeft),
            self.calculateApproxThumbnailCountForOrientation(UIInterfaceOrientation.portrait)
        )
    }()

    var editingThumbnails: Bool = false {
        didSet {
            if editingThumbnails != oldValue {
                dataSource.editingThumbnails = editingThumbnails

                if editingThumbnails {
                    homePanelDelegate?.homePanelWillEnterEditingMode?(self)
                }

                updateAllRemoveButtonStates()
            }
        }
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        coordinator.animate(alongsideTransition: { context in
            self.collection?.reloadData()
        }, completion: nil)
    }

    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.allButUpsideDown
    }

    init() {
        super.init(nibName: nil, bundle: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(TopSitesPanel.notificationReceived(_:)), name: NotificationPrivateDataClearedHistory, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(TopSitesPanel.notificationReceived(_:)), name: NotificationPrivacyModeChanged, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(TopSitesPanel.handleRotation), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let statsHeight: CGFloat = 150.0
        let statsBottomMargin: CGFloat = 25.0
        
        privateTabMessageContainer = UIView()
        privateTabMessageContainer.isUserInteractionEnabled = true
        privateTabMessageContainer.isHidden = !PrivateBrowsing.singleton.isOn
        
        privateTabGraphic = UIImageView(image: UIImage(named: "privateLion"))
        privateTabMessageContainer.addSubview(privateTabGraphic)
        
        privateTabTitleLabel = UILabel()
        privateTabTitleLabel.lineBreakMode = .byWordWrapping
        privateTabTitleLabel.font = UIFont.systemFont(ofSize: 18, weight: UIFontWeightSemibold)
        privateTabTitleLabel.textColor = UIColor(white: 1, alpha: 0.6)
        privateTabTitleLabel.text = Strings.Private_Tab_Title
        privateTabMessageContainer.addSubview(privateTabTitleLabel)
        
        privateTabInfoLabel = UILabel()
        privateTabInfoLabel.lineBreakMode = .byWordWrapping
        privateTabInfoLabel.textAlignment = .center
        privateTabInfoLabel.numberOfLines = 0
        privateTabInfoLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightMedium)
        privateTabInfoLabel.textColor = UIColor(white: 1, alpha: 1.0)
        privateTabInfoLabel.text = Strings.Private_Tab_Body
        privateTabMessageContainer.addSubview(privateTabInfoLabel)
        
        privateTabLinkButton = UIButton()
        let linkButtonTitle = NSAttributedString(string: Strings.Private_Tab_Link, attributes:
            [NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue])
        privateTabLinkButton.setAttributedTitle(linkButtonTitle, for: .normal)
        privateTabLinkButton.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: UIFontWeightMedium)
        privateTabLinkButton.titleLabel?.textColor = UIColor(white: 1, alpha: 0.25)
        privateTabLinkButton.titleLabel?.textAlignment = .center
        privateTabLinkButton.addTarget(self, action: #selector(SEL_privateTabInfo), for: .touchUpInside)
        privateTabMessageContainer.addSubview(privateTabLinkButton)
        
        let collection = TopSitesCollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collection.backgroundColor = PrivateBrowsing.singleton.isOn ? BraveUX.BackgroundColorForTopSitesPrivate : BraveUX.BackgroundColorForBookmarksHistoryAndTopSites
        collection.delegate = self
        collection.dataSource = PrivateBrowsing.singleton.isOn ? nil : dataSource
        collection.register(ThumbnailCell.self, forCellWithReuseIdentifier: ThumbnailIdentifier)
        collection.keyboardDismissMode = .onDrag
        collection.accessibilityIdentifier = "Top Sites View"
        // Entire site panel, including the stats view insets
        collection.contentInset = UIEdgeInsetsMake(statsHeight, 0, 0, 0)
        view.addSubview(collection)
        collection.snp.makeConstraints { make -> Void in
            make.edges.equalTo(self.view)
        }
        self.collection = collection
        
        let braveShieldStatsView = BraveShieldStatsView(frame: CGRect.zero)
        collection.addSubview(braveShieldStatsView)
        self.braveShieldStatsView = braveShieldStatsView
        
        collection.addSubview(privateTabMessageContainer)
        
        // Could setup as section header but would need to use flow layout,
        // Auto-layout subview within collection doesn't work properly,
        // Quick-and-dirty layout here.
        var statsViewFrame: CGRect = braveShieldStatsView.frame
        statsViewFrame.origin.x = 20
        // Offset the stats view from the inset set above
        statsViewFrame.origin.y = -(statsHeight + statsBottomMargin)
        statsViewFrame.size.width = collection.frame.width - statsViewFrame.minX * 2
        statsViewFrame.size.height = statsHeight
        braveShieldStatsView.frame = statsViewFrame
        braveShieldStatsView.autoresizingMask = [.flexibleWidth]

        self.dataSource.collectionView = self.collection
        self.refreshTopSites(self.maxFrecencyLimit)
        
        privateTabMessageContainer.snp.makeConstraints { (make) -> Void in
            make.centerX.equalTo(collection)
            make.top.equalTo(self.braveShieldStatsView?.snp.bottom ?? 0).offset(20)
            make.leftMargin.equalTo(collection).offset(40)
            make.rightMargin.equalTo(collection).offset(-40)
        }
        
        privateTabGraphic.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(0)
            make.centerX.equalTo(self.privateTabMessageContainer)
        }
        
        handleRotation()
    }
    
    func handleRotation() {
        
        let toInterfaceOrientation = UIApplication.shared.statusBarOrientation
        
        if UIDevice.current.userInterfaceIdiom == .pad {
            return
        }
        
        if toInterfaceOrientation.isLandscape {
            UIView.animate(withDuration: 0.2, animations: {
                self.privateTabGraphic.alpha = 0
            })
            privateTabTitleLabel.snp.remakeConstraints { make in
                make.top.equalTo(0)
                make.centerX.equalTo(self.privateTabMessageContainer)
            }
            
            privateTabInfoLabel.snp.remakeConstraints { make in<commit_msg>fix issue where private message not displayed on ipad<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 UIKit
import Shared
import XCGLogger
import Storage
import WebImage
import Deferred

private let log = Logger.browserLogger

private let ThumbnailIdentifier = "Thumbnail"

extension CGSize {
    public func widthLargerOrEqualThanHalfIPad() -> Bool {
        let halfIPadSize: CGFloat = 507
        return width >= halfIPadSize
    }
}

struct TopSitesPanelUX {
    fileprivate static let EmptyStateTitleTextColor = UIColor.darkGray
    fileprivate static let EmptyStateTopPaddingInBetweenItems: CGFloat = 15
    fileprivate static let WelcomeScreenPadding: CGFloat = 15
    fileprivate static let WelcomeScreenItemTextColor = UIColor.gray
    fileprivate static let WelcomeScreenItemWidth = 170
}

class TopSitesPanel: UIViewController {
    weak var homePanelDelegate: HomePanelDelegate?
    fileprivate lazy var emptyStateOverlayView: UIView = self.createEmptyStateOverlayView()
    fileprivate var collection: TopSitesCollectionView? = nil
    fileprivate var privateTabMessageContainer: UIView!
    fileprivate var privateTabGraphic: UIImageView!
    fileprivate var privateTabTitleLabel: UILabel!
    fileprivate var privateTabInfoLabel: UILabel!
    fileprivate var privateTabLinkButton: UIButton!
    fileprivate var braveShieldStatsView: BraveShieldStatsView? = nil
    fileprivate lazy var dataSource: TopSitesDataSource = {
        return TopSitesDataSource()
    }()
    fileprivate lazy var layout: TopSitesLayout = { return TopSitesLayout() }()

    fileprivate lazy var maxFrecencyLimit: Int = {
        return max(
            self.calculateApproxThumbnailCountForOrientation(UIInterfaceOrientation.landscapeLeft),
            self.calculateApproxThumbnailCountForOrientation(UIInterfaceOrientation.portrait)
        )
    }()

    var editingThumbnails: Bool = false {
        didSet {
            if editingThumbnails != oldValue {
                dataSource.editingThumbnails = editingThumbnails

                if editingThumbnails {
                    homePanelDelegate?.homePanelWillEnterEditingMode?(self)
                }

                updateAllRemoveButtonStates()
            }
        }
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        coordinator.animate(alongsideTransition: { context in
            self.collection?.reloadData()
        }, completion: nil)
    }

    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.allButUpsideDown
    }

    init() {
        super.init(nibName: nil, bundle: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(TopSitesPanel.notificationReceived(_:)), name: NotificationPrivateDataClearedHistory, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(TopSitesPanel.notificationReceived(_:)), name: NotificationPrivacyModeChanged, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(TopSitesPanel.handleRotation), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let statsHeight: CGFloat = 150.0
        let statsBottomMargin: CGFloat = 25.0
        
        privateTabMessageContainer = UIView()
        privateTabMessageContainer.isUserInteractionEnabled = true
        privateTabMessageContainer.isHidden = !PrivateBrowsing.singleton.isOn
        
        privateTabGraphic = UIImageView(image: UIImage(named: "privateLion"))
        privateTabMessageContainer.addSubview(privateTabGraphic)
        
        privateTabTitleLabel = UILabel()
        privateTabTitleLabel.lineBreakMode = .byWordWrapping
        privateTabTitleLabel.font = UIFont.systemFont(ofSize: 18, weight: UIFontWeightSemibold)
        privateTabTitleLabel.textColor = UIColor(white: 1, alpha: 0.6)
        privateTabTitleLabel.text = Strings.Private_Tab_Title
        privateTabMessageContainer.addSubview(privateTabTitleLabel)
        
        privateTabInfoLabel = UILabel()
        privateTabInfoLabel.lineBreakMode = .byWordWrapping
        privateTabInfoLabel.textAlignment = .center
        privateTabInfoLabel.numberOfLines = 0
        privateTabInfoLabel.font = UIFont.systemFont(ofSize: 14, weight: UIFontWeightMedium)
        privateTabInfoLabel.textColor = UIColor(white: 1, alpha: 1.0)
        privateTabInfoLabel.text = Strings.Private_Tab_Body
        privateTabMessageContainer.addSubview(privateTabInfoLabel)
        
        privateTabLinkButton = UIButton()
        let linkButtonTitle = NSAttributedString(string: Strings.Private_Tab_Link, attributes:
            [NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue])
        privateTabLinkButton.setAttributedTitle(linkButtonTitle, for: .normal)
        privateTabLinkButton.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: UIFontWeightMedium)
        privateTabLinkButton.titleLabel?.textColor = UIColor(white: 1, alpha: 0.25)
        privateTabLinkButton.titleLabel?.textAlignment = .center
        privateTabLinkButton.addTarget(self, action: #selector(SEL_privateTabInfo), for: .touchUpInside)
        privateTabMessageContainer.addSubview(privateTabLinkButton)
        
        let collection = TopSitesCollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collection.backgroundColor = PrivateBrowsing.singleton.isOn ? BraveUX.BackgroundColorForTopSitesPrivate : BraveUX.BackgroundColorForBookmarksHistoryAndTopSites
        collection.delegate = self
        collection.dataSource = PrivateBrowsing.singleton.isOn ? nil : dataSource
        collection.register(ThumbnailCell.self, forCellWithReuseIdentifier: ThumbnailIdentifier)
        collection.keyboardDismissMode = .onDrag
        collection.accessibilityIdentifier = "Top Sites View"
        // Entire site panel, including the stats view insets
        collection.contentInset = UIEdgeInsetsMake(statsHeight, 0, 0, 0)
        view.addSubview(collection)
        collection.snp.makeConstraints { make -> Void in
            make.edges.equalTo(self.view)
        }
        self.collection = collection
        
        let braveShieldStatsView = BraveShieldStatsView(frame: CGRect.zero)
        collection.addSubview(braveShieldStatsView)
        self.braveShieldStatsView = braveShieldStatsView
        
        collection.addSubview(privateTabMessageContainer)
        
        // Could setup as section header but would need to use flow layout,
        // Auto-layout subview within collection doesn't work properly,
        // Quick-and-dirty layout here.
        var statsViewFrame: CGRect = braveShieldStatsView.frame
        statsViewFrame.origin.x = 20
        // Offset the stats view from the inset set above
        statsViewFrame.origin.y = -(statsHeight + statsBottomMargin)
        statsViewFrame.size.width = collection.frame.width - statsViewFrame.minX * 2
        statsViewFrame.size.height = statsHeight
        braveShieldStatsView.frame = statsViewFrame
        braveShieldStatsView.autoresizingMask = [.flexibleWidth]

        self.dataSource.collectionView = self.collection
        self.refreshTopSites(self.maxFrecencyLimit)
        
        privateTabMessageContainer.snp.makeConstraints { (make) -> Void in
            make.centerX.equalTo(collection)
            if UIDevice.current.userInterfaceIdiom == .pad {
                make.centerY.equalTo(self.view)
            }
            else {
                make.top.equalTo(self.braveShieldStatsView?.snp.bottom ?? 0).offset(20)
            }
            
            make.leftMargin.equalTo(collection).offset(40)
            make.rightMargin.equalTo(collection).offset(-40)
        }
        
        privateTabGraphic.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(0)
            make.centerX.equalTo(self.privateTabMessageContainer)
        }
        
        privateTabTitleLabel.snp.remakeConstraints { make in
            make.top.equalTo(self.privateTabGraphic.snp.bottom).offset(15)
            make.centerX.equalTo(self.privateTabMessageContainer)
        }
        
        privateTabInfoLabel.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(self.privateTabTitleLabel.snp.bottom).offset(10)
            if UIDevice.current.userInterfaceIdiom == .pad {
                make.width.equalTo(400)
                make.centerX.equalTo(collection)
            }
            else {
                make.left.equalTo(0)
                make.right.equalTo(0)
            }
        }
        
        privateTabLinkButton.snp.makeConstraints { (make) -> Void in
            make.top.equalTo(self.privateTabInfoLabel.snp.bottom).offset(10)
            make.left.equalTo(0)
            make.right.equalTo(0)
            make.bottom.equalTo(0)
        }
        
        handleRotation()
    }
    
    func handleRotation() {
        
        let toInterfaceOrientation = UIApplication.shared.statusBarOrientation
        
        if UIDevice.current.userInterfaceIdiom == .pad {
            return
        }
        
        if toInterfaceOrientation.isLandscape {
            UIView.animate(withDuration: 0.2, animations: {
                self.privateTabGraphic.alpha = 0
            })
            privateTabTitleLabel.snp.remakeConstraints { make in
                make.top.equalTo(0)
                make.centerX.equalTo(self.privateTabMessageContainer)
            }
            
            privateTabInfoLabel.snp.remakeConstraints { make in
{'fraction_non_alphanumeric': 0.0714891811624947, 'fraction_numerical': 0.006682223165040305, 'mean_word_length': 2.944979079497908, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, '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': '918563', 'n_tokens_mistral': 5190, 'n_tokens_neox': 4982, 'n_words': 986}