소스 검색

settings(qemu): add devices UI

osy 3 년 전
부모
커밋
3379bda59d
4개의 변경된 파일145개의 추가작업 그리고 60개의 파일을 삭제
  1. 57 0
      Platform/Shared/VMSettingsAddDeviceMenuView.swift
  2. 43 37
      Platform/iOS/VMSettingsView.swift
  3. 37 23
      Platform/macOS/VMQEMUSettingsView.swift
  4. 8 0
      UTM.xcodeproj/project.pbxproj

+ 57 - 0
Platform/Shared/VMSettingsAddDeviceMenuView.swift

@@ -0,0 +1,57 @@
+//
+// 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 VMSettingsAddDeviceMenuView: View {
+    @ObservedObject var config: UTMQemuConfiguration
+    
+    var body: some View {
+        Menu {
+            Button {
+                config.displays.append(UTMQemuConfigurationDisplay())
+            } label: {
+                Label("Display", systemImage: "rectangle.on.rectangle")
+            }.disabled(config.system.architecture.displayDeviceType.allRawValues.isEmpty)
+            Button {
+                config.serials.append(UTMQemuConfigurationSerial())
+            } label: {
+                Label("Serial", systemImage: "cable.connector")
+            }.disabled(config.system.architecture.serialDeviceType.allRawValues.isEmpty)
+            Button {
+                config.networks.append(UTMQemuConfigurationNetwork())
+            } label: {
+                Label("Network", systemImage: "network")
+            }.disabled(config.system.architecture.networkDeviceType.allRawValues.isEmpty)
+            Button {
+                config.sound.append(UTMQemuConfigurationSound())
+            } label: {
+                Label("Sound", systemImage: "speaker.wave.2")
+            }.disabled(config.system.architecture.soundDeviceType.allRawValues.isEmpty)
+        } label: {
+            Label("New…", systemImage: "plus")
+        }.help("Add a new device.")
+        .menuStyle(.borderlessButton)
+    }
+}
+
+struct VMSettingsAddDeviceMenuView_Previews: PreviewProvider {
+    @StateObject static private var config = UTMQemuConfiguration()
+    
+    static var previews: some View {
+        VMSettingsAddDeviceMenuView(config: config)
+    }
+}

+ 43 - 37
Platform/iOS/VMSettingsView.swift

@@ -61,60 +61,66 @@ struct VMSettingsView: View {
                             Label("Drives", systemImage: "internaldrive")
                                 .labelStyle(.roundRectIcon)
                         })
-                    ForEach($config.displays) { $display in
-                        NavigationLink(
-                            destination: VMConfigDisplayView(config: $display, system: $config.system).navigationTitle("Display"),
-                            label: {
-                                Label("Display", systemImage: "rectangle.on.rectangle")
-                                    .labelStyle(RoundRectIconLabelStyle(color: .green))
-                            })
-                    }
-                    ForEach($config.serials) { $serial in
-                        NavigationLink(
-                            destination: VMConfigSerialView(config: $serial, system: $config.system).navigationTitle("Serial"),
-                            label: {
-                                Label("Serial", systemImage: "cable.connector")
-                                    .labelStyle(RoundRectIconLabelStyle(color: .green))
-                            })
-                    }
                     NavigationLink(
                         destination: VMConfigInputView(config: $config.input).navigationTitle("Input"),
                         label: {
                             Label("Input", systemImage: "keyboard")
                                 .labelStyle(RoundRectIconLabelStyle(color: .green))
                         })
