VLCEditController.swift 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*****************************************************************************
  2. * VLCEditController.swift
  3. *
  4. * Copyright © 2018 VLC authors and VideoLAN
  5. * Copyright © 2018 Videolabs
  6. *
  7. * Authors: Soomin Lee <bubu@mikan.io>
  8. *
  9. * Refer to the COPYING file of the official project for license.
  10. *****************************************************************************/
  11. class VLCEditController: NSObject {
  12. private var selectedCellIndexPaths = Set<IndexPath>()
  13. private let collectionView: UICollectionView
  14. private let category: MediaLibraryBaseModel
  15. init(collectionView: UICollectionView, category: MediaLibraryBaseModel) {
  16. self.collectionView = collectionView
  17. self.category = category
  18. super.init()
  19. }
  20. func resetSelections() {
  21. selectedCellIndexPaths.removeAll(keepingCapacity: false)
  22. }
  23. }
  24. // MARK: - Helpers
  25. private extension VLCEditController {
  26. private func resetCell(at indexPath: IndexPath) {
  27. if let cell = collectionView.cellForItem(at: indexPath) as? MediaEditCell {
  28. cell.isChecked = false
  29. }
  30. }
  31. private func resetAllVisibleCell() {
  32. for case let cell as MediaEditCell in collectionView.visibleCells {
  33. cell.isChecked = false
  34. }
  35. }
  36. private struct TextFieldAlertInfo {
  37. var alertTitle: String
  38. var placeHolder: String
  39. var confirmActionTitle: String
  40. init(alertTitle: String = "",
  41. placeHolder: String = "",
  42. confirmActionTitle: String = NSLocalizedString("BUTTON_DONE", comment: "")) {
  43. self.alertTitle = alertTitle
  44. self.placeHolder = placeHolder
  45. self.confirmActionTitle = confirmActionTitle
  46. }
  47. }
  48. private func presentTextFieldAlert(with info: TextFieldAlertInfo,
  49. completionHandler: @escaping (String) -> Void) {
  50. let alertController = UIAlertController(title: info.alertTitle,
  51. message: "",
  52. preferredStyle: .alert)
  53. alertController.addTextField(configurationHandler: {
  54. textField in
  55. textField.placeholder = info.placeHolder
  56. })
  57. let cancelButton = UIAlertAction(title: NSLocalizedString("BUTTON_CANCEL", comment: ""),
  58. style: .default)
  59. let confirmAction = UIAlertAction(title: info.confirmActionTitle, style: .default) {
  60. [weak alertController] _ in
  61. guard let alertController = alertController,
  62. let textField = alertController.textFields?.first else { return }
  63. completionHandler(textField.text ?? "")
  64. }
  65. alertController.addAction(cancelButton)
  66. alertController.addAction(confirmAction)
  67. UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
  68. }
  69. }
  70. // MARK: - VLCEditToolbarDelegate
  71. extension VLCEditController: VLCEditToolbarDelegate {
  72. func createPlaylist() {
  73. if let model = category as? PlaylistModel {
  74. let alertInfo = TextFieldAlertInfo(alertTitle: NSLocalizedString("PLAYLISTS", comment: ""),
  75. placeHolder: "NEW_PLAYLIST")
  76. presentTextFieldAlert(with: alertInfo, completionHandler: {
  77. text -> Void in
  78. model.create(name: text)
  79. })
  80. } else if let model = category as? VideoModel {
  81. let alertInfo = TextFieldAlertInfo(alertTitle: NSLocalizedString("PLAYLISTS", comment: ""),
  82. placeHolder: "NEW_PLAYLIST")
  83. presentTextFieldAlert(with: alertInfo, completionHandler: {
  84. [selectedCellIndexPaths, category] text -> Void in
  85. let playlist = model.medialibrary.createPlaylist(with: text)
  86. for indexPath in selectedCellIndexPaths {
  87. if let media = category.anyfiles[indexPath.row] as? VLCMLMedia {
  88. playlist.appendMedia(withIdentifier: media.identifier())
  89. }
  90. }
  91. })
  92. }
  93. }
  94. func delete() {
  95. var objectsToDelete = [VLCMLObject]()
  96. for indexPath in selectedCellIndexPaths {
  97. objectsToDelete.append(category.anyfiles[indexPath.row])
  98. }
  99. let cancelButton = VLCAlertButton(title: NSLocalizedString("BUTTON_CANCEL", comment: ""))
  100. let deleteButton = VLCAlertButton(title: NSLocalizedString("BUTTON_DELETE", comment: ""),
  101. style: .destructive,
  102. action: {
  103. [weak self] action in
  104. self?.category.delete(objectsToDelete)
  105. self?.selectedCellIndexPaths.removeAll()
  106. self?.resetAllVisibleCell()
  107. })
  108. VLCAlertViewController.alertViewManager(title: NSLocalizedString("DELETE_TITLE", comment: ""),
  109. errorMessage: NSLocalizedString("DELETE_MESSAGE", comment: ""),
  110. viewController: (UIApplication.shared.keyWindow?.rootViewController)!,
  111. buttonsAction: [cancelButton,
  112. deleteButton])
  113. }
  114. func rename() {
  115. // FIXME: Multiple renaming of files(multiple alert can get unfriendly if too many files)
  116. for indexPath in selectedCellIndexPaths {
  117. if let media = category.anyfiles[indexPath.row] as? VLCMLMedia {
  118. // Not using VLCAlertViewController to have more customization in text fields
  119. let alertInfo = TextFieldAlertInfo(alertTitle: String(format: NSLocalizedString("RENAME_MEDIA_TO", comment: ""), media.title),
  120. placeHolder: "NEW_NAME",
  121. confirmActionTitle: NSLocalizedString("BUTTON_RENAME", comment: ""))
  122. presentTextFieldAlert(with: alertInfo, completionHandler: {
  123. [weak self] text -> Void in
  124. guard text != "" else {
  125. VLCAlertViewController.alertViewManager(title: NSLocalizedString("ERROR_RENAME_FAILED", comment: ""),
  126. errorMessage: NSLocalizedString("ERROR_EMPTY_NAME", comment: ""),
  127. viewController: (UIApplication.shared.keyWindow?.rootViewController)!)
  128. return
  129. }
  130. media.updateTitle(text)
  131. self?.resetCell(at: indexPath)
  132. })
  133. }
  134. }
  135. }
  136. }
  137. // MARK: - UICollectionViewDataSource
  138. extension VLCEditController: UICollectionViewDataSource {
  139. func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  140. return category.anyfiles.count
  141. }
  142. func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
  143. if let editCell = (category as? EditableMLModel)?.editCellType() {
  144. if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: editCell.defaultReuseIdentifier,
  145. for: indexPath) as? MediaEditCell {
  146. cell.media = category.anyfiles[indexPath.row]
  147. cell.isChecked = selectedCellIndexPaths.contains(indexPath)
  148. return cell
  149. }
  150. }
  151. return UICollectionViewCell()
  152. }
  153. }
  154. // MARK: - UICollectionViewDelegate
  155. extension VLCEditController: UICollectionViewDelegate {
  156. func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
  157. if let cell = collectionView.cellForItem(at: indexPath) as? MediaEditCell {
  158. cell.isChecked = !cell.isChecked
  159. if cell.isChecked {
  160. // cell selected, saving indexPath
  161. selectedCellIndexPaths.insert(indexPath)
  162. } else {
  163. selectedCellIndexPaths.remove(indexPath)
  164. }
  165. }
  166. }
  167. }
  168. // MARK: - UICollectionViewDelegateFlowLayout
  169. extension VLCEditController: UICollectionViewDelegateFlowLayout {
  170. func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
  171. let contentInset = collectionView.contentInset
  172. // FIXME: 5 should be cell padding, but not usable maybe static?
  173. let insetToRemove = contentInset.left + contentInset.right + (5 * 2)
  174. return CGSize(width: collectionView.frame.width - insetToRemove, height: MediaEditCell.height)
  175. }
  176. }