Skip to content

Create a File Browser

Maximilian Mackh edited this page Apr 17, 2020 · 2 revisions
//
//  FileBrowserViewController.swift
//  BaseComponents Playground
//
//  Created by mmackh on 21/03/2020.
//  Copyright © 2020 proconsult.at gmbh. All rights reserved.
//

import UIKit
import QuickLook

import BaseComponents


class FileBrowserCell: UITableViewCell {
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
        
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func bindObject(_ obj: AnyObject) {
        let diskData = obj as? DiskData
        
        textLabel?.text = diskData?.name
        detailTextLabel?.text = diskData is Directory ? "Folder" : "File"
    }
}

class DirectoryRender: UIView {
    lazy var render: DataRender = {
        let config: DataRenderConfiguration = .init(cellClass: FileBrowserCell.self)
        let render = DataRender(configuration: config)
        render.adjustInsets = true
        return render
    }()
    let directory: Directory
    
    init(_ directory: Directory) {
        
        self.directory = directory
        
        super.init(frame: .zero)
        
        self.addSplitView { (splitView) in
            splitView.direction = .horizontal
            
            splitView.addSubview(render, layoutType: .equal)
            
            splitView.addSubview(UIView().color(.background, .lightGray), layoutType: .fixed, value: SplitView.onePixelHeight)
        }
        
        reloadData()
    }
    
    func reloadData() {
        render.renderArray(directory.contents().sorted(by: { $0.name.localizedStandardCompare($1.name) == .orderedAscending }))
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

class FileBrowserViewController: UIViewController, QLPreviewControllerDataSource {
    var scrollingView: ScrollingView?
    var directoryRenders: Array<DirectoryRender> = []
    var currentSelectedFile: File?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = "App Documents"
        
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, { [unowned self] (barButtonItem) in
            UIAlertController.show(style: .alert, title: nil, message: nil, options: ["Create File", "New Folder"], dismiss: "Cancel") { (idx) in
                let directoryRender = self.directoryRenders.last!
                let directory = directoryRender.directory
                if (idx == 0) {
                    let file = directory.newFile(name: "New File.txt", createIfNeeded: false)
                    if file.exists() {
                        var fileNr = 1
                        let fileNameTemplate = "New File %i.txt"
                        while directory.newFile(name: String(format: fileNameTemplate, fileNr), createIfNeeded: false).exists() {
                            fileNr += 1
                        }
                        _ = directory.newFile(name: String(format: fileNameTemplate, fileNr), createIfNeeded: true)
                    } else {
                        file.create()
                    }
                } else {
                    let createdDirectory = directory.newDirectory(name: "New Folder", createIfNeeded: false)
                    if (createdDirectory.exists()) {
                        var dirNr = 1
                        let dirNameTemplate = "New Folder %i"
                        while directory.newDirectory(name: String(format: dirNameTemplate, dirNr), createIfNeeded: false).exists() {
                            dirNr += 1
                        }
                        _ = directory.newDirectory(name: String(format: dirNameTemplate, dirNr), createIfNeeded: true)
                    } else {
                        createdDirectory.create()
                    }
                }
                
                directoryRender.reloadData()
            }
        })

        view.color(.background, .white)
        
        view.addSplitView { [unowned self] (splitView) in
            self.scrollingView = ScrollingView(frame: .zero)
            self.scrollingView?.direction = .horizontal
            self.scrollingView?.alwaysBounceHorizontal = true
            self.scrollingView?.contentInsetAdjustmentBehavior = .never
            splitView.addSubview(self.scrollingView!, layoutType: .percentage, value: 100)
        }
        
        showDirectory(Directory(searchPathDirectory: .documentDirectory))
    }
    
    func showDirectory(_ directory: Directory) {
        let directoryRender = DirectoryRender(directory)
        directoryRender.render.onSelect { [unowned self] (itemRenderProperties) in
            let diskData = itemRenderProperties.object as? DiskData
            if diskData is Directory {
                if let idx = self.directoryRenders.firstIndex(of: itemRenderProperties.render?.superview?.superview as! DirectoryRender) {
                    var iidx = 0
                    let directoryRendersCopy = self.directoryRenders
                    for directoryRender in directoryRendersCopy {
                        if iidx > idx {
                            directoryRender.removeFromSuperview()
                            self.directoryRenders.remove(at: self.directoryRenders.firstIndex(of: directoryRender)!)
                        }
                        iidx += 1
                    }
                    
                }
                self.showDirectory(diskData as! Directory)
            }
            if diskData is File {
                self.currentSelectedFile = diskData as? File
                let previewController = QLPreviewController()
                previewController.dataSource = self
                self.present(previewController, animated: true)
            }
        }
        directoryRenders.append(directoryRender)
        if let scrollingView = self.scrollingView {
            scrollingView.addSubview(directoryRender, layoutType: .fixed, value: 320, edgeInsets: .zero)
            scrollingView.invalidateLayout()
            scrollingView.setContentOffset(CGPoint(x: max(0, (scrollingView.contentSize.width - scrollingView.bounds.size.width)), y: 0), animated: true)
        }
    }
    
    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
        1
    }
    
    func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
        return currentSelectedFile!.pathURL as QLPreviewItem
    }
}
Clone this wiki locally