-                    ForEach($config.networks) { $network in
-                        NavigationLink(
-                            destination: VMConfigNetworkView(config: $network, system: $config.system).navigationTitle("Network"),
-                            label: {
-                                Label("Network", systemImage: "network")
-                                    .labelStyle(RoundRectIconLabelStyle(color: .green))
-                            })
-                    }
-                    ForEach($config.sound) { $sound in
-                        NavigationLink(
-                            destination: VMConfigSoundView(config: $sound, system: $config.system).navigationTitle("Sound"),
-                            label: {
-                                Label("Sound", systemImage: "speaker.wave.2")
-                                    .labelStyle(RoundRectIconLabelStyle(color: .green))
-                            })
-                    }
                     NavigationLink(
                         destination: VMConfigSharingView(config: $config.sharing).navigationTitle("Sharing"),
                         label: {
                             Label("Sharing", systemImage: "person.crop.circle")
                                 .labelStyle(RoundRectIconLabelStyle(color: .yellow))
                         })
+                    Section(header: Text("Devices")) {
+                        ForEach($config.displays) { $display in
+                            NavigationLink(destination: VMConfigDisplayView(config: $display, system: $config.system).navigationTitle("Display")) {
+                                    Label("Display", systemImage: "rectangle.on.rectangle")
+                                        .labelStyle(RoundRectIconLabelStyle(color: .green))
+                                }
+                        }.onDelete { offsets in
+                            config.displays.remove(atOffsets: offsets)
+                        }
+                        ForEach($config.serials) { $serial in
+                            NavigationLink(destination: VMConfigSerialView(config: $serial, system: $config.system).navigationTitle("Serial")) {
+                                    Label("Serial", systemImage: "cable.connector")
+                                        .labelStyle(RoundRectIconLabelStyle(color: .green))
+                                }
+                        }.onDelete { offsets in
+                            config.serials.remove(atOffsets: offsets)
+                        }
+                        ForEach($config.networks) { $network in
+                            NavigationLink(destination: VMConfigNetworkView(config: $network, system: $config.system).navigationTitle("Network")) {
+                                    Label("Network", systemImage: "network")
+                                        .labelStyle(RoundRectIconLabelStyle(color: .green))
+                                }
+                        }.onDelete { offsets in
+                            config.networks.remove(atOffsets: offsets)
+                        }
+                        ForEach($config.sound) { $sound in
+                            NavigationLink(destination: VMConfigSoundView(config: $sound, system: $config.system).navigationTitle("Sound")) {
+                                    Label("Sound", systemImage: "speaker.wave.2")
+                                        .labelStyle(RoundRectIconLabelStyle(color: .green))
+                                }
+                        }.onDelete { offsets in
+                            config.sound.remove(atOffsets: offsets)
+                        }
+                    }
                 }
             }
             .navigationTitle("Settings")
             .navigationViewStyle(.stack)
