DocumentPickerViewController.swift 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. //
  2. // DocumentPickerViewController.swift
  3. // Picker
  4. //
  5. // Created by Marino Faggiana on 27/12/16.
  6. // Copyright © 2016 TWS. All rights reserved.
  7. //
  8. // Author Marino Faggiana <m.faggiana@twsweb.it>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. import UIKit
  24. class DocumentPickerViewController: UIDocumentPickerExtensionViewController, CCNetworkingDelegate, OCNetworkingDelegate {
  25. // MARK: - Properties
  26. var providerDB : providerSessionDB?
  27. lazy var fileCoordinator: NSFileCoordinator = {
  28. let fileCoordinator = NSFileCoordinator()
  29. fileCoordinator.purposeIdentifier = self.parameterProviderIdentifier
  30. return fileCoordinator
  31. }()
  32. var parameterMode : UIDocumentPickerMode?
  33. var parameterOriginalURL: URL?
  34. var parameterProviderIdentifier: String!
  35. var metadata : CCMetadata?
  36. var recordsTableMetadata : [TableMetadata]?
  37. var titleFolder : String?
  38. var activeAccount : String?
  39. var activeUrl : String?
  40. var activeUser : String?
  41. var activePassword : String?
  42. var activeUID : String?
  43. var activeAccessToken : String?
  44. var directoryUser : String?
  45. var typeCloud : String?
  46. var serverUrl : String?
  47. var localServerUrl : String?
  48. var thumbnailInLoading = [String: IndexPath]()
  49. lazy var networkingOperationQueue : OperationQueue = {
  50. var queue = OperationQueue()
  51. queue.name = netQueueName
  52. queue.maxConcurrentOperationCount = 10
  53. return queue
  54. }()
  55. var hud : CCHud!
  56. // MARK: - IBOutlets
  57. @IBOutlet weak var tableView: UITableView!
  58. @IBOutlet weak var toolBar: UIToolbar!
  59. @IBOutlet weak var saveButton: UIBarButtonItem!
  60. // MARK: - View Life Cycle
  61. override func viewDidLoad() {
  62. providerDB = providerSessionDB.sharedInstance
  63. if let record = CCCoreData.getActiveAccount() {
  64. activeAccount = record.account!
  65. activePassword = record.password!
  66. activeUrl = record.url!
  67. activeUser = record.user!
  68. typeCloud = record.typeCloud!
  69. directoryUser = CCUtility.getDirectoryActiveUser(activeUser, activeUrl: activeUrl)
  70. if (localServerUrl == nil) {
  71. localServerUrl = CCUtility.getHomeServerUrlActiveUrl(activeUrl, typeCloud: typeCloud)
  72. } else {
  73. self.navigationItem.title = titleFolder
  74. }
  75. } else {
  76. // Close error no account return nil
  77. let deadlineTime = DispatchTime.now() + 0.1
  78. DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
  79. let alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_no_active_account_", comment: ""), preferredStyle: .alert)
  80. alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { action in
  81. self.dismissGrantingAccess(to: nil)
  82. })
  83. self.present(alert, animated: true, completion: nil)
  84. }
  85. return
  86. }
  87. // MARK: - init Object
  88. CCNetworking.shared().settingDelegate(self)
  89. hud = CCHud.init(view: self.navigationController?.view)
  90. // COLOR_SEPARATOR_TABLE
  91. self.tableView.separatorColor = UIColor(colorLiteralRed: 153.0/255.0, green: 153.0/255.0, blue: 153.0/255.0, alpha: 0.2)
  92. // (save) mode of presentation -> pass variable for pushViewController
  93. if parameterMode != nil {
  94. prepareForPresentation(in: parameterMode!)
  95. }
  96. readFolder()
  97. }
  98. // MARK: - Overridden Instance Methods
  99. override func prepareForPresentation(in mode: UIDocumentPickerMode) {
  100. // ------------------> Settings parameter ----------------
  101. if parameterMode == nil {
  102. parameterMode = mode
  103. }
  104. if parameterOriginalURL == nil && originalURL != nil {
  105. parameterOriginalURL = originalURL
  106. }
  107. if parameterProviderIdentifier == nil {
  108. parameterProviderIdentifier = providerIdentifier
  109. }
  110. // -------------------------------------------------------
  111. switch mode {
  112. case .exportToService:
  113. print("Document Picker Mode : exportToService")
  114. saveButton.title = "Save in this position"
  115. case .moveToService:
  116. //Show confirmation button
  117. print("Document Picker Mode : moveToService")
  118. saveButton.title = "Save in this position"
  119. case .open:
  120. print("Document Picker Mode : open")
  121. saveButton.tintColor = UIColor.clear
  122. case .import:
  123. print("Document Picker Mode : import")
  124. saveButton.tintColor = UIColor.clear
  125. }
  126. }
  127. // MARK: - Read folder
  128. func readFolder() {
  129. let metadataNet = CCMetadataNet.init(account: activeAccount)!
  130. metadataNet.action = actionReadFolder
  131. metadataNet.serverUrl = localServerUrl
  132. metadataNet.selector = selectorReadFolder
  133. let ocNetworking : OCnetworking = OCnetworking.init(delegate: self, metadataNet: metadataNet, withUser: activeUser, withPassword: activePassword, withUrl: activeUrl, withTypeCloud: typeCloud, activityIndicator: false)
  134. networkingOperationQueue.addOperation(ocNetworking)
  135. hud.visibleIndeterminateHud()
  136. }
  137. func readFolderFailure(_ metadataNet: CCMetadataNet!, message: String!, errorCode: Int) {
  138. hud.hideHud()
  139. let alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert)
  140. alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { action in
  141. self.dismissGrantingAccess(to: nil)
  142. })
  143. self.present(alert, animated: true, completion: nil)
  144. }
  145. func readFolderSuccess(_ metadataNet: CCMetadataNet!, permissions: String!, rev: String!, metadatas: [Any]!) {
  146. // remove all record
  147. let predicate = NSPredicate(format: "(account == '\(activeAccount!)') AND (directoryID == '\(metadataNet.directoryID!)') AND ((session == NULL) OR (session == ''))")
  148. CCCoreData.deleteMetadata(with: predicate)
  149. for metadata in metadatas as! [CCMetadata] {
  150. // do not insert crypto file
  151. if CCUtility.isCryptoString(metadata.fileName) {
  152. continue
  153. }
  154. // Only Directory ?
  155. if (parameterMode == .moveToService || parameterMode == .exportToService) && metadata.directory == false {
  156. continue
  157. }
  158. // plist + crypto = completed ?
  159. if CCUtility.isCryptoPlistString(metadata.fileName) && metadata.directory == false {
  160. var isCryptoComplete = false
  161. for completeMetadata in metadatas as! [CCMetadata] {
  162. if completeMetadata.fileName == CCUtility.trasformedFileNamePlist(inCrypto: metadata.fileName) {
  163. isCryptoComplete = true
  164. }
  165. }
  166. if isCryptoComplete == false {
  167. continue
  168. }
  169. }
  170. // Add record
  171. CCCoreData.add(metadata, activeAccount: activeAccount, activeUrl: activeUrl, typeCloud: typeCloud, context: nil)
  172. // if plist do not exists, download it
  173. if CCUtility.isCryptoPlistString(metadata.fileName) && FileManager.default.fileExists(atPath: "\(directoryUser!)/\(metadata.fileName!)") == false {
  174. let metadataNet = CCMetadataNet.init(account: activeAccount)!
  175. metadataNet.action = actionDownloadFile
  176. metadataNet.metadata = metadata
  177. metadataNet.downloadData = false
  178. metadataNet.downloadPlist = true
  179. metadataNet.selector = selectorLoadPlist
  180. metadataNet.serverUrl = localServerUrl
  181. metadataNet.session = download_session_foreground
  182. metadataNet.taskStatus = Int(taskStatusResume)
  183. let ocNetworking : OCnetworking = OCnetworking.init(delegate: self, metadataNet: metadataNet, withUser: activeUser, withPassword: activePassword, withUrl: activeUrl, withTypeCloud: typeCloud, activityIndicator: false)
  184. networkingOperationQueue.addOperation(ocNetworking)
  185. }
  186. }
  187. // Get Datasource
  188. recordsTableMetadata = CCCoreData.getTableMetadata(with: NSPredicate(format: "(account == '\(activeAccount!)') AND (directoryID == '\(metadataNet.directoryID!)')"), fieldOrder: "fileName", ascending: true) as? [TableMetadata]
  189. tableView.reloadData()
  190. hud.hideHud()
  191. }
  192. // MARK: - Download / Upload
  193. func progressTask(_ fileID: String!, serverUrl: String!, cryptated: Bool, progress: Float) {
  194. hud.progress(progress)
  195. }
  196. func cancelTransfer() {
  197. networkingOperationQueue.cancelAllOperations()
  198. }
  199. // MARK: - Download
  200. func downloadFileFailure(_ fileID: String!, serverUrl: String!, selector: String!, message: String!, errorCode: Int) {
  201. hud.hideHud()
  202. if selector == selectorLoadFileView && errorCode != -999 {
  203. let alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert)
  204. alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { action in
  205. //self.dismissGrantingAccess(to: nil)
  206. NSLog("[LOG] Download Error \(fileID) \(message) (error \(errorCode))");
  207. })
  208. self.present(alert, animated: true, completion: nil)
  209. }
  210. }
  211. func downloadFileSuccess(_ fileID: String!, serverUrl: String!, selector: String!, selectorPost: String!) {
  212. hud.hideHud()
  213. let metadata = CCCoreData.getMetadataWithPreficate(NSPredicate(format: "(account == '\(activeAccount!)') AND (fileID == '\(fileID!)')"), context: nil)
  214. switch selector {
  215. case selectorLoadFileView :
  216. do {
  217. try FileManager.default.moveItem(atPath: "\(directoryUser!)/\(fileID!)", toPath: "\(directoryUser!)/\(metadata!.fileNamePrint!)")
  218. } catch let error as NSError {
  219. print(error)
  220. }
  221. let url = URL(string: "file://\(directoryUser!)/\(metadata!.fileNamePrint!)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)
  222. self.dismissGrantingAccess(to: url)
  223. case selectorLoadPlist :
  224. CCCoreData.downloadFilePlist(metadata, activeAccount: activeAccount, activeUrl: activeUrl, typeCloud: typeCloud, directoryUser: directoryUser)
  225. tableView.reloadData()
  226. default :
  227. print("selector : \(selector!)")
  228. tableView.reloadData()
  229. }
  230. }
  231. // MARK: - Upload
  232. func uploadFileFailure(_ fileID: String!, serverUrl: String!, selector: String!, message: String!, errorCode: Int) {
  233. hud.hideHud()
  234. // remove file
  235. CCCoreData.deleteMetadata(with: NSPredicate(format: "(account == '\(activeAccount!)') AND (fileID == '\(fileID!)')"))
  236. if errorCode != -999 {
  237. let alert = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: message, preferredStyle: .alert)
  238. alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { action in
  239. //self.dismissGrantingAccess(to: nil)
  240. NSLog("[LOG] Download Error \(fileID) \(message) (error \(errorCode))");
  241. })
  242. self.present(alert, animated: true, completion: nil)
  243. }
  244. }
  245. func uploadFileSuccess(_ fileID: String!, serverUrl: String!, selector: String!, selectorPost: String!) {
  246. hud.hideHud()
  247. let url = URL(string: "file://\(directoryUser!)/\(fileID!)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)
  248. dismissGrantingAccess(to: nil)
  249. }
  250. // MARK: - Download Thumbnail
  251. func downloadThumbnailFailure(_ metadataNet: CCMetadataNet!, message: String!, errorCode: Int) {
  252. NSLog("[LOG] Thumbnail Error \(metadataNet.fileName) \(message) (error \(errorCode))");
  253. }
  254. func downloadThumbnailSuccess(_ metadataNet: CCMetadataNet!) {
  255. if let indexPath = thumbnailInLoading[metadataNet.fileID] {
  256. let path = "\(directoryUser!)/\(metadataNet.fileID!).ico"
  257. if FileManager.default.fileExists(atPath: path) {
  258. if let cell = tableView.cellForRow(at: indexPath) as? recordMetadataCell {
  259. cell.fileImageView.image = UIImage(contentsOfFile: path)
  260. }
  261. }
  262. }
  263. }
  264. func downloadThumbnail(_ metadata : CCMetadata) {
  265. let metadataNet = CCMetadataNet.init(account: activeAccount)!
  266. metadataNet.action = actionDownloadThumbnail
  267. metadataNet.fileID = metadata.fileID
  268. metadataNet.fileName = CCUtility.returnFileNamePath(fromFileName: metadata.fileName, serverUrl: localServerUrl, activeUrl: activeUrl, typeCloud: typeCloud)
  269. metadataNet.fileNameLocal = metadata.fileID;
  270. metadataNet.fileNamePrint = metadata.fileNamePrint;
  271. metadataNet.options = "m";
  272. metadataNet.selector = selectorDownloadThumbnail;
  273. metadataNet.serverUrl = localServerUrl
  274. let ocNetworking : OCnetworking = OCnetworking.init(delegate: self, metadataNet: metadataNet, withUser: activeUser, withPassword: activePassword, withUrl: activeUrl, withTypeCloud: typeCloud, activityIndicator: false)
  275. networkingOperationQueue.addOperation(ocNetworking)
  276. }
  277. }
  278. // MARK: - IBActions
  279. extension DocumentPickerViewController {
  280. @IBAction func saveButtonTapped(_ sender: AnyObject) {
  281. guard let sourceURL = parameterOriginalURL else {
  282. return
  283. }
  284. switch parameterMode! {
  285. case .moveToService, .exportToService:
  286. let fileName = sourceURL.lastPathComponent
  287. guard let destinationURL = URL(string: "file://\(directoryUser!)/\(fileName)".addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!) else {
  288. return
  289. }
  290. fileCoordinator.coordinate(readingItemAt: sourceURL, options: .withoutChanges, error: nil, byAccessor: { [weak self] newURL in
  291. // Remove destination file
  292. do {
  293. try FileManager.default.removeItem(at: destinationURL)
  294. } catch _ {
  295. print("file do not exists")
  296. }
  297. do {
  298. try FileManager.default.copyItem(at: sourceURL, to: destinationURL)
  299. // Upload fileName to Cloud
  300. let metadataNet = CCMetadataNet.init(account: self!.activeAccount)!
  301. metadataNet.action = actionUploadFile
  302. metadataNet.cryptated = false
  303. metadataNet.fileName = fileName
  304. metadataNet.fileNamePrint = fileName
  305. metadataNet.serverUrl = self!.localServerUrl
  306. metadataNet.session = upload_session_foreground
  307. metadataNet.taskStatus = Int(taskStatusResume)
  308. let ocNetworking : OCnetworking = OCnetworking.init(delegate: self!, metadataNet: metadataNet, withUser: self!.activeUser, withPassword: self!.activePassword, withUrl: self!.activeUrl, withTypeCloud: self!.typeCloud, activityIndicator: false)
  309. self!.networkingOperationQueue.addOperation(ocNetworking)
  310. self!.hud.visibleHudTitle(NSLocalizedString("_uploading_", comment: ""), mode: MBProgressHUDMode.determinateHorizontalBar, color: self!.navigationController?.view.tintColor)
  311. self!.hud.addButtonCancel(withTarget: self, selector: "cancelTransfer")
  312. } catch _ {
  313. print("error copying file")
  314. }
  315. })
  316. default:
  317. dismiss(animated: true, completion: nil)
  318. }
  319. }
  320. }
  321. // MARK: - UITableViewDelegate
  322. extension DocumentPickerViewController: UITableViewDelegate {
  323. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  324. return 50
  325. }
  326. }
  327. // MARK: - UITableViewDataSource
  328. extension DocumentPickerViewController: UITableViewDataSource {
  329. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  330. if (recordsTableMetadata == nil) {
  331. return 0
  332. } else {
  333. return recordsTableMetadata!.count
  334. }
  335. }
  336. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  337. let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! recordMetadataCell
  338. cell.separatorInset = UIEdgeInsetsMake(0, 60, 0, 0)
  339. let recordTableMetadata = recordsTableMetadata?[(indexPath as NSIndexPath).row]
  340. let metadata = CCCoreData.insertEntity(in: recordTableMetadata)!
  341. // File Image View
  342. let filePath = "\(directoryUser!)/\(metadata.fileID!).ico"
  343. if FileManager.default.fileExists(atPath: filePath) {
  344. cell.fileImageView.image = UIImage(contentsOfFile: filePath)
  345. } else {
  346. cell.fileImageView.image = UIImage(named: metadata.iconName!)
  347. if metadata.thumbnailExists && metadata.directory == false {
  348. downloadThumbnail(metadata)
  349. thumbnailInLoading[metadata.fileID] = indexPath
  350. }
  351. }
  352. // File Name
  353. cell.FileName.text = metadata.fileNamePrint
  354. return cell
  355. }
  356. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  357. let recordTableMetadata = recordsTableMetadata?[(indexPath as NSIndexPath).row]
  358. tableView.deselectRow(at: indexPath, animated: true)
  359. if recordTableMetadata!.directory == 0 {
  360. let metadata = CCCoreData.insertEntity(in: recordTableMetadata)!
  361. if FileManager.default.fileExists(atPath: "\(directoryUser!)/\(metadata.fileID!)") {
  362. downloadFileSuccess(metadata.fileID!, serverUrl: localServerUrl!, selector: selectorLoadFileView, selectorPost: nil)
  363. } else {
  364. // Download file
  365. let metadataNet = CCMetadataNet.init(account: activeAccount)!
  366. metadataNet.action = actionDownloadFile
  367. metadataNet.downloadData = true
  368. metadataNet.downloadPlist = false
  369. metadataNet.metadata = metadata
  370. metadataNet.selector = selectorLoadFileView
  371. metadataNet.serverUrl = localServerUrl
  372. metadataNet.session = download_session_foreground
  373. metadataNet.taskStatus = Int(taskStatusResume)
  374. let ocNetworking : OCnetworking = OCnetworking.init(delegate: self, metadataNet: metadataNet, withUser: activeUser, withPassword: activePassword, withUrl: activeUrl, withTypeCloud: typeCloud, activityIndicator: false)
  375. networkingOperationQueue.addOperation(ocNetworking)
  376. hud.visibleHudTitle(NSLocalizedString("_loading_", comment: ""), mode: MBProgressHUDMode.determinateHorizontalBar, color: self.navigationController?.view.tintColor)
  377. hud.addButtonCancel(withTarget: self, selector: "cancelTransfer")
  378. }
  379. } else {
  380. var dir : String! = recordTableMetadata!.fileName
  381. let nextViewController = self.storyboard?.instantiateViewController(withIdentifier: "DocumentPickerViewController") as! DocumentPickerViewController
  382. if recordTableMetadata?.cryptated == 1 {
  383. dir = CCUtility.trasformedFileNamePlist(inCrypto: recordTableMetadata!.fileName)
  384. }
  385. nextViewController.parameterMode = parameterMode
  386. nextViewController.parameterOriginalURL = parameterOriginalURL
  387. nextViewController.parameterProviderIdentifier = parameterProviderIdentifier
  388. nextViewController.localServerUrl = CCUtility.stringAppendServerUrl(localServerUrl!, addServerUrl: dir)
  389. nextViewController.titleFolder = recordTableMetadata?.fileNamePrint
  390. self.navigationController?.pushViewController(nextViewController, animated: true)
  391. }
  392. }
  393. }
  394. // MARK: - Class UITableViewCell
  395. class recordMetadataCell: UITableViewCell {
  396. @IBOutlet weak var fileImageView: UIImageView!
  397. @IBOutlet weak var FileName : UILabel!
  398. }
  399. // MARK: - Class providerSession
  400. class providerSessionDB {
  401. class var sharedInstance : providerSessionDB {
  402. struct Static {
  403. static let instance = providerSessionDB()
  404. }
  405. return Static.instance
  406. }
  407. private init() {
  408. let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: capabilitiesGroups)
  409. let pathDB = dirGroup?.appendingPathComponent(appDatabase).appendingPathComponent("cryptocloud")
  410. MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStore(at: pathDB!)
  411. MagicalRecord.setLoggingLevel(MagicalRecordLoggingLevel.off)
  412. }
  413. }