Implemented folder expanding.
This commit is contained in:
parent
48ab0cd733
commit
b18d4a294e
@ -19,7 +19,7 @@ class MasterTableViewCell : UITableViewCell {
|
||||
|
||||
weak var delegate: MasterTableViewCellDelegate?
|
||||
var allowDisclosureSelection = false
|
||||
|
||||
|
||||
override var accessibilityLabel: String? {
|
||||
set {}
|
||||
get {
|
||||
@ -32,6 +32,24 @@ class MasterTableViewCell : UITableViewCell {
|
||||
}
|
||||
}
|
||||
|
||||
var indent = false {
|
||||
didSet {
|
||||
if indent != oldValue {
|
||||
setNeedsLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var disclosureExpanded = false {
|
||||
didSet {
|
||||
if disclosureExpanded {
|
||||
accessoryButton?.setImage(AppAssets.chevronDownImage, for: .normal)
|
||||
} else {
|
||||
accessoryButton?.setImage(AppAssets.chevronRightImage, for: .normal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var faviconImage: UIImage? {
|
||||
didSet {
|
||||
if let image = faviconImage {
|
||||
@ -106,7 +124,7 @@ class MasterTableViewCell : UITableViewCell {
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
let layout = MasterTableViewCellLayout(cellSize: bounds.size, shouldShowImage: shouldShowImage, label: titleView, unreadCountView: unreadCountView, showingEditingControl: showingEditControl)
|
||||
let layout = MasterTableViewCellLayout(cellSize: bounds.size, shouldShowImage: shouldShowImage, label: titleView, unreadCountView: unreadCountView, showingEditingControl: showingEditControl, indent: indent)
|
||||
layoutWith(layout)
|
||||
}
|
||||
|
||||
@ -116,7 +134,7 @@ class MasterTableViewCell : UITableViewCell {
|
||||
return
|
||||
}
|
||||
|
||||
if sender.imageView?.image == AppAssets.chevronRightImage {
|
||||
if !disclosureExpanded {
|
||||
sender.setImage(AppAssets.chevronDownImage, for: .normal)
|
||||
delegate?.disclosureSelected(self, expanding: true)
|
||||
} else {
|
||||
@ -124,6 +142,8 @@ class MasterTableViewCell : UITableViewCell {
|
||||
delegate?.disclosureSelected(self, expanding: false)
|
||||
}
|
||||
|
||||
disclosureExpanded = !disclosureExpanded
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -138,13 +158,21 @@ private extension MasterTableViewCell {
|
||||
}
|
||||
|
||||
func addAccessoryView() {
|
||||
|
||||
let button = UIButton(type: .roundedRect)
|
||||
button.frame = CGRect(x: 0, y: 0, width: 25.0, height: 25.0)
|
||||
button.setImage(AppAssets.chevronRightImage, for: .normal)
|
||||
|
||||
if disclosureExpanded {
|
||||
button.setImage(AppAssets.chevronDownImage, for: .normal)
|
||||
} else {
|
||||
button.setImage(AppAssets.chevronRightImage, for: .normal)
|
||||
}
|
||||
|
||||
button.tintColor = AppAssets.chevronDisclosureColor
|
||||
button.addTarget(self, action: #selector(buttonPressed(_:)), for: UIControl.Event.touchUpInside)
|
||||
accessoryButton = button
|
||||
accessoryView = button
|
||||
|
||||
}
|
||||
|
||||
func addSubviewAtInit(_ view: UIView) {
|
||||
|
@ -23,7 +23,7 @@ struct MasterTableViewCellLayout {
|
||||
let titleRect: CGRect
|
||||
let unreadCountRect: CGRect
|
||||
|
||||
init(cellSize: CGSize, shouldShowImage: Bool, label: UILabel, unreadCountView: MasterUnreadCountView, showingEditingControl: Bool) {
|
||||
init(cellSize: CGSize, shouldShowImage: Bool, label: UILabel, unreadCountView: MasterUnreadCountView, showingEditingControl: Bool, indent: Bool) {
|
||||
|
||||
let adjustedWidth: CGFloat = {
|
||||
if showingEditingControl {
|
||||
@ -37,8 +37,9 @@ struct MasterTableViewCellLayout {
|
||||
|
||||
var rFavicon = CGRect.zero
|
||||
if shouldShowImage {
|
||||
let indent = showingEditingControl ? MasterTableViewCellLayout.imageMarginLeft + 40 : MasterTableViewCellLayout.imageMarginLeft
|
||||
rFavicon = CGRect(x: indent, y: 0.0, width: MasterTableViewCellLayout.imageSize.width, height: MasterTableViewCellLayout.imageSize.height)
|
||||
var indentX = showingEditingControl ? MasterTableViewCellLayout.imageMarginLeft + 40 : MasterTableViewCellLayout.imageMarginLeft
|
||||
indentX = indent ? indentX + 20 : indentX
|
||||
rFavicon = CGRect(x: indentX, y: 0.0, width: MasterTableViewCellLayout.imageSize.width, height: MasterTableViewCellLayout.imageSize.height)
|
||||
rFavicon = MasterTableViewCellLayout.centerVertically(rFavicon, bounds)
|
||||
}
|
||||
self.faviconRect = rFavicon
|
||||
|
@ -17,6 +17,9 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
var undoableCommands = [UndoableCommand]()
|
||||
var animatingChanges = false
|
||||
|
||||
var expandedNodes = [Node]()
|
||||
var shadowTable = [[Node]]()
|
||||
|
||||
let treeControllerDelegate = MasterTreeControllerDelegate()
|
||||
lazy var treeController: TreeController = {
|
||||
return TreeController(delegate: treeControllerDelegate)
|
||||
@ -44,6 +47,13 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
refreshControl = UIRefreshControl()
|
||||
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
|
||||
|
||||
// Set up the backing structures
|
||||
for _ in treeController.rootNode.childNodes {
|
||||
shadowTable.append([Node]())
|
||||
}
|
||||
|
||||
rebuildShadow()
|
||||
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
@ -124,7 +134,7 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return treeController.rootNode.childAtIndex(section)?.numberOfChildNodes ?? 0
|
||||
return shadowTable[section].count
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
@ -302,12 +312,17 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
// MARK: API
|
||||
|
||||
func configure(_ cell: MasterTableViewCell, _ node: Node) {
|
||||
|
||||
cell.delegate = self
|
||||
cell.allowDisclosureSelection = node.canHaveChildNodes
|
||||
cell.indent = node.parent?.representedObject is Folder
|
||||
cell.disclosureExpanded = expandedNodes.contains(node)
|
||||
cell.allowDisclosureSelection = node.canHaveChildNodes
|
||||
|
||||
cell.name = nameFor(node)
|
||||
configureUnreadCount(cell, node)
|
||||
configureFavicon(cell, node)
|
||||
cell.shouldShowImage = node.representedObject is SmallIconProvider
|
||||
|
||||
}
|
||||
|
||||
func configureUnreadCount(_ cell: MasterTableViewCell, _ node: Node) {
|
||||
@ -341,8 +356,8 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
|
||||
func delete(indexPath: IndexPath) {
|
||||
|
||||
guard let containerNode = treeController.rootNode.childAtIndex(indexPath.section),
|
||||
let deleteNode = containerNode.childAtIndex(indexPath.row),
|
||||
guard let deleteNode = nodeFor(indexPath: indexPath),
|
||||
let containerNode = deleteNode.parent,
|
||||
let container = containerNode.representedObject as? Container else {
|
||||
return
|
||||
}
|
||||
@ -357,7 +372,7 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
container.deleteFolder(folder)
|
||||
}
|
||||
|
||||
treeController.rebuild()
|
||||
rebuildBackingStructures()
|
||||
tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
|
||||
animatingChanges = false
|
||||
@ -405,7 +420,7 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
|
||||
}
|
||||
|
||||
func nodeFor(indexPath: IndexPath) -> Node? {
|
||||
return treeController.rootNode.childAtIndex(indexPath.section)?.childAtIndex(indexPath.row)
|
||||
return shadowTable[indexPath.section][indexPath.row]
|
||||
}
|
||||
|
||||
}
|
||||
@ -433,7 +448,11 @@ extension MasterViewController: UIDocumentPickerDelegate {
|
||||
extension MasterViewController: MasterTableViewCellDelegate {
|
||||
|
||||
func disclosureSelected(_ sender: MasterTableViewCell, expanding: Bool) {
|
||||
// let indexSet = tableView.indexPath(for: sender)
|
||||
if expanding {
|
||||
expandCell(sender)
|
||||
} else {
|
||||
collapseCell(sender)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -444,7 +463,7 @@ private extension MasterViewController {
|
||||
|
||||
func rebuildTreeAndReloadDataIfNeeded() {
|
||||
if !animatingChanges && !BatchUpdate.shared.isPerforming {
|
||||
treeController.rebuild()
|
||||
rebuildBackingStructures()
|
||||
tableView.reloadData()
|
||||
}
|
||||
}
|
||||
@ -475,4 +494,96 @@ private extension MasterViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func rebuildBackingStructures() {
|
||||
treeController.rebuild()
|
||||
rebuildShadow()
|
||||
}
|
||||
|
||||
func rebuildShadow() {
|
||||
|
||||
for i in 0..<treeController.rootNode.numberOfChildNodes {
|
||||
|
||||
var result = [Node]()
|
||||
|
||||
if let nodes = treeController.rootNode.childAtIndex(i)?.childNodes {
|
||||
for node in nodes {
|
||||
result.append(node)
|
||||
if expandedNodes.contains(node) {
|
||||
for child in node.childNodes {
|
||||
result.append(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadowTable[i] = result
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func expandCell(_ cell: MasterTableViewCell) {
|
||||
|
||||
animatingChanges = true
|
||||
|
||||
guard let indexPath = tableView.indexPath(for: cell) else {
|
||||
return
|
||||
}
|
||||
|
||||
let expandNode = shadowTable[indexPath.section][indexPath.row]
|
||||
expandedNodes.append(expandNode)
|
||||
|
||||
var indexPathsToInsert = [IndexPath]()
|
||||
for i in 0..<expandNode.childNodes.count {
|
||||
if let child = expandNode.childAtIndex(i) {
|
||||
let nextIndex = indexPath.row + i + 1
|
||||
indexPathsToInsert.append(IndexPath(row: nextIndex, section: indexPath.section))
|
||||
shadowTable[indexPath.section].insert(child, at: nextIndex)
|
||||
}
|
||||
}
|
||||
|
||||
tableView.beginUpdates()
|
||||
tableView.insertRows(at: indexPathsToInsert, with: .automatic)
|
||||
tableView.endUpdates()
|
||||
|
||||
animatingChanges = false
|
||||
|
||||
}
|
||||
|
||||
func collapseCell(_ cell: MasterTableViewCell) {
|
||||
|
||||
animatingChanges = true
|
||||
|
||||
guard let indexPath = tableView.indexPath(for: cell) else {
|
||||
return
|
||||
}
|
||||
|
||||
let collapseNode = shadowTable[indexPath.section][indexPath.row]
|
||||
if let removeNode = expandedNodes.firstIndex(of: collapseNode) {
|
||||
expandedNodes.remove(at: removeNode)
|
||||
}
|
||||
|
||||
var indexPathsToRemove = [IndexPath]()
|
||||
|
||||
for child in collapseNode.childNodes {
|
||||
if let index = shadowTable[indexPath.section].firstIndex(of: child) {
|
||||
indexPathsToRemove.append(IndexPath(row: index, section: indexPath.section))
|
||||
}
|
||||
}
|
||||
|
||||
for child in collapseNode.childNodes {
|
||||
if let index = shadowTable[indexPath.section].firstIndex(of: child) {
|
||||
shadowTable[indexPath.section].remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
tableView.beginUpdates()
|
||||
tableView.deleteRows(at: indexPathsToRemove, with: .automatic)
|
||||
tableView.endUpdates()
|
||||
|
||||
animatingChanges = false
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user