-            .navigationBarItems(leading: Button(action: cancel, label: {
-                Text("Cancel")
-            }), trailing: HStack {
-                Button(action: save, label: {
+            .navigationBarItems(leading: HStack {
+                VMSettingsAddDeviceMenuView(config: config)
+                EditButton()
+            }, trailing: HStack {
+                Button(action: cancel) {
+                    Text("Cancel")
+                }
+                Button(action: save) {
                     Text("Save")
-                })
+                }
             })
         }.disabled(data.busy)
         .overlay(BusyOverlay())

+ 37 - 23
Platform/macOS/VMQEMUSettingsView.swift

@@ -22,6 +22,7 @@ struct VMQEMUSettingsView: View {
 
     @State private var infoActive: Bool = true
     @State private var isResetConfig: Bool = false
+    @State private var isNewDriveShown: Bool = false
     
     var body: some View {
         NavigationLink(destination: VMConfigInfoView(config: $config.information).scrollable(), isActive: $infoActive) {
@@ -38,37 +39,50 @@ struct VMQEMUSettingsView: View {
         NavigationLink(destination: VMConfigQEMUView(config: $config.qemu, system: $config.system, fetchFixedArguments: { config.generatedArguments }).scrollable()) {
             Label("QEMU", systemImage: "shippingbox")
         }
-        ForEach($config.displays) { $display in
-            NavigationLink(destination: VMConfigDisplayView(config: $display, system: $config.system).scrollable()) {
-                Label("Display", systemImage: "rectangle.on.rectangle")
-            }
-        }
-        ForEach($config.serials) { $serial in
-            NavigationLink(destination: VMConfigSerialView(config: $serial, system: $config.system).scrollable()) {
-                Label("Serial", systemImage: "cable.connector")
-            }
-        }
         NavigationLink(destination: VMConfigInputView(config: $config.input).scrollable()) {
             Label("Input", systemImage: "keyboard")
         }
-        ForEach($config.networks) { $network in
-            Group {
+        NavigationLink(destination: VMConfigSharingView(config: $config.sharing).scrollable()) {
+            Label("Sharing", systemImage: "person.crop.circle")
+        }
+        Section(header: Text("Devices")) {
+            ForEach($config.displays) { $display in
+                NavigationLink(destination: VMConfigDisplayView(config: $display, system: $config.system).scrollable()) {
+                    Label("Display", systemImage: "rectangle.on.rectangle")
+                }.contextMenu {
+                    DestructiveButton("Remove") {
+                        config.displays.removeAll(where: { $0.id == display.id })
+                    }
+                }
+            }
+            ForEach($config.serials) { $serial in
+                NavigationLink(destination: VMConfigSerialView(config: $serial, system: $config.system).scrollable()) {
+                    Label("Serial", systemImage: "cable.connector")
+                }.contextMenu {
+                    DestructiveButton("Remove") {
+                        config.serials.removeAll(where: { $0.id == serial.id })
+                    }
+                }
+            }
+            ForEach($config.networks) { $network in
                 NavigationLink(destination: VMConfigNetworkView(config: $network, system: $config.system).scrollable()) {
                     Label("Network", systemImage: "network")
-                }
-                NavigationLink(destination: VMConfigAdvancedNetworkView(config: $network).scrollable()) {
-                    Label("IP Configuration", systemImage: "mappin.circle")
-                        .padding(.leading)
+                }.contextMenu {
+                    DestructiveButton("Remove") {
+                        config.networks.removeAll(where: { $0.id == network.id })
+                    }
                 }
             }
-        }
-        ForEach($config.sound) { $sound in
-            NavigationLink(destination: VMConfigSoundView(config: $sound, system: $config.system).scrollable()) {
-                Label("Sound", systemImage: "speaker.wave.2")
+            ForEach($config.sound) { $sound in
+                NavigationLink(destination: VMConfigSoundView(config: $sound, system: $config.system).scrollable()) {
+                    Label("Sound", systemImage: "speaker.wave.2")
+                }.contextMenu {
+                    DestructiveButton("Remove") {
+                        config.sound.removeAll(where: { $0.id == sound.id })
+                    }
+                }
             }
-        }
-        NavigationLink(destination: VMConfigSharingView(config: $config.sharing).scrollable()) {
-            Label("Sharing", systemImage: "person.crop.circle")
+            VMSettingsAddDeviceMenuView(config: config)
         }
         Section(header: Text("Drives")) {
             VMDrivesSettingsView(drives: $config.drives, template: UTMQemuConfigurationDrive(forArchitecture: config.system.architecture, target: config.system.target))

+ 8 - 0
UTM.xcodeproj/project.pbxproj

@@ -179,6 +179,9 @@
 		84B36D2927B790BE00C22685 /* DestructiveButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B36D2827B790BE00C22685 /* DestructiveButton.swift */; };
 		84B36D2A27B790BE00C22685 /* DestructiveButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B36D2827B790BE00C22685 /* DestructiveButton.swift */; };
 		84B36D2B27B790BE00C22685 /* DestructiveButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B36D2827B790BE00C22685 /* DestructiveButton.swift */; };
+		84C4D9022880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4D9012880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift */; };
+		84C4D9032880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4D9012880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift */; };
+		84C4D9042880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4D9012880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift */; };
 		84C584E1268E95B3000FCABF /* UTMLegacyAppleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C584DE268E95B3000FCABF /* UTMLegacyAppleConfiguration.swift */; };
 		84C584E3268F8AE7000FCABF /* VMQEMUSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C584E2268F8AE7000FCABF /* VMQEMUSettingsView.swift */; };
 		84C584E5268F8C65000FCABF /* VMAppleSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C584E4268F8C65000FCABF /* VMAppleSettingsView.swift */; };
