Tab picker: Allow multiple selection/deletion
This commit is contained in:
@@ -251,9 +251,11 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
|
|||||||
activeTabObservation = tabController.$activeTabIndex
|
activeTabObservation = tabController.$activeTabIndex
|
||||||
.receive(on: RunLoop.main)
|
.receive(on: RunLoop.main)
|
||||||
.sink(receiveValue: { [unowned self] (activeTab: Int) in
|
.sink(receiveValue: { [unowned self] (activeTab: Int) in
|
||||||
let tab = tabController.tabs[activeTab]
|
if activeTab < tabController.tabs.count {
|
||||||
if self.tab != tab {
|
let tab = tabController.tabs[activeTab]
|
||||||
self.tab = tab
|
if self.tab != tab {
|
||||||
|
self.tab = tab
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
protocol ScriptPolicyViewControllerDelegate: class {
|
protocol ScriptPolicyViewControllerDelegate: AnyObject {
|
||||||
func didChangeScriptPolicy()
|
func didChangeScriptPolicy()
|
||||||
func setScriptsEnabledForTab(_ enabled: Bool)
|
func setScriptsEnabledForTab(_ enabled: Bool)
|
||||||
}
|
}
|
||||||
@@ -96,16 +96,7 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
override var traitCollection: UITraitCollection {
|
override var traitCollection: UITraitCollection {
|
||||||
get {
|
get { return super.traitCollection.alwaysPadLike() }
|
||||||
let actualTraits = super.traitCollection
|
|
||||||
if actualTraits.userInterfaceIdiom == .mac {
|
|
||||||
// Override traits to be iPad like on mac. We dont want small list cells here.
|
|
||||||
let desiredTraits = UITraitCollection(userInterfaceIdiom: .pad)
|
|
||||||
return UITraitCollection(traitsFrom: [ actualTraits, desiredTraits ])
|
|
||||||
}
|
|
||||||
|
|
||||||
return actualTraits
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static let enableScriptsForTabItem: String = "enableScriptsForTab"
|
private static let enableScriptsForTabItem: String = "enableScriptsForTab"
|
||||||
@@ -229,6 +220,7 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate
|
|||||||
|
|
||||||
override func loadView() {
|
override func loadView() {
|
||||||
self.view = collectionView
|
self.view = collectionView
|
||||||
|
self.view.backgroundColor = .systemGroupedBackground
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UICollectionViewDelegate
|
// MARK: UICollectionViewDelegate
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
protocol TabPickerViewControllerDelegate: class
|
protocol TabPickerViewControllerDelegate: AnyObject
|
||||||
{
|
{
|
||||||
func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab)
|
func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab)
|
||||||
func tabPicker(_ picker: TabPickerViewController, willCloseTab tab: Tab)
|
func tabPicker(_ picker: TabPickerViewController, willCloseTab tab: Tab)
|
||||||
@@ -22,9 +22,27 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
|||||||
|
|
||||||
typealias TabID = UUID
|
typealias TabID = UUID
|
||||||
|
|
||||||
|
private var selectedTabsForEditing: Set<Tab> = []
|
||||||
private var collectionView: UICollectionView?
|
private var collectionView: UICollectionView?
|
||||||
private var dataSource: UICollectionViewDiffableDataSource<Int, TabID>?
|
private var dataSource: UICollectionViewDiffableDataSource<Int, TabID>?
|
||||||
|
|
||||||
|
override var traitCollection: UITraitCollection {
|
||||||
|
get { return super.traitCollection.alwaysPadLike() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var newTabButton: UIBarButtonItem = {
|
||||||
|
UIBarButtonItem(systemItem: .add, primaryAction: UIAction(handler: { [unowned self] _ in
|
||||||
|
let newTab = self.tabController.createNewTab(url: nil)
|
||||||
|
self.delegate?.tabPicker(self, didSelectTab: newTab)
|
||||||
|
}), menu: nil)
|
||||||
|
}()
|
||||||
|
|
||||||
|
lazy var deleteTabButton: UIBarButtonItem = {
|
||||||
|
UIBarButtonItem(systemItem: .trash, primaryAction: UIAction(handler: { [unowned self] _ in
|
||||||
|
deleteSelectedTabs()
|
||||||
|
}), menu: nil)
|
||||||
|
}()
|
||||||
|
|
||||||
init(tabController: TabController) {
|
init(tabController: TabController) {
|
||||||
self.tabController = tabController
|
self.tabController = tabController
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
@@ -58,6 +76,8 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
|||||||
|
|
||||||
let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig)
|
let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig)
|
||||||
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout)
|
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout)
|
||||||
|
collectionView.allowsMultipleSelectionDuringEditing = true
|
||||||
|
collectionView.backgroundColor = .systemGroupedBackground
|
||||||
|
|
||||||
let registry = UICollectionView.CellRegistration<UICollectionViewListCell, TabID> { [unowned self] (listCell, indexPath, item) in
|
let registry = UICollectionView.CellRegistration<UICollectionViewListCell, TabID> { [unowned self] (listCell, indexPath, item) in
|
||||||
var config = listCell.defaultContentConfiguration()
|
var config = listCell.defaultContentConfiguration()
|
||||||
@@ -85,7 +105,7 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
|||||||
config.imageProperties.maximumSize = CGSize(width: 21.0, height: 21.0)
|
config.imageProperties.maximumSize = CGSize(width: 21.0, height: 21.0)
|
||||||
config.imageProperties.cornerRadius = 3.0
|
config.imageProperties.cornerRadius = 3.0
|
||||||
|
|
||||||
if tab == self.selectedTab {
|
if self.selectedTab == tab {
|
||||||
listCell.accessories = [ .checkmark() ]
|
listCell.accessories = [ .checkmark() ]
|
||||||
} else {
|
} else {
|
||||||
listCell.accessories = []
|
listCell.accessories = []
|
||||||
@@ -114,16 +134,68 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
|||||||
self.collectionView = collectionView
|
self.collectionView = collectionView
|
||||||
self.view = self.collectionView
|
self.view = self.collectionView
|
||||||
|
|
||||||
let newTabButton = UIBarButtonItem(systemItem: .add, primaryAction: UIAction(handler: { [unowned self] _ in
|
configureNavigationButtons(forEditing: isEditing)
|
||||||
let newTab = self.tabController.createNewTab(url: nil)
|
}
|
||||||
self.delegate?.tabPicker(self, didSelectTab: newTab)
|
|
||||||
}), menu: nil)
|
|
||||||
|
|
||||||
navigationItem.rightBarButtonItem = newTabButton
|
private func configureNavigationButtons(forEditing: Bool) {
|
||||||
|
if !forEditing {
|
||||||
|
navigationItem.rightBarButtonItem = newTabButton
|
||||||
|
} else {
|
||||||
|
deleteTabButton.isEnabled = collectionView?.indexPathsForSelectedItems?.count ?? 0 > 0
|
||||||
|
navigationItem.rightBarButtonItem = deleteTabButton
|
||||||
|
}
|
||||||
|
|
||||||
|
navigationItem.leftBarButtonItem = editButtonItem
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setEditing(_ editing: Bool, animated: Bool) {
|
||||||
|
super.setEditing(editing, animated: animated)
|
||||||
|
|
||||||
|
if let collectionView = collectionView {
|
||||||
|
collectionView.isEditing = editing
|
||||||
|
}
|
||||||
|
|
||||||
|
configureNavigationButtons(forEditing: editing)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func deleteSelectedTabs() {
|
||||||
|
guard let dataSource = dataSource else { return }
|
||||||
|
|
||||||
|
var snapshot = dataSource.snapshot()
|
||||||
|
for tab in selectedTabsForEditing {
|
||||||
|
snapshot.deleteItems([ tab.identifier ])
|
||||||
|
self.delegate?.tabPicker(self, willCloseTab: tab)
|
||||||
|
self.tabController.closeTab(tab)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource.apply(snapshot, animatingDifferences: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
let tab = tabController.tabs[indexPath.row]
|
let tab = tabController.tabs[indexPath.row]
|
||||||
delegate?.tabPicker(self, didSelectTab: tab)
|
|
||||||
|
if !isEditing {
|
||||||
|
delegate?.tabPicker(self, didSelectTab: tab)
|
||||||
|
} else {
|
||||||
|
deleteTabButton.isEnabled = collectionView.indexPathsForSelectedItems?.count ?? 0 > 0
|
||||||
|
selectedTabsForEditing.update(with: tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
|
||||||
|
if isEditing {
|
||||||
|
let tab = tabController.tabs[indexPath.row]
|
||||||
|
selectedTabsForEditing.remove(tab)
|
||||||
|
|
||||||
|
deleteTabButton.isEnabled = collectionView.indexPathsForSelectedItems?.count ?? 0 > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, shouldBeginMultipleSelectionInteractionAt indexPath: IndexPath) -> Bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didBeginMultipleSelectionInteractionAt indexPath: IndexPath) {
|
||||||
|
isEditing = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
App/Utilities/UITraitCollection+MacLike.swift
Normal file
20
App/Utilities/UITraitCollection+MacLike.swift
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// UITraitCollection+MacLike.swift
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by James Magahern on 2/11/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension UITraitCollection {
|
||||||
|
public func alwaysPadLike() -> UITraitCollection {
|
||||||
|
if self.userInterfaceIdiom == .mac {
|
||||||
|
// Override traits to be iPad like on mac. We dont want small list cells here.
|
||||||
|
let desiredTraits = UITraitCollection(userInterfaceIdiom: .pad)
|
||||||
|
return UITraitCollection(traitsFrom: [ self, desiredTraits ])
|
||||||
|
}
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@
|
|||||||
CDCE2664251AA80F007FE92A /* DocumentControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */; };
|
CDCE2664251AA80F007FE92A /* DocumentControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */; };
|
||||||
CDCE2666251AA840007FE92A /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2665251AA840007FE92A /* StackView.swift */; };
|
CDCE2666251AA840007FE92A /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2665251AA840007FE92A /* StackView.swift */; };
|
||||||
CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */; };
|
CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */; };
|
||||||
|
CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDEDD8A925D62ADB00862605 /* UITraitCollection+MacLike.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -133,6 +134,7 @@
|
|||||||
CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentControlViewController.swift; sourceTree = "<group>"; };
|
CDCE2663251AA80F007FE92A /* DocumentControlViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentControlViewController.swift; sourceTree = "<group>"; };
|
||||||
CDCE2665251AA840007FE92A /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = "<group>"; };
|
CDCE2665251AA840007FE92A /* StackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackView.swift; sourceTree = "<group>"; };
|
||||||
CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeAdjustView.swift; sourceTree = "<group>"; };
|
CDCE2667251AAA9A007FE92A /* FontSizeAdjustView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSizeAdjustView.swift; sourceTree = "<group>"; };
|
||||||
|
CDEDD8A925D62ADB00862605 /* UITraitCollection+MacLike.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITraitCollection+MacLike.swift"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -315,6 +317,7 @@
|
|||||||
CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */,
|
CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */,
|
||||||
1ADFF4C624CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift */,
|
1ADFF4C624CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift */,
|
||||||
1AB88F0524D4D3A90006F850 /* UIGestureRecognizer+Actions.swift */,
|
1AB88F0524D4D3A90006F850 /* UIGestureRecognizer+Actions.swift */,
|
||||||
|
CDEDD8A925D62ADB00862605 /* UITraitCollection+MacLike.swift */,
|
||||||
);
|
);
|
||||||
path = Utilities;
|
path = Utilities;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -468,6 +471,7 @@
|
|||||||
CDCE2666251AA840007FE92A /* StackView.swift in Sources */,
|
CDCE2666251AA840007FE92A /* StackView.swift in Sources */,
|
||||||
CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */,
|
CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */,
|
||||||
1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */,
|
1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */,
|
||||||
|
CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */,
|
||||||
CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */,
|
CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */,
|
||||||
1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */,
|
1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */,
|
||||||
1ADFF4AE24C8ED32006DC7AE /* ResourcePolicyManager.swift in Sources */,
|
1ADFF4AE24C8ED32006DC7AE /* ResourcePolicyManager.swift in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user