NCShareExtension.swift 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. //
  2. // NCShareExtension.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 20/04/2021.
  6. // Copyright © 2021 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  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. import NCCommunication
  25. import IHProgressHUD
  26. class NCShareExtension: UIViewController, NCListCellDelegate, NCEmptyDataSetDelegate, NCRenameFileDelegate, NCAccountRequestDelegate {
  27. @IBOutlet weak var collectionView: UICollectionView!
  28. @IBOutlet weak var tableView: UITableView!
  29. @IBOutlet weak var cancelButton: UIBarButtonItem!
  30. @IBOutlet weak var separatorView: UIView!
  31. @IBOutlet weak var commandView: UIView!
  32. @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint!
  33. @IBOutlet weak var commandViewHeightConstraint: NSLayoutConstraint!
  34. @IBOutlet weak var createFolderView: UIView!
  35. @IBOutlet weak var createFolderImage: UIImageView!
  36. @IBOutlet weak var createFolderLabel: UILabel!
  37. @IBOutlet weak var uploadView: UIView!
  38. @IBOutlet weak var uploadImage: UIImageView!
  39. @IBOutlet weak var uploadLabel: UILabel!
  40. // -------------------------------------------------------------
  41. var serverUrl = ""
  42. var filesName: [String] = []
  43. // -------------------------------------------------------------
  44. private var emptyDataSet: NCEmptyDataSet?
  45. private let keyLayout = NCGlobal.shared.layoutViewShareExtension
  46. private var metadataFolder: tableMetadata?
  47. private var networkInProgress = false
  48. private var dataSource = NCDataSource()
  49. private var layoutForView: NCGlobal.layoutForViewType?
  50. private var heightRowTableView: CGFloat = 50
  51. private var heightCommandView: CGFloat = 170
  52. private var autoUploadFileName = ""
  53. private var autoUploadDirectory = ""
  54. private let refreshControl = UIRefreshControl()
  55. private var activeAccount: tableAccount!
  56. private let chunckSize = CCUtility.getChunkSize() * 1000000
  57. private var numberFilesName: Int = 0
  58. private var counterUpload: Int = 0
  59. // MARK: - View Life Cycle
  60. override func viewDidLoad() {
  61. super.viewDidLoad()
  62. self.navigationController?.navigationBar.prefersLargeTitles = false
  63. // Cell
  64. collectionView.register(UINib.init(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell")
  65. collectionView.collectionViewLayout = NCListLayout()
  66. // Add Refresh Control
  67. collectionView.addSubview(refreshControl)
  68. refreshControl.tintColor = NCBrandColor.shared.brandText
  69. refreshControl.backgroundColor = NCBrandColor.shared.systemBackground
  70. refreshControl.addTarget(self, action: #selector(reloadDatasource), for: .valueChanged)
  71. // Command view
  72. commandView.backgroundColor = NCBrandColor.shared.secondarySystemBackground
  73. separatorView.backgroundColor = NCBrandColor.shared.separator
  74. separatorHeightConstraint.constant = 0.5
  75. // Table view
  76. tableView.separatorColor = NCBrandColor.shared.separator
  77. tableView.layer.cornerRadius = 10
  78. tableView.tableFooterView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 0, height: 1)))
  79. commandViewHeightConstraint.constant = heightCommandView
  80. // Create folder
  81. createFolderView.layer.cornerRadius = 10
  82. createFolderImage.image = NCUtility.shared.loadImage(named: "folder.badge.plus", color: NCBrandColor.shared.label)
  83. createFolderLabel.text = NSLocalizedString("_create_folder_", comment: "")
  84. let createFolderGesture = UITapGestureRecognizer(target: self, action: #selector(actionCreateFolder))
  85. createFolderView.addGestureRecognizer(createFolderGesture)
  86. // Upload
  87. uploadView.layer.cornerRadius = 10
  88. //uploadImage.image = NCUtility.shared.loadImage(named: "square.and.arrow.up", color: NCBrandColor.shared.label)
  89. uploadLabel.text = NSLocalizedString("_upload_", comment: "")
  90. uploadLabel.textColor = .systemBlue
  91. let uploadGesture = UITapGestureRecognizer(target: self, action: #selector(actionUpload))
  92. uploadView.addGestureRecognizer(uploadGesture)
  93. // LOG
  94. let levelLog = CCUtility.getLogLevel()
  95. let isSimulatorOrTestFlight = NCUtility.shared.isSimulatorOrTestFlight()
  96. let versionNextcloudiOS = String(format: NCBrandOptions.shared.textCopyrightNextcloudiOS, NCUtility.shared.getVersionApp())
  97. NCCommunicationCommon.shared.levelLog = levelLog
  98. if let pathDirectoryGroup = CCUtility.getDirectoryGroup()?.path {
  99. NCCommunicationCommon.shared.pathLog = pathDirectoryGroup
  100. }
  101. if isSimulatorOrTestFlight {
  102. NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + versionNextcloudiOS + " (Simulator / TestFlight)")
  103. } else {
  104. NCCommunicationCommon.shared.writeLog("Start session with level \(levelLog) " + versionNextcloudiOS)
  105. }
  106. // HUD
  107. IHProgressHUD.set(viewForExtension: self.view)
  108. IHProgressHUD.set(defaultMaskType: .clear)
  109. IHProgressHUD.set(minimumDismiss: 0)
  110. NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object:nil)
  111. }
  112. override func viewWillAppear(_ animated: Bool) {
  113. super.viewWillAppear(animated)
  114. if serverUrl == "" {
  115. if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
  116. setAccount(account: activeAccount.account)
  117. getFilesExtensionContext { (filesName) in
  118. self.filesName = filesName
  119. DispatchQueue.main.async {
  120. var saveHtml: [String] = []
  121. var saveOther: [String] = []
  122. for fileName in self.filesName {
  123. if (fileName as NSString).pathExtension.lowercased() == "html" {
  124. saveHtml.append(fileName)
  125. } else {
  126. saveOther.append(fileName)
  127. }
  128. }
  129. if saveOther.count > 0 && saveHtml.count > 0 {
  130. for file in saveHtml {
  131. self.filesName = self.filesName.filter(){$0 != file}
  132. }
  133. }
  134. self.setCommandView()
  135. }
  136. }
  137. } else {
  138. let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: NSLocalizedString("_no_active_account_", comment: ""), preferredStyle: .alert)
  139. alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
  140. self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
  141. }))
  142. self.present(alertController, animated: true)
  143. }
  144. }
  145. }
  146. override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
  147. super.viewWillTransition(to: size, with: coordinator)
  148. coordinator.animate(alongsideTransition: nil) { _ in
  149. self.collectionView?.collectionViewLayout.invalidateLayout()
  150. }
  151. }
  152. override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
  153. super.traitCollectionDidChange(previousTraitCollection)
  154. collectionView.reloadData()
  155. tableView.reloadData()
  156. }
  157. // MARK: -
  158. @objc func triggerProgressTask(_ notification: NSNotification) {
  159. if let userInfo = notification.userInfo as NSDictionary?, let progressNumber = userInfo["progress"] as? NSNumber {
  160. let progress = CGFloat(progressNumber.floatValue)
  161. let status = NSLocalizedString("_upload_file_", comment: "") + " \(self.counterUpload) " + NSLocalizedString("_of_", comment: "") + " \(self.numberFilesName)"
  162. IHProgressHUD.show(progress: progress, status: status)
  163. }
  164. }
  165. // MARK: -
  166. func setAccount(account: String) {
  167. guard let activeAccount = NCManageDatabase.shared.getAccount(predicate: NSPredicate(format: "account == %@", account)) else {
  168. extensionContext?.completeRequest(returningItems: extensionContext?.inputItems, completionHandler: nil)
  169. return
  170. }
  171. self.activeAccount = activeAccount
  172. // NETWORKING
  173. NCCommunicationCommon.shared.setup(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, password: CCUtility.getPassword(activeAccount.account), urlBase: activeAccount.urlBase, userAgent: CCUtility.getUserAgent(), webDav: NCUtilityFileSystem.shared.getWebDAV(account: activeAccount.account), nextcloudVersion: 0, delegate: NCNetworking.shared)
  174. // get auto upload folder
  175. autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName()
  176. autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: activeAccount.urlBase, account: activeAccount.account)
  177. serverUrl = NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account)
  178. layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout,serverUrl: serverUrl)
  179. reloadDatasource(withLoadFolder: true)
  180. setNavigationBar(navigationTitle: NCBrandOptions.shared.brand)
  181. }
  182. func setNavigationBar(navigationTitle: String) {
  183. navigationItem.title = navigationTitle
  184. cancelButton.title = NSLocalizedString("_cancel_", comment: "")
  185. // BACK BUTTON
  186. let backButton = UIButton(type: .custom)
  187. backButton.setImage(UIImage(named: "back"), for: .normal)
  188. backButton.tintColor = .systemBlue
  189. backButton.semanticContentAttribute = .forceLeftToRight
  190. backButton.setTitle(" "+NSLocalizedString("_back_", comment: ""), for: .normal)
  191. backButton.setTitleColor(.systemBlue, for: .normal)
  192. backButton.action(for: .touchUpInside) { _ in
  193. while self.serverUrl.last != "/" {
  194. self.serverUrl.removeLast()
  195. }
  196. self.serverUrl.removeLast()
  197. self.reloadDatasource(withLoadFolder: true)
  198. var navigationTitle = (self.serverUrl as NSString).lastPathComponent
  199. if NCUtilityFileSystem.shared.getHomeServer(account: self.activeAccount.account) == self.serverUrl {
  200. navigationTitle = NCBrandOptions.shared.brand
  201. }
  202. self.setNavigationBar(navigationTitle: navigationTitle)
  203. }
  204. // PROFILE BUTTON
  205. let image = NCUtility.shared.loadUserImage(
  206. for: activeAccount.user,
  207. displayName: activeAccount.displayName,
  208. userBaseUrl: activeAccount)
  209. let profileButton = UIButton(type: .custom)
  210. profileButton.setImage(image, for: .normal)
  211. if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) {
  212. var title = " "
  213. if let userAlias = activeAccount?.alias, !userAlias.isEmpty {
  214. title += userAlias
  215. } else {
  216. title += activeAccount?.displayName ?? ""
  217. }
  218. profileButton.setTitle(title, for: .normal)
  219. profileButton.setTitleColor(.systemBlue, for: .normal)
  220. }
  221. profileButton.semanticContentAttribute = .forceLeftToRight
  222. profileButton.sizeToFit()
  223. profileButton.action(for: .touchUpInside) { _ in
  224. let accounts = NCManageDatabase.shared.getAllAccountOrderAlias()
  225. if accounts.count > 1 {
  226. if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
  227. // Only here change the active account
  228. for account in accounts {
  229. if account.account == self.activeAccount.account {
  230. account.active = true
  231. } else {
  232. account.active = false
  233. }
  234. }
  235. vcAccountRequest.activeAccount = self.activeAccount
  236. vcAccountRequest.accounts = accounts.sorted { (sorg, dest) -> Bool in
  237. return sorg.active && !dest.active
  238. }
  239. vcAccountRequest.enableTimerProgress = false
  240. vcAccountRequest.enableAddAccount = false
  241. vcAccountRequest.delegate = self
  242. vcAccountRequest.dismissDidEnterBackground = true
  243. let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height/5)
  244. let numberCell = accounts.count
  245. let height = min(CGFloat(numberCell * Int(vcAccountRequest.heightCell) + 45), screenHeighMax)
  246. let popup = NCPopupViewController(contentController: vcAccountRequest, popupWidth: 300, popupHeight: height+20)
  247. self.present(popup, animated: true)
  248. }
  249. }
  250. }
  251. if serverUrl == NCUtilityFileSystem.shared.getHomeServer(account: activeAccount.account) {
  252. navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: profileButton)], animated: true)
  253. } else {
  254. let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
  255. space.width = 20
  256. navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: backButton), space, UIBarButtonItem(customView: profileButton)], animated: true)
  257. }
  258. }
  259. func setCommandView() {
  260. var counter: CGFloat = 0
  261. if filesName.count == 0 {
  262. self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
  263. return
  264. } else {
  265. if filesName.count < 3 {
  266. counter = CGFloat(filesName.count)
  267. self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter)
  268. } else {
  269. counter = 3
  270. self.commandViewHeightConstraint.constant = heightCommandView + (self.heightRowTableView * counter)
  271. }
  272. if filesName.count <= 3 {
  273. self.tableView.isScrollEnabled = false
  274. }
  275. // Label upload button
  276. numberFilesName = filesName.count
  277. uploadLabel.text = NSLocalizedString("_upload_", comment: "") + " \(numberFilesName) " + NSLocalizedString("_files_", comment: "")
  278. // Empty
  279. emptyDataSet = NCEmptyDataSet.init(view: collectionView, offset: -50*counter, delegate: self)
  280. self.tableView.reloadData()
  281. }
  282. }
  283. // MARK: - Empty
  284. func emptyDataSetView(_ view: NCEmptyView) {
  285. if networkInProgress {
  286. view.emptyImage.image = UIImage.init(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
  287. view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
  288. view.emptyDescription.text = ""
  289. } else {
  290. view.emptyImage.image = UIImage.init(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
  291. view.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
  292. view.emptyDescription.text = ""
  293. }
  294. }
  295. // MARK: ACTION
  296. @IBAction func actionCancel(_ sender: UIBarButtonItem) {
  297. extensionContext?.completeRequest(returningItems: extensionContext?.inputItems, completionHandler: nil)
  298. }
  299. @objc func actionCreateFolder() {
  300. let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message:"", preferredStyle: .alert)
  301. alertController.addTextField { (textField) in
  302. textField.autocapitalizationType = UITextAutocapitalizationType.words
  303. }
  304. let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { (action:UIAlertAction) in
  305. if let fileName = alertController.textFields?.first?.text {
  306. self.createFolder(with: fileName)
  307. }
  308. }
  309. let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (action:UIAlertAction) in
  310. print("You've pressed cancel button")
  311. }
  312. alertController.addAction(actionSave)
  313. alertController.addAction(actionCancel)
  314. self.present(alertController, animated: true, completion:nil)
  315. }
  316. @objc func actionUpload() {
  317. if let fileName = filesName.first {
  318. counterUpload += 1
  319. filesName.removeFirst()
  320. let ocId = NSUUID().uuidString
  321. let filePath = CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!
  322. if NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: filePath) {
  323. let metadata = NCManageDatabase.shared.createMetadata(account: activeAccount.account, user: activeAccount.user, userId: activeAccount.userId, fileName: fileName, fileNameView: fileName, ocId: ocId, serverUrl: serverUrl, urlBase: activeAccount.urlBase, url: "", contentType: "", livePhoto: false)
  324. metadata.session = NCCommunicationCommon.shared.sessionIdentifierUpload
  325. metadata.sessionSelector = NCGlobal.shared.selectorUploadFile
  326. metadata.size = NCUtilityFileSystem.shared.getFileSize(filePath: filePath)
  327. metadata.status = NCGlobal.shared.metadataStatusWaitUpload
  328. // E2EE
  329. if CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase) {
  330. metadata.e2eEncrypted = true
  331. }
  332. // CHUNCK
  333. if chunckSize != 0 && metadata.size > chunckSize {
  334. metadata.chunk = true
  335. }
  336. NCNetworking.shared.upload(metadata: metadata) {
  337. } completion: { (errorCode, errorDescription) in
  338. if errorCode == 0 {
  339. self.actionUpload()
  340. } else {
  341. IHProgressHUD.dismiss()
  342. NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", ocId))
  343. NCManageDatabase.shared.deleteChunks(account: self.activeAccount.account, ocId: ocId)
  344. let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert)
  345. alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
  346. self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
  347. }))
  348. self.present(alertController, animated: true)
  349. }
  350. }
  351. }
  352. } else {
  353. IHProgressHUD.showSuccesswithStatus(NSLocalizedString("_success_", comment: ""))
  354. DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
  355. self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
  356. }
  357. }
  358. }
  359. func rename(fileName: String, fileNameNew: String) {
  360. if let row = self.filesName.firstIndex(where: {$0 == fileName}) {
  361. if NCUtilityFileSystem.shared.moveFile(atPath: (NSTemporaryDirectory() + fileName), toPath: (NSTemporaryDirectory() + fileNameNew)) {
  362. filesName[row] = fileNameNew
  363. tableView.reloadData()
  364. }
  365. }
  366. }
  367. func accountRequestChangeAccount(account: String) {
  368. setAccount(account: account)
  369. }
  370. }
  371. // MARK: - Collection View
  372. extension NCShareExtension: UICollectionViewDelegate {
  373. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  374. if let metadata = dataSource.cellForItemAt(indexPath: indexPath) {
  375. if let serverUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName) {
  376. if metadata.e2eEncrypted && !CCUtility.isEnd(toEndEnabled: activeAccount.account) {
  377. let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: NSLocalizedString("_e2e_goto_settings_for_enable_", comment: ""), preferredStyle: .alert)
  378. alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
  379. self.present(alertController, animated: true)
  380. return
  381. }
  382. self.serverUrl = serverUrl
  383. reloadDatasource(withLoadFolder: true)
  384. setNavigationBar(navigationTitle: metadata.fileNameView)
  385. }
  386. }
  387. }
  388. }
  389. extension NCShareExtension: UICollectionViewDataSource {
  390. func numberOfSections(in collectionView: UICollectionView) -> Int {
  391. return 1
  392. }
  393. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  394. let numberOfItems = dataSource.numberOfItems()
  395. emptyDataSet?.numberOfItemsInSection(numberOfItems, section:section)
  396. return numberOfItems
  397. }
  398. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  399. guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else {
  400. return collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell
  401. }
  402. var tableShare: tableShare?
  403. var isShare = false
  404. var isMounted = false
  405. if let metadataFolder = metadataFolder {
  406. isShare = metadata.permissions.contains(NCGlobal.shared.permissionShared) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionShared)
  407. isMounted = metadata.permissions.contains(NCGlobal.shared.permissionMounted) && !metadataFolder.permissions.contains(NCGlobal.shared.permissionMounted)
  408. }
  409. if dataSource.metadataShare[metadata.ocId] != nil {
  410. tableShare = dataSource.metadataShare[metadata.ocId]
  411. }
  412. let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as! NCListCell
  413. cell.delegate = self
  414. cell.fileObjectId = metadata.ocId
  415. cell.fileUser = metadata.ownerId
  416. cell.labelTitle.text = metadata.fileNameView
  417. cell.labelTitle.textColor = NCBrandColor.shared.label
  418. cell.imageSelect.image = nil
  419. cell.imageStatus.image = nil
  420. cell.imageLocal.image = nil
  421. cell.imageFavorite.image = nil
  422. cell.imageShared.image = nil
  423. cell.imageMore.image = nil
  424. cell.imageItem.image = nil
  425. cell.imageItem.backgroundColor = nil
  426. cell.progressView.progress = 0.0
  427. if metadata.directory {
  428. if metadata.e2eEncrypted {
  429. cell.imageItem.image = NCBrandColor.cacheImages.folderEncrypted
  430. } else if isShare {
  431. cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe
  432. } else if (tableShare != nil && tableShare?.shareType != 3) {
  433. cell.imageItem.image = NCBrandColor.cacheImages.folderSharedWithMe
  434. } else if (tableShare != nil && tableShare?.shareType == 3) {
  435. cell.imageItem.image = NCBrandColor.cacheImages.folderPublic
  436. } else if metadata.mountType == "group" {
  437. cell.imageItem.image = NCBrandColor.cacheImages.folderGroup
  438. } else if isMounted {
  439. cell.imageItem.image = NCBrandColor.cacheImages.folderExternal
  440. } else if metadata.fileName == autoUploadFileName && metadata.serverUrl == autoUploadDirectory {
  441. cell.imageItem.image = NCBrandColor.cacheImages.folderAutomaticUpload
  442. } else {
  443. cell.imageItem.image = NCBrandColor.cacheImages.folder
  444. }
  445. cell.labelInfo.text = CCUtility.dateDiff(metadata.date as Date)
  446. let lockServerUrl = CCUtility.stringAppendServerUrl(metadata.serverUrl, addFileName: metadata.fileName)!
  447. let tableDirectory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", activeAccount.account, lockServerUrl))
  448. // Local image: offline
  449. if tableDirectory != nil && tableDirectory!.offline {
  450. cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag
  451. }
  452. }
  453. // image Favorite
  454. if metadata.favorite {
  455. cell.imageFavorite.image = NCBrandColor.cacheImages.favorite
  456. }
  457. cell.imageSelect.isHidden = true
  458. cell.backgroundView = nil
  459. cell.hideButtonMore(true)
  460. cell.hideButtonShare(true)
  461. cell.selectMode(false)
  462. // Live Photo
  463. if metadata.livePhoto {
  464. cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto
  465. }
  466. // Remove last separator
  467. if collectionView.numberOfItems(inSection: indexPath.section) == indexPath.row + 1 {
  468. cell.separator.isHidden = true
  469. } else {
  470. cell.separator.isHidden = false
  471. }
  472. return cell
  473. }
  474. }
  475. // MARK: - Table View
  476. extension NCShareExtension: UITableViewDelegate {
  477. func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
  478. return heightRowTableView
  479. }
  480. func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  481. }
  482. }
  483. extension NCShareExtension: UITableViewDataSource {
  484. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  485. filesName.count
  486. }
  487. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  488. let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
  489. cell.backgroundColor = NCBrandColor.shared.systemBackground
  490. let imageCell = cell.viewWithTag(10) as? UIImageView
  491. let fileNameCell = cell.viewWithTag(20) as? UILabel
  492. let moreButton = cell.viewWithTag(30) as? NCShareExtensionButtonWithIndexPath
  493. let sizeCell = cell.viewWithTag(40) as? UILabel
  494. imageCell?.layer.cornerRadius = 6
  495. imageCell?.layer.masksToBounds = true
  496. let fileName = filesName[indexPath.row]
  497. let resultInternalType = NCCommunicationCommon.shared.getInternalType(fileName: fileName, mimeType: "", directory: false)
  498. if let image = UIImage(contentsOfFile: (NSTemporaryDirectory() + fileName)) {
  499. imageCell?.image = image.resizeImage(size: CGSize(width: 80, height: 80), isAspectRation: true)
  500. } else {
  501. if resultInternalType.iconName.count > 0 {
  502. imageCell?.image = UIImage.init(named: resultInternalType.iconName)
  503. } else {
  504. imageCell?.image = NCBrandColor.cacheImages.file
  505. }
  506. }
  507. fileNameCell?.text = fileName
  508. let fileSize = NCUtilityFileSystem.shared.getFileSize(filePath: (NSTemporaryDirectory() + fileName))
  509. sizeCell?.text = CCUtility.transformedSize(fileSize)
  510. moreButton?.setImage(NCUtility.shared.loadImage(named: "more").image(color: NCBrandColor.shared.label, size: 15), for: .normal)
  511. moreButton?.indexPath = indexPath
  512. moreButton?.fileName = fileName
  513. moreButton?.image = imageCell?.image
  514. moreButton?.action(for: .touchUpInside, { sender in
  515. if let fileName = (sender as! NCShareExtensionButtonWithIndexPath).fileName {
  516. let alertController = UIAlertController(title: "", message: fileName, preferredStyle: .alert)
  517. alertController.addAction(UIAlertAction(title: NSLocalizedString("_delete_file_", comment: ""), style: .default) { (action:UIAlertAction) in
  518. if let index = self.filesName.firstIndex(of: fileName) {
  519. self.filesName.remove(at: index)
  520. if self.filesName.count == 0 {
  521. self.extensionContext?.completeRequest(returningItems: self.extensionContext?.inputItems, completionHandler: nil)
  522. } else {
  523. self.setCommandView()
  524. }
  525. }
  526. })
  527. alertController.addAction(UIAlertAction(title: NSLocalizedString("_rename_file_", comment: ""), style: .default) { (action:UIAlertAction) in
  528. if let vcRename = UIStoryboard(name: "NCRenameFile", bundle: nil).instantiateInitialViewController() as? NCRenameFile {
  529. vcRename.delegate = self
  530. vcRename.fileName = fileName
  531. vcRename.imagePreview = (sender as! NCShareExtensionButtonWithIndexPath).image
  532. let popup = NCPopupViewController(contentController: vcRename, popupWidth: vcRename.width, popupHeight: vcRename.height)
  533. self.present(popup, animated: true)
  534. }
  535. })
  536. alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel) { (action:UIAlertAction) in })
  537. self.present(alertController, animated: true, completion:nil)
  538. }
  539. })
  540. return cell
  541. }
  542. }
  543. // MARK: - NC API & Algorithm
  544. extension NCShareExtension {
  545. @objc func reloadDatasource(withLoadFolder: Bool) {
  546. layoutForView = NCUtility.shared.getLayoutForView(key: keyLayout, serverUrl: serverUrl)
  547. let metadatasSource = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND directory == true", activeAccount.account, serverUrl))
  548. self.dataSource = NCDataSource.init(metadatasSource: metadatasSource, sort: layoutForView?.sort, ascending: layoutForView?.ascending, directoryOnTop: layoutForView?.directoryOnTop, favoriteOnTop: true, filterLivePhoto: true)
  549. if withLoadFolder {
  550. loadFolder()
  551. } else {
  552. self.refreshControl.endRefreshing()
  553. }
  554. collectionView.reloadData()
  555. }
  556. func createFolder(with fileName: String) {
  557. NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { (errorCode, errorDescription) in
  558. DispatchQueue.main.async {
  559. if errorCode == 0 {
  560. self.serverUrl = self.serverUrl + "/" + fileName
  561. self.reloadDatasource(withLoadFolder: true)
  562. self.setNavigationBar(navigationTitle: fileName)
  563. } else {
  564. let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert)
  565. alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
  566. self.present(alertController, animated: true)
  567. }
  568. }
  569. }
  570. }
  571. func loadFolder() {
  572. networkInProgress = true
  573. collectionView.reloadData()
  574. NCNetworking.shared.readFolder(serverUrl: serverUrl, account: activeAccount.account) { (_, metadataFolder, _, _, _, _, errorCode, errorDescription) in
  575. DispatchQueue.main.async {
  576. if errorCode != 0 {
  577. let alertController = UIAlertController(title: NSLocalizedString("_error_", comment: ""), message: errorDescription, preferredStyle: .alert)
  578. alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
  579. self.present(alertController, animated: true)
  580. }
  581. self.networkInProgress = false
  582. self.metadataFolder = metadataFolder
  583. self.reloadDatasource(withLoadFolder: false)
  584. }
  585. }
  586. }
  587. func getFilesExtensionContext(completion: @escaping (_ filesName: [String])->()) {
  588. var itemsProvider: [NSItemProvider] = []
  589. var filesName: [String] = []
  590. var conuter = 0
  591. let dateFormatter = DateFormatter()
  592. // ----------------------------------------------------------------------------------------
  593. // Image
  594. func getItem(image: UIImage, fileNameOriginal: String?) {
  595. var fileName: String = ""
  596. if let pngImageData = image.pngData() {
  597. if fileNameOriginal != nil {
  598. fileName = fileNameOriginal!
  599. } else {
  600. fileName = "\(dateFormatter.string(from: Date()))\(conuter).png"
  601. }
  602. let filenamePath = NSTemporaryDirectory() + fileName
  603. if (try? pngImageData.write(to: URL(fileURLWithPath: filenamePath), options: [.atomic])) != nil {
  604. filesName.append(fileName)
  605. }
  606. }
  607. }
  608. // URL
  609. func getItem(url: NSURL, fileNameOriginal: String?) {
  610. guard let path = url.path else { return }
  611. var fileName: String = ""
  612. if fileNameOriginal != nil {
  613. fileName = fileNameOriginal!
  614. } else {
  615. if let ext = url.pathExtension {
  616. fileName = "\(dateFormatter.string(from: Date()))\(conuter)." + ext
  617. }
  618. }
  619. let filenamePath = NSTemporaryDirectory() + fileName
  620. do {
  621. try FileManager.default.removeItem(atPath: filenamePath)
  622. }
  623. catch { }
  624. do {
  625. try FileManager.default.copyItem(atPath: path, toPath:filenamePath)
  626. do {
  627. let attr : NSDictionary? = try FileManager.default.attributesOfItem(atPath: filenamePath) as NSDictionary?
  628. if let _attr = attr {
  629. if _attr.fileSize() > 0 {
  630. filesName.append(fileName)
  631. }
  632. }
  633. } catch { }
  634. } catch { }
  635. }
  636. // Data
  637. func getItem(data: Data, fileNameOriginal: String?, description: String) {
  638. var fileName: String = ""
  639. if data.count > 0 {
  640. if fileNameOriginal != nil {
  641. fileName = fileNameOriginal!
  642. } else {
  643. let fullNameArr = description.components(separatedBy: "\"")
  644. let fileExtArr = fullNameArr[1].components(separatedBy: ".")
  645. let pathExtention = (fileExtArr[fileExtArr.count-1]).uppercased()
  646. fileName = "\(dateFormatter.string(from: Date()))\(conuter).\(pathExtention)"
  647. }
  648. let filenamePath = NSTemporaryDirectory() + fileName
  649. FileManager.default.createFile(atPath: filenamePath, contents:data, attributes:nil)
  650. filesName.append(fileName)
  651. }
  652. }
  653. // String
  654. func getItem(string: NSString, fileNameOriginal: String?) {
  655. var fileName: String = ""
  656. if string.length > 0 {
  657. fileName = "\(dateFormatter.string(from: Date()))\(conuter).txt"
  658. let filenamePath = NSTemporaryDirectory() + "\(dateFormatter.string(from: Date()))\(conuter).txt"
  659. FileManager.default.createFile(atPath: filenamePath, contents:string.data(using: String.Encoding.utf8.rawValue), attributes:nil)
  660. filesName.append(fileName)
  661. }
  662. }
  663. // ----------------------------------------------------------------------------------------
  664. guard let inputItems : [NSExtensionItem] = extensionContext?.inputItems as? [NSExtensionItem] else {
  665. return completion(filesName)
  666. }
  667. for item : NSExtensionItem in inputItems {
  668. if let attachments = item.attachments {
  669. if attachments.isEmpty { continue }
  670. for (_, itemProvider) in (attachments.enumerated()) {
  671. if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeItem as String) || itemProvider.hasItemConformingToTypeIdentifier("public.url") {
  672. itemsProvider.append(itemProvider)
  673. }
  674. }
  675. }
  676. }
  677. CCUtility.emptyTemporaryDirectory()
  678. dateFormatter.dateFormat = "yyyy-MM-dd HH-mm-ss-"
  679. for itemProvider in itemsProvider {
  680. var typeIdentifier = ""
  681. if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeItem as String) { typeIdentifier = kUTTypeItem as String }
  682. if itemProvider.hasItemConformingToTypeIdentifier("public.url") { typeIdentifier = "public.url" }
  683. itemProvider.loadItem(forTypeIdentifier: typeIdentifier, options: nil, completionHandler: {(item, error) -> Void in
  684. if error == nil {
  685. var fileNameOriginal: String?
  686. if let url = item as? NSURL {
  687. if FileManager.default.fileExists(atPath: url.path ?? "") {
  688. fileNameOriginal = url.lastPathComponent!
  689. } else if url.scheme?.lowercased().contains("http") == true {
  690. fileNameOriginal = "\(dateFormatter.string(from: Date()))\(conuter).html"
  691. } else {
  692. fileNameOriginal = "\(dateFormatter.string(from: Date()))\(conuter)"
  693. }
  694. }
  695. if let image = item as? UIImage {
  696. getItem(image: image, fileNameOriginal: fileNameOriginal)
  697. }
  698. if let url = item as? URL {
  699. getItem(url: url as NSURL, fileNameOriginal: fileNameOriginal)
  700. }
  701. if let data = item as? Data {
  702. getItem(data: data, fileNameOriginal: fileNameOriginal, description: itemProvider.description)
  703. }
  704. if let string = item as? NSString {
  705. getItem(string: string, fileNameOriginal: fileNameOriginal)
  706. }
  707. }
  708. conuter += 1
  709. if conuter == itemsProvider.count {
  710. completion(filesName)
  711. }
  712. })
  713. }
  714. }
  715. }
  716. /*
  717. let task = URLSession.shared.downloadTask(with: urlitem) { localURL, urlResponse, error in
  718. if let localURL = localURL {
  719. if fileNameOriginal != nil {
  720. fileName = fileNameOriginal!
  721. } else {
  722. let ext = url.pathExtension
  723. fileName = "\(dateFormatter.string(from: Date()))\(conuter)." + ext
  724. }
  725. let filenamePath = NSTemporaryDirectory() + fileName
  726. do {
  727. try FileManager.default.removeItem(atPath: filenamePath)
  728. }
  729. catch { }
  730. do {
  731. try FileManager.default.copyItem(atPath: localURL.path, toPath:filenamePath)
  732. do {
  733. let attr : NSDictionary? = try FileManager.default.attributesOfItem(atPath: filenamePath) as NSDictionary?
  734. if let _attr = attr {
  735. if _attr.fileSize() > 0 {
  736. filesName.append(fileName)
  737. }
  738. }
  739. } catch let error {
  740. outError = error
  741. }
  742. } catch let error {
  743. outError = error
  744. }
  745. }
  746. if index + 1 == attachments.count {
  747. completion(filesName, outError)
  748. }
  749. }
  750. task.resume()
  751. */
  752. class NCShareExtensionButtonWithIndexPath: UIButton {
  753. var indexPath:IndexPath?
  754. var fileName: String?
  755. var image: UIImage?
  756. }