@@ -1609,6 +1612,7 @@
 		84A381A9268CB30C0048EE4D /* VMDrivesSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMDrivesSettingsView.swift; sourceTree = "<group>"; };
 		84B36D2427B704C200C22685 /* UTMDownloadVMTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMDownloadVMTask.swift; sourceTree = "<group>"; };
 		84B36D2827B790BE00C22685 /* DestructiveButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestructiveButton.swift; sourceTree = "<group>"; };
+		84C4D9012880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMSettingsAddDeviceMenuView.swift; sourceTree = "<group>"; };
 		84C584DC268E70F1000FCABF /* UTMVirtualMachine-Protected.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UTMVirtualMachine-Protected.h"; sourceTree = "<group>"; };
 		84C584DE268E95B3000FCABF /* UTMLegacyAppleConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMLegacyAppleConfiguration.swift; sourceTree = "<group>"; };
 		84C584E2268F8AE7000FCABF /* VMQEMUSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMQEMUSettingsView.swift; sourceTree = "<group>"; };
@@ -3100,6 +3104,7 @@
 				CE2D954B24AD4F980059923A /* VMDetailsView.swift */,
 				CE2D954224AD4F980059923A /* VMPlaceholderView.swift */,
 				CE2D954524AD4F980059923A /* VMRemovableDrivesView.swift */,
+				84C4D9012880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift */,
 				CE8813D424CD265700532628 /* VMShareFileModifier.swift */,
 				CE2D953824AD4F980059923A /* VMToolbarModifier.swift */,
 				CEBE820226A4C1B5007AAB12 /* VMWizardDrivesView.swift */,
@@ -3457,6 +3462,7 @@
 			files = (
 				CE2D926A24AD46670059923A /* VMDisplayMetalViewController+Pointer.h in Sources */,
 				CE2D926B24AD46670059923A /* qapi-types-rocker.c in Sources */,
+				84C4D9022880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift in Sources */,
 				CE2D956F24AD4F990059923A /* VMRemovableDrivesView.swift in Sources */,
 				CE2D926E24AD46670059923A /* qapi-commands-crypto.c in Sources */,
 				2CE8EB092572E173000E2EBB /* qapi-visit-block-export.c in Sources */,
@@ -4009,6 +4015,7 @@
 				CE0B6D2E24AD57FC00FE012D /* qapi-commands-migration.c in Sources */,
 				CE0B6D5324AD584C00FE012D /* qapi-types-transaction.c in Sources */,
 				CE0B6D7424AD584D00FE012D /* qapi-visit-misc.c in Sources */,
+				84C4D9042880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift in Sources */,
 				CE0B6D3624AD57FC00FE012D /* qapi-commands-common.c in Sources */,
 				8471770C27CCA60600D3A50B /* DefaultPicker.swift in Sources */,
 				CEBE820526A4C1B5007AAB12 /* VMWizardDrivesView.swift in Sources */,
@@ -4083,6 +4090,7 @@
 				CEA45E55263519B5002FA97D /* qapi-types-net.c in Sources */,
 				CEA45E56263519B5002FA97D /* qapi-types-rdma.c in Sources */,
 				CEA45E57263519B5002FA97D /* ImagePicker.swift in Sources */,
+				84C4D9032880CA8A00EC3B2B /* VMSettingsAddDeviceMenuView.swift in Sources */,
 				CEA45E58263519B5002FA97D /* qapi-commands-rocker.c in Sources */,
 				CEA45E5A263519B5002FA97D /* VMConfigSystemView.swift in Sources */,
 				CEA45E5B263519B5002FA97D /* VMShareFileModifier.swift in Sources */,