EditActions.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*****************************************************************************
  2. * EditActions.swift
  3. *
  4. * Copyright © 2019 VLC authors and VideoLAN
  5. *
  6. * Authors: Edgar Fouillet <vlc # edgar.fouillet.eu>
  7. *
  8. * Refer to the COPYING file of the official project for license.
  9. *****************************************************************************/
  10. enum completionState {
  11. case inProgress
  12. case success
  13. case fail
  14. }
  15. class EditActions {
  16. private let rootViewController: UIViewController
  17. private let model: MediaLibraryBaseModel
  18. private let mediaLibraryService: MediaLibraryService
  19. private var completion: ((completionState) -> Void)?
  20. var objects = [VLCMLObject]()
  21. private lazy var addToPlaylistViewController: AddToPlaylistViewController = {
  22. var addToPlaylistViewController = AddToPlaylistViewController(playlists: mediaLibraryService.playlists())
  23. addToPlaylistViewController.delegate = self
  24. return addToPlaylistViewController
  25. }()
  26. init(model: MediaLibraryBaseModel, mediaLibraryService: MediaLibraryService) {
  27. self.rootViewController = UIApplication.shared.keyWindow!.rootViewController!
  28. self.model = model
  29. self.mediaLibraryService = mediaLibraryService
  30. }
  31. private func addToNewPlaylist() {
  32. let alertInfo = TextFieldAlertInfo(alertTitle: NSLocalizedString("PLAYLISTS", comment: ""),
  33. placeHolder: NSLocalizedString("PLAYLIST_PLACEHOLDER",
  34. comment: ""))
  35. presentTextFieldAlert(with: alertInfo) {
  36. [unowned self] text -> Void in
  37. guard text != "" else {
  38. DispatchQueue.main.async {
  39. VLCAlertViewController.alertViewManager(title: NSLocalizedString("ERROR_EMPTY_NAME",
  40. comment: ""),
  41. viewController: self.rootViewController)
  42. }
  43. return
  44. }
  45. self.createPlaylist(text)
  46. }
  47. }
  48. func addToPlaylist(_ completion: ((completionState) -> Void)? = nil) {
  49. self.completion = completion
  50. if !mediaLibraryService.playlists().isEmpty {
  51. addToPlaylistViewController.playlists = mediaLibraryService.playlists()
  52. let navigationController = UINavigationController(rootViewController: addToPlaylistViewController)
  53. rootViewController.present(navigationController, animated: true, completion: nil)
  54. } else {
  55. addToNewPlaylist()
  56. }
  57. }
  58. func rename(_ completion: ((completionState) -> Void)? = nil) {
  59. self.completion = completion
  60. if !objects.isEmpty {
  61. let mlObject = objects.first
  62. var mlObjectName = ""
  63. if let media = mlObject as? VLCMLMedia {
  64. mlObjectName = media.title
  65. } else if let playlist = mlObject as? VLCMLPlaylist {
  66. mlObjectName = playlist.name
  67. } else {
  68. assertionFailure("EditActions: Rename called with wrong model.")
  69. }
  70. // Not using VLCAlertViewController to have more customization in text fields
  71. let alertInfo = TextFieldAlertInfo(alertTitle: String(format: NSLocalizedString("RENAME_MEDIA_TO", comment: ""), mlObjectName),
  72. textfieldText: mlObjectName,
  73. confirmActionTitle: NSLocalizedString("BUTTON_RENAME", comment: ""))
  74. presentTextFieldAlert(with: alertInfo, completionHandler: {
  75. [unowned self] text -> Void in
  76. guard text != "" else {
  77. VLCAlertViewController.alertViewManager(title: NSLocalizedString("ERROR_RENAME_FAILED", comment: ""),
  78. errorMessage: NSLocalizedString("ERROR_EMPTY_NAME", comment: ""),
  79. viewController: self.rootViewController)
  80. self.completion?(.fail)
  81. return
  82. }
  83. if let media = mlObject as? VLCMLMedia {
  84. media.updateTitle(text)
  85. } else if let playlist = mlObject as? VLCMLPlaylist {
  86. playlist.updateName(text)
  87. }
  88. self.objects.removeFirst()
  89. self.completion?(.inProgress)
  90. self.rename(completion)
  91. })
  92. } else {
  93. self.completion?(.success)
  94. }
  95. }
  96. private func URLs() -> [URL] {
  97. var fileURLs = [URL]()
  98. for object in objects {
  99. if let media = object as? VLCMLMedia {
  100. if let file = media.mainFile() {
  101. fileURLs.append(file.mrl)
  102. }
  103. } else if let mediaCollection = object as? MediaCollectionModel {
  104. if let files = mediaCollection.files() {
  105. for media in files {
  106. if let file = media.mainFile() {
  107. fileURLs.append(file.mrl)
  108. }
  109. }
  110. }
  111. }
  112. }
  113. return fileURLs
  114. }
  115. func delete(_ completion: ((completionState) -> Void)? = nil) {
  116. self.completion = completion
  117. var message = NSLocalizedString("DELETE_MESSAGE", comment: "")
  118. if model is PlaylistModel {
  119. message = NSLocalizedString("DELETE_MESSAGE_PLAYLIST", comment: "")
  120. } else if (model as? CollectionModel)?.mediaCollection is VLCMLPlaylist {
  121. message = NSLocalizedString("DELETE_MESSAGE_PLAYLIST_CONTENT", comment: "")
  122. }
  123. let cancelButton = VLCAlertButton(title: NSLocalizedString("BUTTON_CANCEL", comment: ""),
  124. style: .cancel)
  125. let deleteButton = VLCAlertButton(title: NSLocalizedString("BUTTON_DELETE", comment: ""),
  126. style: .destructive,
  127. action: {
  128. [unowned self] action in
  129. self.model.delete(self.objects)
  130. self.objects.removeAll()
  131. self.completion?(.success)
  132. })
  133. VLCAlertViewController.alertViewManager(title: NSLocalizedString("DELETE_TITLE", comment: ""),
  134. errorMessage: message,
  135. viewController: rootViewController,
  136. buttonsAction: [cancelButton,
  137. deleteButton])
  138. }
  139. func share(_ completion: ((completionState) -> Void)? = nil) {
  140. self.completion = completion
  141. UIApplication.shared.beginIgnoringInteractionEvents()
  142. guard let controller = VLCActivityViewControllerVendor.activityViewController(forFiles: URLs(),
  143. presenting: nil,
  144. presenting: rootViewController,
  145. completionHandler: {
  146. [unowned self] _ in
  147. self.completion?(.success)
  148. }
  149. ) else {
  150. UIApplication.shared.endIgnoringInteractionEvents()
  151. self.completion?(.fail)
  152. return
  153. }
  154. controller.popoverPresentationController?.sourceView = rootViewController.view
  155. rootViewController.present(controller, animated: true) {
  156. UIApplication.shared.endIgnoringInteractionEvents()
  157. }
  158. }
  159. }
  160. private extension EditActions {
  161. private struct TextFieldAlertInfo {
  162. var alertTitle: String
  163. var alertDescription: String
  164. var placeHolder: String
  165. var textfieldText: String
  166. var confirmActionTitle: String
  167. init(alertTitle: String = "",
  168. alertDescription: String = "",
  169. placeHolder: String = "",
  170. textfieldText: String = "",
  171. confirmActionTitle: String = NSLocalizedString("BUTTON_DONE", comment: "")) {
  172. self.alertTitle = alertTitle
  173. self.alertDescription = alertDescription
  174. self.placeHolder = placeHolder
  175. self.textfieldText = textfieldText
  176. self.confirmActionTitle = confirmActionTitle
  177. }
  178. }
  179. private func presentTextFieldAlert(with info: TextFieldAlertInfo,
  180. completionHandler: @escaping (String) -> Void) {
  181. let alertController = UIAlertController(title: info.alertTitle,
  182. message: info.alertDescription,
  183. preferredStyle: .alert)
  184. alertController.addTextField(configurationHandler: {
  185. textField in
  186. textField.text = info.textfieldText
  187. textField.placeholder = info.placeHolder
  188. })
  189. let cancelButton = UIAlertAction(title: NSLocalizedString("BUTTON_CANCEL", comment: ""),
  190. style: .cancel)
  191. let confirmAction = UIAlertAction(title: info.confirmActionTitle, style: .default) {
  192. [weak alertController] _ in
  193. guard let alertController = alertController,
  194. let textField = alertController.textFields?.first else { return }
  195. completionHandler(textField.text ?? "")
  196. }
  197. alertController.addAction(cancelButton)
  198. alertController.addAction(confirmAction)
  199. rootViewController.present(alertController, animated: true, completion: nil)
  200. }
  201. private func createPlaylist(_ name: String) {
  202. guard let playlist = mediaLibraryService.createPlaylist(with: name) else {
  203. assertionFailure("EditActions: createPlaylist: Failed to create a playlist.")
  204. DispatchQueue.main.async {
  205. VLCAlertViewController.alertViewManager(title: NSLocalizedString("ERROR_PLAYLIST_CREATION",
  206. comment: ""),
  207. viewController: self.rootViewController)
  208. }
  209. completion?(.fail)
  210. return
  211. }
  212. for media in objects {
  213. if !playlist.appendMedia(withIdentifier: media.identifier()) {
  214. assertionFailure("EditActions: createPlaylist: Failed to add item.")
  215. }
  216. }
  217. completion?(.success)
  218. }
  219. }
  220. // MARK: - AddToPlaylistViewControllerDelegate
  221. extension EditActions: AddToPlaylistViewControllerDelegate {
  222. func addToPlaylistViewController(_ addToPlaylistViewController: AddToPlaylistViewController,
  223. didSelectPlaylist playlist: VLCMLPlaylist) {
  224. for media in objects {
  225. if !playlist.appendMedia(withIdentifier: media.identifier()) {
  226. assertionFailure("EditActions: AddToPlaylistViewControllerDelegate: Failed to add item.")
  227. completion?(.fail)
  228. }
  229. }
  230. addToPlaylistViewController.dismiss(animated: true, completion: nil)
  231. completion?(.success)
  232. }
  233. func addToPlaylistViewController(_ addToPlaylistViewController: AddToPlaylistViewController,
  234. newPlaylistWithName name: String) {
  235. createPlaylist(name)
  236. addToPlaylistViewController.dismiss(animated: true, completion: nil)
  237. }
  238. }