NCCollectionViewCommonSelectTabBar.swift 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. //
  2. // NCCollectionViewCommonSelectionTabBar.swift
  3. // Nextcloud
  4. //
  5. // Created by Milen on 01.02.24.
  6. // Copyright © 2024 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 Foundation
  24. import UIKit
  25. import SwiftUI
  26. protocol NCCollectionViewCommonSelectTabBarDelegate: AnyObject {
  27. func selectAll()
  28. func delete()
  29. func move()
  30. func share()
  31. func saveAsAvailableOffline(isAnyOffline: Bool)
  32. func lock(isAnyLocked: Bool)
  33. }
  34. class NCCollectionViewCommonSelectTabBar: ObservableObject {
  35. var controller: NCMainTabBarController?
  36. var hostingController: UIViewController?
  37. open weak var delegate: NCCollectionViewCommonSelectTabBarDelegate?
  38. @Published var isAnyOffline = false
  39. @Published var canSetAsOffline = false
  40. @Published var isAnyDirectory = false
  41. @Published var isAllDirectory = false
  42. @Published var isAnyLocked = false
  43. @Published var canUnlock = true
  44. @Published var enableLock = false
  45. @Published var isSelectedEmpty = true
  46. init(controller: NCMainTabBarController? = nil, delegate: NCCollectionViewCommonSelectTabBarDelegate? = nil) {
  47. let rootView = NCCollectionViewCommonSelectTabBarView(tabBarSelect: self)
  48. hostingController = UIHostingController(rootView: rootView)
  49. self.controller = controller
  50. self.delegate = delegate
  51. guard let controller, let hostingController else { return }
  52. controller.view.addSubview(hostingController.view)
  53. hostingController.view.frame = controller.tabBar.frame
  54. hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
  55. hostingController.view.backgroundColor = .clear
  56. hostingController.view.isHidden = true
  57. }
  58. func show() {
  59. guard let controller, let hostingController else { return }
  60. controller.tabBar.isHidden = true
  61. if hostingController.view.isHidden {
  62. hostingController.view.isHidden = false
  63. hostingController.view.transform = .init(translationX: 0, y: hostingController.view.frame.height)
  64. UIView.animate(withDuration: 0.2) {
  65. hostingController.view.transform = .init(translationX: 0, y: 0)
  66. }
  67. }
  68. }
  69. func hide() {
  70. guard let controller, let hostingController else { return }
  71. hostingController.view.isHidden = true
  72. controller.tabBar.isHidden = false
  73. }
  74. func isHidden() -> Bool {
  75. guard let hostingController else { return false }
  76. return hostingController.view.isHidden
  77. }
  78. func update(fileSelect: [String], metadatas: [tableMetadata]? = nil, userId: String? = nil) {
  79. if let metadatas {
  80. isAnyOffline = false
  81. canSetAsOffline = true
  82. isAnyDirectory = false
  83. isAllDirectory = true
  84. isAnyLocked = false
  85. canUnlock = true
  86. for metadata in metadatas {
  87. if metadata.directory {
  88. isAnyDirectory = true
  89. } else {
  90. isAllDirectory = false
  91. }
  92. if !metadata.canSetAsAvailableOffline {
  93. canSetAsOffline = false
  94. }
  95. if metadata.lock {
  96. isAnyLocked = true
  97. if metadata.lockOwner != userId {
  98. canUnlock = false
  99. }
  100. }
  101. guard !isAnyOffline else { continue }
  102. if metadata.directory,
  103. let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@",
  104. metadata.account,
  105. metadata.serverUrl + "/" + metadata.fileName)) {
  106. isAnyOffline = directory.offline
  107. } else if let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) {
  108. isAnyOffline = localFile.offline
  109. } // else: file is not offline, continue
  110. }
  111. enableLock = !isAnyDirectory && canUnlock && !NCCapabilities.shared.getCapabilities(account: controller?.account).capabilityFilesLockVersion.isEmpty
  112. }
  113. isSelectedEmpty = fileSelect.isEmpty
  114. }
  115. }
  116. struct NCCollectionViewCommonSelectTabBarView: View {
  117. @ObservedObject var tabBarSelect: NCCollectionViewCommonSelectTabBar
  118. @Environment(\.verticalSizeClass) var sizeClass
  119. var body: some View {
  120. VStack {
  121. Spacer().frame(height: sizeClass == .compact ? 5 : 10)
  122. HStack {
  123. Button {
  124. tabBarSelect.delegate?.share()
  125. } label: {
  126. Image(systemName: "square.and.arrow.up")
  127. .font(Font.system(.body).weight(.light))
  128. .imageScale(sizeClass == .compact ? .medium : .large)
  129. }
  130. .tint(Color(NCBrandColor.shared.iconImageColor))
  131. .frame(maxWidth: .infinity)
  132. .disabled(tabBarSelect.isSelectedEmpty || tabBarSelect.isAllDirectory)
  133. Button {
  134. tabBarSelect.delegate?.move()
  135. } label: {
  136. Image(systemName: "rectangle.portrait.and.arrow.right")
  137. .font(Font.system(.body).weight(.light))
  138. .imageScale(sizeClass == .compact ? .medium : .large)
  139. }
  140. .tint(Color(NCBrandColor.shared.iconImageColor))
  141. .frame(maxWidth: .infinity)
  142. .disabled(tabBarSelect.isSelectedEmpty)
  143. Button {
  144. tabBarSelect.delegate?.delete()
  145. } label: {
  146. Image(systemName: "trash")
  147. .font(Font.system(.body).weight(.light))
  148. .imageScale(sizeClass == .compact ? .medium : .large)
  149. }
  150. .tint(.red)
  151. .frame(maxWidth: .infinity)
  152. .disabled(tabBarSelect.isSelectedEmpty)
  153. Menu {
  154. Button(action: {
  155. tabBarSelect.delegate?.saveAsAvailableOffline(isAnyOffline: tabBarSelect.isAnyOffline)
  156. }, label: {
  157. Label(NSLocalizedString(tabBarSelect.isAnyOffline ? "_remove_available_offline_" : "_set_available_offline_", comment: ""), systemImage: tabBarSelect.isAnyOffline ? "icloud.slash" : "icloud.and.arrow.down")
  158. if !tabBarSelect.canSetAsOffline && !tabBarSelect.isAnyOffline {
  159. Text(NSLocalizedString("_e2ee_set_as_offline_", comment: ""))
  160. }
  161. })
  162. .disabled(!tabBarSelect.isAnyOffline && (!tabBarSelect.canSetAsOffline || tabBarSelect.isSelectedEmpty))
  163. Button(action: {
  164. tabBarSelect.delegate?.lock(isAnyLocked: tabBarSelect.isAnyLocked)
  165. }, label: {
  166. Label(NSLocalizedString(tabBarSelect.isAnyLocked ? "_unlock_" : "_lock_", comment: ""), systemImage: tabBarSelect.isAnyLocked ? "lock.open" : "lock")
  167. if !tabBarSelect.enableLock {
  168. Text(NSLocalizedString("_lock_no_permissions_selected_", comment: ""))
  169. }
  170. })
  171. .disabled(!tabBarSelect.enableLock || tabBarSelect.isSelectedEmpty)
  172. Button(action: {
  173. tabBarSelect.delegate?.selectAll()
  174. }, label: {
  175. Label(NSLocalizedString("_select_all_", comment: ""), systemImage: "checkmark")
  176. })
  177. } label: {
  178. Image(systemName: "ellipsis.circle")
  179. .font(Font.system(.body).weight(.light))
  180. .imageScale(sizeClass == .compact ? .medium : .large)
  181. }
  182. .tint(Color(NCBrandColor.shared.iconImageColor))
  183. .frame(maxWidth: .infinity)
  184. }
  185. }
  186. .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
  187. .background(.thinMaterial)
  188. .overlay(Rectangle().frame(width: nil, height: 0.5, alignment: .top).foregroundColor(Color(UIColor.separator)), alignment: .top)
  189. }
  190. }
  191. #Preview {
  192. NCCollectionViewCommonSelectTabBarView(tabBarSelect: NCCollectionViewCommonSelectTabBar())
  193. }