Tab picker: Allow multiple selection/deletion
This commit is contained in:
@@ -251,9 +251,11 @@ class BrowserViewController: UIViewController, WKNavigationDelegate, WKUIDelegat
|
||||
activeTabObservation = tabController.$activeTabIndex
|
||||
.receive(on: RunLoop.main)
|
||||
.sink(receiveValue: { [unowned self] (activeTab: Int) in
|
||||
let tab = tabController.tabs[activeTab]
|
||||
if self.tab != tab {
|
||||
self.tab = tab
|
||||
if activeTab < tabController.tabs.count {
|
||||
let tab = tabController.tabs[activeTab]
|
||||
if self.tab != tab {
|
||||
self.tab = tab
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol ScriptPolicyViewControllerDelegate: class {
|
||||
protocol ScriptPolicyViewControllerDelegate: AnyObject {
|
||||
func didChangeScriptPolicy()
|
||||
func setScriptsEnabledForTab(_ enabled: Bool)
|
||||
}
|
||||
@@ -96,16 +96,7 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate
|
||||
}
|
||||
|
||||
override var traitCollection: UITraitCollection {
|
||||
get {
|
||||
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
|
||||
}
|
||||
get { return super.traitCollection.alwaysPadLike() }
|
||||
}
|
||||
|
||||
private static let enableScriptsForTabItem: String = "enableScriptsForTab"
|
||||
@@ -229,6 +220,7 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate
|
||||
|
||||
override func loadView() {
|
||||
self.view = collectionView
|
||||
self.view.backgroundColor = .systemGroupedBackground
|
||||
}
|
||||
|
||||
// MARK: UICollectionViewDelegate
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol TabPickerViewControllerDelegate: class
|
||||
protocol TabPickerViewControllerDelegate: AnyObject
|
||||
{
|
||||
func tabPicker(_ picker: TabPickerViewController, didSelectTab tab: Tab)
|
||||
func tabPicker(_ picker: TabPickerViewController, willCloseTab tab: Tab)
|
||||
@@ -22,9 +22,27 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
||||
|
||||
typealias TabID = UUID
|
||||
|
||||
private var selectedTabsForEditing: Set<Tab> = []
|
||||
private var collectionView: UICollectionView?
|
||||
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) {
|
||||
self.tabController = tabController
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
@@ -58,6 +76,8 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
||||
|
||||
let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig)
|
||||
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
|
||||
var config = listCell.defaultContentConfiguration()
|
||||
@@ -85,7 +105,7 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
||||
config.imageProperties.maximumSize = CGSize(width: 21.0, height: 21.0)
|
||||
config.imageProperties.cornerRadius = 3.0
|
||||
|
||||
if tab == self.selectedTab {
|
||||
if self.selectedTab == tab {
|
||||
listCell.accessories = [ .checkmark() ]
|
||||
} else {
|
||||
listCell.accessories = []
|
||||
@@ -114,16 +134,68 @@ class TabPickerViewController: UIViewController, UICollectionViewDelegate
|
||||
self.collectionView = collectionView
|
||||
self.view = self.collectionView
|
||||
|
||||
let newTabButton = UIBarButtonItem(systemItem: .add, primaryAction: UIAction(handler: { [unowned self] _ in
|
||||
let newTab = self.tabController.createNewTab(url: nil)
|
||||
self.delegate?.tabPicker(self, didSelectTab: newTab)
|
||||
}), menu: nil)
|
||||
configureNavigationButtons(forEditing: isEditing)
|
||||
}
|
||||
|
||||
private func configureNavigationButtons(forEditing: Bool) {
|
||||
if !forEditing {
|
||||
navigationItem.rightBarButtonItem = newTabButton
|
||||
} else {
|
||||
deleteTabButton.isEnabled = collectionView?.indexPathsForSelectedItems?.count ?? 0 > 0
|
||||
navigationItem.rightBarButtonItem = deleteTabButton
|
||||
}
|
||||
|
||||
navigationItem.rightBarButtonItem = newTabButton
|
||||
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) {
|
||||
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 */; };
|
||||
CDCE2666251AA840007FE92A /* StackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDCE2665251AA840007FE92A /* StackView.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 */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -133,6 +134,7 @@
|
||||
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>"; };
|
||||
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 */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -315,6 +317,7 @@
|
||||
CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */,
|
||||
1ADFF4C624CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift */,
|
||||
1AB88F0524D4D3A90006F850 /* UIGestureRecognizer+Actions.swift */,
|
||||
CDEDD8A925D62ADB00862605 /* UITraitCollection+MacLike.swift */,
|
||||
);
|
||||
path = Utilities;
|
||||
sourceTree = "<group>";
|
||||
@@ -468,6 +471,7 @@
|
||||
CDCE2666251AA840007FE92A /* StackView.swift in Sources */,
|
||||
CD853BD124E778B800D2BDCC /* History.xcdatamodeld in Sources */,
|
||||
1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */,
|
||||
CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */,
|
||||
CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */,
|
||||
1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */,
|
||||
1ADFF4AE24C8ED32006DC7AE /* ResourcePolicyManager.swift in Sources */,
|
||||
|
||||
Reference in New Issue
Block a user