2
0

VMToolbarModifier.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. //
  2. // Copyright © 2020 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. import SwiftUI
  17. // Lots of dirty hacks to work around SwiftUI bugs introduced in Beta 2
  18. struct VMToolbarModifier: ViewModifier {
  19. @ObservedObject var vm: VMData
  20. let bottom: Bool
  21. @State private var showSharePopup = false
  22. @State private var confirmAction: ConfirmAction?
  23. @EnvironmentObject private var data: UTMData
  24. @State private var shareItem: VMShareItemModifier.ShareItem?
  25. #if os(macOS)
  26. let buttonPlacement: ToolbarItemPlacement = .automatic
  27. let padding: CGFloat = 0
  28. #else
  29. var buttonPlacement: ToolbarItemPlacement {
  30. if bottom {
  31. return .bottomBar
  32. } else {
  33. return .navigationBarTrailing
  34. }
  35. }
  36. var padding: CGFloat {
  37. if bottom {
  38. return 0
  39. } else {
  40. return 10
  41. }
  42. }
  43. #endif
  44. func body(content: Content) -> some View {
  45. content.toolbar {
  46. #if os(visionOS)
  47. UTMPreferenceButtonToolbarContent()
  48. #endif
  49. ToolbarItemGroup(placement: buttonPlacement) {
  50. #if !WITH_REMOTE // FIXME: implement remote feature
  51. if vm.isShortcut {
  52. DestructiveButton {
  53. confirmAction = .confirmDeleteShortcut
  54. } label: {
  55. Label("Remove", systemImage: "trash")
  56. .labelStyle(.iconOnly)
  57. }.help("Remove selected shortcut")
  58. .disabled(!vm.isModifyAllowed)
  59. .padding(.leading, padding)
  60. } else {
  61. DestructiveButton {
  62. confirmAction = .confirmDeleteVM
  63. } label: {
  64. Label("Delete", systemImage: "trash")
  65. .labelStyle(.iconOnly)
  66. }.help("Delete selected VM")
  67. .disabled(!vm.isModifyAllowed)
  68. .padding(.leading, padding)
  69. }
  70. #if !os(macOS)
  71. if bottom {
  72. Spacer()
  73. }
  74. #endif
  75. Button {
  76. confirmAction = .confirmCloneVM
  77. } label: {
  78. Label("Clone", systemImage: "doc.on.doc")
  79. .labelStyle(.iconOnly)
  80. }.help("Clone selected VM")
  81. .padding(.leading, padding)
  82. #if !os(macOS)
  83. if bottom {
  84. Spacer()
  85. }
  86. #endif
  87. #if os(macOS)
  88. if !vm.isShortcut {
  89. Button {
  90. confirmAction = .confirmMoveVM
  91. } label: {
  92. Label("Move", systemImage: "arrow.down.doc")
  93. .labelStyle(.iconOnly)
  94. }.help("Move selected VM")
  95. .disabled(!vm.isModifyAllowed)
  96. .padding(.leading, padding)
  97. }
  98. #endif
  99. Button {
  100. shareItem = .utmCopy(vm)
  101. showSharePopup.toggle()
  102. } label: {
  103. Label("Share", systemImage: "square.and.arrow.up")
  104. .labelStyle(.iconOnly)
  105. }.help("Share selected VM")
  106. .padding(.leading, padding)
  107. #if !os(macOS)
  108. if bottom {
  109. Spacer()
  110. }
  111. #endif
  112. #endif
  113. if vm.hasSuspendState || !vm.isStopped {
  114. Button {
  115. confirmAction = .confirmStopVM
  116. } label: {
  117. Label("Stop", systemImage: "stop")
  118. .labelStyle(.iconOnly)
  119. }.help("Stop selected VM")
  120. .padding(.leading, padding)
  121. } else {
  122. Button {
  123. data.run(vm: data.selectedVM!)
  124. } label: {
  125. Label("Run", systemImage: "play")
  126. .labelStyle(.iconOnly)
  127. }.help("Run selected VM")
  128. .padding(.leading, padding)
  129. }
  130. #if !WITH_REMOTE // FIXME: implement remote feature
  131. #if !os(macOS)
  132. if bottom {
  133. Spacer()
  134. }
  135. #endif
  136. Button {
  137. data.close(vm: vm) // close window
  138. data.edit(vm: vm)
  139. } label: {
  140. Label("Edit", systemImage: "slider.horizontal.3")
  141. .labelStyle(.iconOnly)
  142. }.help("Edit selected VM")
  143. .disabled(vm.hasSuspendState || !vm.isModifyAllowed)
  144. .padding(.leading, padding)
  145. #endif
  146. }
  147. }
  148. .modifier(VMShareItemModifier(isPresented: $showSharePopup, shareItem: shareItem))
  149. .modifier(VMConfirmActionModifier(vm: vm, confirmAction: $confirmAction) {
  150. if confirmAction == .confirmMoveVM {
  151. shareItem = .utmMove(vm)
  152. showSharePopup.toggle()
  153. }
  154. })
  155. }
  156. }
  157. #if os(visionOS)
  158. struct UTMPreferenceButtonToolbarContent: ToolbarContent {
  159. var body: some ToolbarContent {
  160. ToolbarItem(placement: .topBarLeading) {
  161. Button {
  162. UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
  163. } label: {
  164. Label("Preferences", systemImage: "gear")
  165. .labelStyle(.iconOnly)
  166. }.help("Show UTM preferences")
  167. }
  168. }
  169. }
  170. #endif