148 lines
6.6 KiB
Swift
148 lines
6.6 KiB
Swift
//
|
|
// Copyright © 2021 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 VMWizardOSWindowsView: View {
|
|
@ObservedObject var wizardState: VMWizardState
|
|
@State private var isFileImporterPresented: Bool = false
|
|
@State private var useVhdx: Bool = false
|
|
|
|
var body: some View {
|
|
VMWizardContent("Windows") {
|
|
Section {
|
|
Toggle("Install Windows 10 or higher", isOn: $wizardState.isWindows10OrHigher)
|
|
.onChange(of: wizardState.isWindows10OrHigher) { newValue in
|
|
if newValue {
|
|
wizardState.systemBootUefi = true
|
|
wizardState.systemBootTpm = true
|
|
wizardState.isGuestToolsInstallRequested = true
|
|
} else {
|
|
wizardState.systemBootTpm = false
|
|
wizardState.isGuestToolsInstallRequested = false
|
|
}
|
|
}
|
|
|
|
if wizardState.isWindows10OrHigher {
|
|
Toggle("Import VHDX Image", isOn: $useVhdx)
|
|
#if os(macOS)
|
|
if useVhdx {
|
|
#if arch(arm64)
|
|
Link(destination: URL(string: "https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64")!) {
|
|
Label("Download Windows 11 for ARM64 Preview VHDX", systemImage: "link")
|
|
}.buttonStyle(.borderless)
|
|
#endif
|
|
} else if #available(macOS 12, *) { // CrystalFetch is only available on macOS 12+
|
|
Button {
|
|
let downloadCrystalFetch = URL(string: "https://mac.getutm.app/crystalfetch/")!
|
|
if let crystalFetch = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "llc.turing.CrystalFetch") {
|
|
NSWorkspace.shared.openApplication(at: crystalFetch, configuration: .init()) { _, error in
|
|
if error != nil {
|
|
NSWorkspace.shared.open(downloadCrystalFetch)
|
|
}
|
|
}
|
|
} else {
|
|
NSWorkspace.shared.open(downloadCrystalFetch)
|
|
}
|
|
} label: {
|
|
Label("Fetch latest Windows installer…", systemImage: "link")
|
|
}.buttonStyle(.link)
|
|
}
|
|
#endif
|
|
Link(destination: URL(string: "https://docs.getutm.app/guides/windows/")!) {
|
|
Label("Windows Install Guide", systemImage: "link")
|
|
}.buttonStyle(.borderless)
|
|
}
|
|
} header: {
|
|
Text("Image File Type")
|
|
}
|
|
.onAppear {
|
|
// SwiftUI bug: on macOS 11, onAppear() is called every time the check box is clicked
|
|
if #available(iOS 15, macOS 12, *) {
|
|
if wizardState.windowsBootVhdx != nil {
|
|
useVhdx = true
|
|
}
|
|
}
|
|
}
|
|
|
|
Section {
|
|
if useVhdx {
|
|
FileBrowseField(url: $wizardState.windowsBootVhdx, isFileImporterPresented: $isFileImporterPresented, hasClearButton: false)
|
|
} else {
|
|
FileBrowseField(url: $wizardState.bootImageURL, isFileImporterPresented: $isFileImporterPresented, hasClearButton: false)
|
|
}
|
|
|
|
if wizardState.isBusy {
|
|
Spinner(size: .large)
|
|
}
|
|
} header: {
|
|
if useVhdx {
|
|
Text("Boot VHDX Image")
|
|
} else {
|
|
Text("Boot ISO Image")
|
|
}
|
|
}
|
|
|
|
if !wizardState.isWindows10OrHigher {
|
|
DetailedSection("", description: "Some older systems do not support UEFI boot, such as Windows 7 and below.") {
|
|
Toggle("UEFI Boot", isOn: $wizardState.systemBootUefi)
|
|
.onChange(of: wizardState.systemBootUefi) { newValue in
|
|
if !newValue {
|
|
wizardState.systemBootTpm = false
|
|
}
|
|
}
|
|
Toggle("Secure Boot with TPM 2.0", isOn: $wizardState.systemBootTpm)
|
|
.disabled(!wizardState.systemBootUefi)
|
|
}
|
|
}
|
|
|
|
// Disabled on iOS 14 due to a SwiftUI layout bug
|
|
// Disabled for non-Windows 10 installs due to autounattend version
|
|
if #available(iOS 15, *), wizardState.isWindows10OrHigher {
|
|
DetailedSection("", description: "Download and mount the guest support package for Windows. This is required for some features including dynamic resolution and clipboard sharing.") {
|
|
Toggle("Install drivers and SPICE tools", isOn: $wizardState.isGuestToolsInstallRequested)
|
|
}
|
|
}
|
|
}
|
|
.fileImporter(isPresented: $isFileImporterPresented, allowedContentTypes: [.data], onCompletion: processImage)
|
|
}
|
|
|
|
private func processImage(_ result: Result<URL, Error>) {
|
|
wizardState.busyWorkAsync {
|
|
let url = try result.get()
|
|
await MainActor.run {
|
|
if useVhdx {
|
|
wizardState.windowsBootVhdx = url
|
|
wizardState.bootImageURL = nil
|
|
wizardState.isSkipBootImage = true
|
|
} else {
|
|
wizardState.windowsBootVhdx = nil
|
|
wizardState.bootImageURL = url
|
|
wizardState.isSkipBootImage = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct VMWizardOSWindowsView_Previews: PreviewProvider {
|
|
@StateObject static var wizardState = VMWizardState()
|
|
|
|
static var previews: some View {
|
|
VMWizardOSWindowsView(wizardState: wizardState)
|
|
}
|
|
}
|