189 lines
5.9 KiB
Swift
189 lines
5.9 KiB
Swift
//
|
|
// Copyright © 2022 osy. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct VMNavigationListView: View {
|
|
@EnvironmentObject private var data: UTMData
|
|
|
|
var body: some View {
|
|
if #available(iOS 16, macOS 13, *) {
|
|
NavigationSplitView {
|
|
List(selection: $data.selectedVM) {
|
|
listBody
|
|
}.modifier(VMListModifier())
|
|
} detail: {
|
|
if let vm = data.selectedVM {
|
|
VMDetailsView(vm: vm)
|
|
} else {
|
|
VMPlaceholderView()
|
|
#if os(visionOS)
|
|
.toolbar {
|
|
UTMPreferenceButtonToolbarContent()
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
NavigationView {
|
|
List {
|
|
listBody
|
|
}.modifier(VMListModifier())
|
|
VMPlaceholderView()
|
|
}
|
|
}
|
|
}
|
|
|
|
@ViewBuilder private var listBody: some View {
|
|
ForEach(data.virtualMachines) { vm in
|
|
if !vm.isLoaded {
|
|
UTMUnavailableVMView(vm: vm)
|
|
} else {
|
|
if #available(iOS 16, macOS 13, visionOS 1, *) {
|
|
VMCardView(vm: vm)
|
|
.modifier(VMContextMenuModifier(vm: vm))
|
|
.tag(vm)
|
|
} else {
|
|
NavigationLink(
|
|
destination: VMDetailsView(vm: vm),
|
|
tag: vm,
|
|
selection: $data.selectedVM,
|
|
label: { VMCardView(vm: vm) })
|
|
.modifier(VMContextMenuModifier(vm: vm))
|
|
}
|
|
}
|
|
}.onMove(perform: move)
|
|
#if !WITH_REMOTE // FIXME: implement remote feature
|
|
.onDelete(perform: delete)
|
|
#endif
|
|
|
|
if data.pendingVMs.count > 0 {
|
|
Section(header: Text("Pending")) {
|
|
ForEach(data.pendingVMs, id: \.name) { vm in
|
|
UTMPendingVMView(vm: vm)
|
|
}.onDelete(perform: cancel)
|
|
}.transition(.opacity)
|
|
}
|
|
}
|
|
|
|
private func move(fromOffsets: IndexSet, toOffset: Int) {
|
|
data.listMove(fromOffsets: fromOffsets, toOffset: toOffset)
|
|
}
|
|
|
|
private func delete(indexSet: IndexSet) {
|
|
let selected = data.virtualMachines[indexSet]
|
|
for vm in selected {
|
|
data.busyWorkAsync {
|
|
try await data.delete(vm: vm)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func cancel(indexSet: IndexSet) {
|
|
let selected = data.pendingVMs[indexSet]
|
|
for vm in selected {
|
|
data.cancelDownload(for: vm)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct VMListModifier: ViewModifier {
|
|
@EnvironmentObject private var data: UTMData
|
|
@State private var settingsPresented = false
|
|
@State private var sheetPresented = false
|
|
|
|
func body(content: Content) -> some View {
|
|
content
|
|
#if os(macOS)
|
|
.frame(minWidth: 250, idealWidth: 350)
|
|
#endif
|
|
.listStyle(.sidebar)
|
|
.navigationTitle(productName)
|
|
#if os(macOS)
|
|
.navigationSubtitle(data.selectedVM?.detailsTitleLabel ?? "")
|
|
#endif
|
|
.toolbar {
|
|
#if os(macOS)
|
|
ToolbarItem(placement: .navigation) {
|
|
newButton
|
|
}
|
|
#else
|
|
#if !WITH_REMOTE // FIXME: implement remote feature
|
|
ToolbarItem(placement: .navigationBarLeading) {
|
|
newButton
|
|
}
|
|
#endif
|
|
#if !os(visionOS) && !WITH_REMOTE
|
|
ToolbarItem(placement: .navigationBarTrailing) {
|
|
Button("Settings") {
|
|
settingsPresented.toggle()
|
|
}
|
|
}
|
|
#endif
|
|
ToolbarItem(placement: .navigationBarTrailing) {
|
|
EditButton()
|
|
}
|
|
#endif
|
|
}
|
|
#if os(iOS)
|
|
// SwiftUI bug on iOS 14.4 and previous versions prevents multiple .sheet from working
|
|
.sheet(isPresented: $sheetPresented) {
|
|
if data.showNewVMSheet {
|
|
VMWizardView()
|
|
} else if settingsPresented {
|
|
#if !WITH_REMOTE
|
|
UTMSettingsView()
|
|
#endif
|
|
}
|
|
}
|
|
.onChange(of: data.showNewVMSheet) { newValue in
|
|
if newValue {
|
|
settingsPresented = false
|
|
sheetPresented = true
|
|
}
|
|
}
|
|
.onChange(of: settingsPresented) { newValue in
|
|
if newValue {
|
|
data.showNewVMSheet = false
|
|
sheetPresented = true
|
|
}
|
|
}
|
|
.onChange(of: sheetPresented) { newValue in
|
|
if !newValue {
|
|
settingsPresented = false
|
|
data.showNewVMSheet = false
|
|
}
|
|
}
|
|
.onReceive(NSNotification.OpenVirtualMachine) { _ in
|
|
sheetPresented = false
|
|
}
|
|
#else
|
|
.sheet(isPresented: $data.showNewVMSheet) {
|
|
VMWizardView()
|
|
}
|
|
.onReceive(NSNotification.OpenVirtualMachine) { _ in
|
|
data.showNewVMSheet = false
|
|
}
|
|
#endif
|
|
}
|
|
|
|
private var newButton: some View {
|
|
Button(action: { data.newVM() }, label: {
|
|
Label("New VM", systemImage: "plus").labelStyle(.iconOnly)
|
|
}).help("Create a new VM")
|
|
}
|
|
}
|