Compare commits

...

1 Commits

Author SHA1 Message Date
Amir Abbas ae4cd1dff3 Fixed undo manager bugs
- Fixed contents of file with offset method bugs
- Improved `LocalFileProvider.copy()` implementation
2017-02-09 03:02:21 +03:30
7 changed files with 86 additions and 33 deletions
+1
View File
@@ -34,6 +34,7 @@ before_deploy:
- brew update
- brew outdated carthage || brew upgrade carthage
- carthage version
- carthage build --no-skip-current --verbose
- carthage archive $PROJECTNAME
deploy:
+1 -1
View File
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
#
s.name = "FileProvider"
s.version = "0.12.3"
s.version = "0.12.4"
s.summary = "FileManager replacement for Local and Remote (WebDAV/Dropbox/OneDrive/SMB2) files on iOS and macOS."
# This description is used to generate tags and improve search results.
+2 -2
View File
@@ -603,7 +603,7 @@
799396601D48B7BF00086753 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_VERSION_STRING = 0.12.3;
BUNDLE_VERSION_STRING = 0.12.4;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -633,7 +633,7 @@
799396611D48B7BF00086753 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_VERSION_STRING = 0.12.3;
BUNDLE_VERSION_STRING = 0.12.4;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
+44 -1
View File
@@ -329,13 +329,56 @@ let data = "What's up Newyork!".data(encoding: .utf8)
documentsProvider.writeContents(path: "old.txt", content: data, atomically: true, completionHandler: nil)
```
### Undo Operations
Providers conform to `FileProviderUndoable` can perform undo for **some** operations like moving/renaming, copying and creating (file or folder). **Now, only `LocalFileProvider` supports this feature.** To implement:
```swift
// To setup a new UndoManager:
documentsProvider.setupUndoManager()
// or if you have an UndoManager object already:
documentsProvider.undoManager = self.undoManager
// e.g.: To undo last operation manually:
documentsProvider.undoManager?.undo()
```
You can also bind `UndoManager` object with view controller to use shake gesture and builtin undo support in iOS/macOS, add these code to your ViewController class like this sample code:
```swift
class ViewController: UIViewController
override var canBecomeFirstResponder: Bool {
return true
}
override var undoManager: UndoManager? {
return (provider as? FileProvideUndoable)?.undoManager
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Your code here
UIApplication.shared.applicationSupportsShakeToEdit = true
self.becomeFirstResponder()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Your code here
UIApplication.shared.applicationSupportsShakeToEdit = false
self.resignFirstResponder()
}
// The rest of your implementation
}
```
### Operation Handle
Creating/Copying/Deleting functions return a `OperationHandle` for remote operations. It provides operation type, progress and a `.cancel()` method which allows you to cancel operation in midst.
It's not supported by native `(NS)FileManager` so `LocalFileProvider`, but this functionality will be added to future `PosixFileProvider` class.
### Monitoring FIle Changes
### Monitoring File Changes
You can monitor updates in some file system (Local and SMB2), there is three methods in supporting provider you can use to register a handler, to unregister and to check whether it's being monitored or not. It's useful to find out when new files added or removed from directory and update user interface. The handler will be dispatched to main threads to avoid UI bugs with a 0.25 sec delay.
+13
View File
@@ -493,9 +493,15 @@ public protocol FileProviderMonitor: FileProviderBasic {
}
public protocol FileProvideUndoable: FileProviderOperations {
/// To initialize undo manager either call `setupUndoManager()` or set it manually.
///
/// - Note: Only some operations (moving/renaming, copying and creating) are supported for undoing.
/// - Note: recording operations will occur after setting this object.
var undoManager: UndoManager? { get set }
/// UndoManager supports undoing this file operation
func canUndo(handle: OperationHandle) -> Bool
/// UndoManager supports undoing this operation
func canUndo(operation: FileOperationType) -> Bool
}
@@ -526,6 +532,13 @@ public extension FileProvideUndoable {
return nil
}
}
/// Initiates `self.undoManager` if equals with `nil`, and set `levelsOfUndo` to 10.
public func setupUndoManager() {
guard self.undoManager == nil else { return }
self.undoManager = UndoManager()
self.undoManager?.levelsOfUndo = 10
}
}
public protocol FileProvider: FileProviderBasic, FileProviderOperations, FileProviderReadWrite, NSCopying {
+22 -28
View File
@@ -200,7 +200,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
}
dynamic func doSimpleOperation(_ box: UndoBox) {
_ = self.doOperation(box.operation) { (_) in
guard let _ = self.undoManager else { return }
_ = self.doOperation(box.undoOperation) { (_) in
return
}
}
@@ -209,24 +210,23 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
fileprivate func doOperation(_ opType: FileOperationType, data: Data? = nil, atomically: Bool = false, completionHandler: SimpleCompletionHandler) -> OperationHandle? {
guard let sourcePath = opType.source else { return nil }
let destPath = opType.destination
let source: URL, dest: URL?
if sourcePath.hasPrefix("file://") {
source = URL(string: sourcePath)!
} else {
source = self.url(of: sourcePath)
}
let source: URL = sourcePath.hasPrefix("file://") ? URL(string: sourcePath)! : self.url(of: sourcePath)
let dest: URL?
if let destPath = destPath {
if destPath.hasPrefix("file://") {
dest = URL(string: destPath)!
} else {
dest = self.url(of: destPath)
}
dest = destPath.hasPrefix("file://") ? URL(string: destPath)! : self.url(of: destPath)
} else {
dest = nil
}
if let undoManager = self.undoManager, let undoOp = self.undoOperation(for: opType) {
let undoBox = UndoBox(provider: self, operation: opType, undoOperation: undoOp)
undoManager.beginUndoGrouping()
undoManager.registerUndo(withTarget: self, selector: #selector(LocalFileProvider.doSimpleOperation(_:)), object: undoBox)
undoManager.setActionName(opType.actionDescription)
undoManager.endUndoGrouping()
}
let operationHandler: (URL, URL?) -> Void = { source, dest in
let successfulSecurityScopedResourceAccess = source.startAccessingSecurityScopedResource()
do {
@@ -254,11 +254,6 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
source.stopAccessingSecurityScopedResource()
}
if let undoOp = self.undoOperation(for: opType) {
let undoBox = UndoBox(provider: self, operation: undoOp)
self.undoManager?.registerUndo(withTarget: self, selector: #selector(LocalFileProvider.doSimpleOperation(_:)), object: undoBox)
}
completionHandler?(nil)
DispatchQueue.main.async {
self.delegate?.fileproviderSucceed(self, operation: opType)
@@ -354,12 +349,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
let url = self.url(of: path)
let operationHandler: (URL) -> Void = { url in
guard self.fileManager.fileExists(atPath: url.path) && !url.fileIsDirectory else {
completionHandler(nil, self.throwError(path, code: CocoaError.fileNoSuchFile as FoundationErrorEnum))
return
}
guard let handle = FileHandle(forReadingAtPath: url.path) else {
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadNoPermission as FoundationErrorEnum))
completionHandler(nil, self.throwError(path, code: CocoaError.fileNoSuchFile as FoundationErrorEnum))
return
}
@@ -367,17 +358,18 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
handle.closeFile()
}
let size = LocalFileObject(fileWithURL: url)?.size ?? -1
guard size > offset else {
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum))
return
}
handle.seek(toFileOffset: UInt64(offset))
guard Int64(handle.offsetInFile) == offset else {
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadUnknown as FoundationErrorEnum))
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum))
return
}
let data = handle.readData(ofLength: length)
guard length > 0 && data.count == length else {
completionHandler(nil, self.throwError(path, code: CocoaError.fileReadTooLarge as FoundationErrorEnum))
return
}
completionHandler(data, nil)
}
@@ -462,6 +454,8 @@ open class LocalFileProvider: FileProvider, FileProviderMonitor, FileProvideUndo
copy.delegate = self.delegate
copy.fileOperationDelegate = self.fileOperationDelegate
copy.isPathRelative = self.isPathRelative
copy.undoManager = self.undoManager
copy.isCoorinating = self.isCoorinating
return copy
}
}
+3 -1
View File
@@ -308,10 +308,12 @@ open class LocalOperationHandle: OperationHandle {
class UndoBox: NSObject {
weak var provider: FileProvideUndoable?
let operation: FileOperationType
let undoOperation: FileOperationType
init(provider: FileProvideUndoable, operation: FileOperationType) {
init(provider: FileProvideUndoable, operation: FileOperationType, undoOperation: FileOperationType) {
self.provider = provider
self.operation = operation
self.undoOperation = undoOperation
}
}