Skip to content

Commit

Permalink
Add button to show hard disk location in finder
Browse files Browse the repository at this point in the history
  • Loading branch information
* committed Aug 27, 2023
1 parent a67f096 commit 45f211b
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 77 deletions.
18 changes: 9 additions & 9 deletions virtualOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/* Begin PBXBuildFile section */
0005A77A27E2809E0013BE83 /* VirtualMachineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0005A77927E2809E0013BE83 /* VirtualMachineView.swift */; };
002E64922871B2DD00CE95A0 /* UserDefaults+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002E64912871B2DD00CE95A0 /* UserDefaults+Settings.swift */; };
0044A65527F601E60007988A /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0044A65427F601E60007988A /* MainViewModel.swift */; };
0044A65527F601E60007988A /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0044A65427F601E60007988A /* ViewModel.swift */; };
0044A65A27F76BD30007988A /* URL+Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0044A65927F76BD30007988A /* URL+Paths.swift */; };
006504E727F9D59300723BCA /* ConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006504E627F9D59300723BCA /* ConfigurationView.swift */; };
007987AF27E2487200960D74 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 007987AE27E2487200960D74 /* LICENSE */; };
Expand Down Expand Up @@ -49,7 +49,7 @@
/* Begin PBXFileReference section */
0005A77927E2809E0013BE83 /* VirtualMachineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VirtualMachineView.swift; sourceTree = "<group>"; };
002E64912871B2DD00CE95A0 /* UserDefaults+Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Settings.swift"; sourceTree = "<group>"; };
0044A65427F601E60007988A /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = "<group>"; };
0044A65427F601E60007988A /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = "<group>"; };
0044A65927F76BD30007988A /* URL+Paths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Paths.swift"; sourceTree = "<group>"; };
006504E627F9D59300723BCA /* ConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationView.swift; sourceTree = "<group>"; };
007987AE27E2487200960D74 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
Expand Down Expand Up @@ -135,8 +135,8 @@
children = (
00BA26AC2826DAF200E80B76 /* Info.plist */,
00989C6327E2340C0048776B /* virtualOSApp.swift */,
00989C9127E236A10048776B /* Model */,
00989C9327E236A10048776B /* View */,
00989C9127E236A10048776B /* Model */,
0090AF5F27E25F6F0077D35F /* Extension */,
00989C6727E2340D0048776B /* Assets.xcassets */,
00989C6C27E2340D0048776B /* virtualOS.entitlements */,
Expand Down Expand Up @@ -174,7 +174,7 @@
isa = PBXGroup;
children = (
01FCAD8329AB707C00F12689 /* ApplicationDelegate.swift */,
0044A65427F601E60007988A /* MainViewModel.swift */,
0044A65427F601E60007988A /* ViewModel.swift */,
007987B027E24A8400960D74 /* VirtualMac.swift */,
00989C9927E238930048776B /* VirtualMacConfiguration.swift */,
01B042F129CD9F6A003CD5C2 /* Bookmark.swift */,
Expand Down Expand Up @@ -338,7 +338,7 @@
00989C9A27E238930048776B /* VirtualMacConfiguration.swift in Sources */,
01B042F229CD9F6A003CD5C2 /* Bookmark.swift in Sources */,
0090AF6127E25F6F0077D35F /* UInt64+Byte.swift in Sources */,
0044A65527F601E60007988A /* MainViewModel.swift in Sources */,
0044A65527F601E60007988A /* ViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -500,7 +500,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 9;
CURRENT_PROJECT_VERSION = 12;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"virtualOS/Preview Content\"";
DEVELOPMENT_TEAM = 2AD47BTDQ6;
Expand All @@ -515,7 +515,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.0;
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = com.github.yep.ios.virtualOS;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -533,7 +533,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 9;
CURRENT_PROJECT_VERSION = 12;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"virtualOS/Preview Content\"";
DEVELOPMENT_TEAM = 2AD47BTDQ6;
Expand All @@ -548,7 +548,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.0;
MARKETING_VERSION = 1.3;
MARKETING_VERSION = 1.3.2;
PRODUCT_BUNDLE_IDENTIFIER = com.github.yep.ios.virtualOS;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down
12 changes: 3 additions & 9 deletions virtualOS/Model/Bookmark.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,9 @@ struct Bookmark {
previousURL.stopAccessingSecurityScopedResource()
}

if accessedURLs[key] == bookmarkURL {
// resource already accessed, do nothing
} else {
// start access resource
if !bookmarkURL.startAccessingSecurityScopedResource() {
// access failed
bookmarkURL.stopAccessingSecurityScopedResource()
return nil
}
if accessedURLs[key] != bookmarkURL {
// resource not already accessed, start access
_ = bookmarkURL.startAccessingSecurityScopedResource()
accessedURLs[key] = bookmarkURL
}
return bookmarkURL
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// MainViewModel.swift
// ViewModel.swift
// virtualOS
//
// Created by Jahn Bertsch on 31.03.22.
Expand All @@ -11,7 +11,7 @@ import Foundation
import Virtualization
import OSLog

final class MainViewModel: NSObject, ObservableObject {
final class ViewModel: NSObject, ObservableObject {
enum State: String {
case Downloading
case Installing
Expand Down Expand Up @@ -342,7 +342,7 @@ final class MainViewModel: NSObject, ObservableObject {
}
}

extension MainViewModel: VZVirtualMachineDelegate {
extension ViewModel: VZVirtualMachineDelegate {
func guestDidStop(_ vm: VZVirtualMachine) {
state = .Stopped
}
Expand Down
6 changes: 3 additions & 3 deletions virtualOS/View/ConfigurationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct ConfigurationView: View {
case custom = 2
}

@ObservedObject var viewModel: MainViewModel
@ObservedObject var viewModel: ViewModel
@State fileprivate var cpuCountSliderValue: Float = 0 {
didSet {
viewModel.virtualMac.parameters.cpuCount = Int(cpuCountSliderValue)
Expand Down Expand Up @@ -125,7 +125,7 @@ struct ConfigurationView: View {
Text("Shared Folder").frame(minWidth: textWidth, alignment: .leading)
VStack(alignment: .leading, content: {
Picker("", selection: $sharedFolderType) {
Text("None").tag(SharedFolderType.none)
Text("No shared folder").tag(SharedFolderType.none)
Text("Custom").tag(SharedFolderType.custom)
}.pickerStyle(.inline)
Button("Select Shared Folder") {
Expand Down Expand Up @@ -194,7 +194,7 @@ struct ConfigurationView: View {
struct ConfigurationViewProvider_Previews: PreviewProvider {
static var previews: some View {
VStack {
ConfigurationView(viewModel: MainViewModel())
ConfigurationView(viewModel: ViewModel())
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions virtualOS/View/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import SwiftUI

struct MainView: View {
@ObservedObject var viewModel: MainViewModel
@ObservedObject var viewModel: ViewModel

var body: some View {
VStack {
Expand Down Expand Up @@ -51,7 +51,7 @@ struct MainView: View {

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
MainView(viewModel: MainViewModel())
MainView(viewModel: ViewModel())
}
}

Expand Down
4 changes: 2 additions & 2 deletions virtualOS/View/MenuCommands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SwiftUI
#if arch(arm64)

struct MenuCommands: Commands {
@ObservedObject var viewModel: MainViewModel
@ObservedObject var viewModel: ViewModel

var body: some Commands {
CommandGroup(replacing: .appInfo) {
Expand All @@ -30,7 +30,7 @@ struct MenuCommands: Commands {
Divider()
Button("Delete Restore Image") {
viewModel.deleteRestoreImage()
}.disabled(!MainViewModel.restoreImageExists)
}.disabled(!ViewModel.restoreImageExists)
Button("Delete Virtual Machine", action: {
viewModel.deleteVirtualMachine()
})
Expand Down
99 changes: 53 additions & 46 deletions virtualOS/View/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,49 +9,59 @@

import SwiftUI
import UniformTypeIdentifiers
import AppKit

struct SettingsView: View {
@ObservedObject var viewModel: MainViewModel

enum HardDiskLocation: String, CaseIterable, Identifiable {
fileprivate enum HardDiskLocation: String, CaseIterable, Identifiable {
case sandbox = "Sandbox"
case custom = "Select location where VM hard disk images will be stored."
case custom = "Select location where VM hard disk image will be stored."
var id: Self { self }
}
enum RestoreImageType: String, CaseIterable, Identifiable {
fileprivate enum RestoreImageType: String, CaseIterable, Identifiable {
case latest = "Downloads latest restore image from Apple."
case custom = "Select custom restore image (.ipsw)\nFor example, download from [https://ipsw.me](https://ipsw.me/product/Mac)"
case custom = "Select custom restore image (.ipsw)\nFor example, download from https://ipsw.me/product/mac"
var id: Self { self }
}
fileprivate struct SizeConstants {
static let totalWidth = CGFloat(470)
static let infoWidth = CGFloat(300)
static let diskWidth = CGFloat(140)
static let locationWidth = CGFloat(450)
static let minTextHeight = CGFloat(28)
}

@State var diskSize = String(UserDefaults.standard.diskSize)
@State var hardDisk = HardDiskLocation.sandbox
@State var restoreImageType = RestoreImageType.latest

var hardDiskLocationInfo: String {
if let customHardDiskURL = viewModel.customHardDiskURL {
return "Using \(customHardDiskURL.path)"
} else if hardDisk == .sandbox {
@ObservedObject var viewModel: ViewModel
@State fileprivate var diskSize = String(UserDefaults.standard.diskSize)
@State fileprivate var hardDiskLocation = HardDiskLocation.sandbox
@State fileprivate var restoreImageType = RestoreImageType.latest
@State fileprivate var showAlert = false

fileprivate var hardDiskLocationString: String {
if hardDiskLocation == .sandbox {
return URL.basePath
} else {
return HardDiskLocation.custom.rawValue
if let customHardDiskURL = viewModel.customHardDiskURL {
return customHardDiskURL.path
} else {
return HardDiskLocation.custom.rawValue
}
}
}
var restoreImageInfo: String {
fileprivate var restoreImageInfoString: String {
if let restoreImageURL = viewModel.customRestoreImageURL {
return "Using \(restoreImageURL.path)"
return restoreImageURL.path
} else {
return restoreImageType.rawValue
}
}

var body: some View {
VStack {
Text("Settings")
VStack() {
Text("Settings").font(.headline)
Form {
HStack {
TextField("Hard Disk Size:", text: $diskSize)
.frame(maxWidth: 130)
.frame(maxWidth: SizeConstants.diskWidth)
.onChange(of: diskSize) { newValue in
if let newDiskSize = Int(diskSize) {
viewModel.diskSize = newDiskSize
Expand All @@ -62,72 +72,70 @@ struct SettingsView: View {
Text("(in GB)")
}

Picker("Hard Disk Location:", selection: $hardDisk) {
Picker("Hard Disk Location:", selection: $hardDiskLocation) {
Text("Default").tag(HardDiskLocation.sandbox)
Text("Custom").tag(HardDiskLocation.custom)
}
.pickerStyle(.inline)
.onChange(of: hardDisk) { newValue in
.onChange(of: hardDiskLocation) { newValue in
if newValue == .sandbox {
UserDefaults.standard.hardDiskDirectoryBookmarkData = nil
}
}

HStack {
Button("Show in Finder") {
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: hardDiskLocationString)
}.disabled(hardDiskLocation != .sandbox && viewModel.customHardDiskURL == nil)

Button("Select Hard Disk Location") {
selectCustomHardDiskLocation()
}.disabled(hardDisk == .sandbox)
}.disabled(hardDiskLocation == .sandbox)
}

Text(.init("hardDiskLocationInfo"))
Text(.init(hardDiskLocationString))
.font(.caption)
.frame(maxWidth: 270, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: SizeConstants.infoWidth, minHeight: SizeConstants.minTextHeight, alignment: .topLeading)
.lineLimit(nil)
.disabled(hardDisk == .sandbox)
.disabled(hardDiskLocation == .sandbox)


Picker("Restore Image:", selection: $restoreImageType) {
Text("Latest").tag(RestoreImageType.latest)
Text("Custom").tag(RestoreImageType.custom)
}.pickerStyle(.inline)

Button("Select Restore Image") {
selectRestoreImage()
}.disabled(restoreImageType == .latest)
Text(restoreImageInfo)

Text(restoreImageInfoString)
.font(.caption)
.frame(maxWidth: 270, alignment: .leading)
.frame(maxWidth: SizeConstants.infoWidth, minHeight: SizeConstants.minTextHeight, alignment: .topLeading)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(nil)
.disabled(restoreImageType == .latest)
}.padding(.bottom)

Text("To open the hard disk location directory:\nIn Finder, in the 'Go' menu, select 'Go to Folder' and enter the path shown above.")
.frame(maxWidth: 370, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(nil)
.padding(.bottom)
.textSelection(.enabled)
.font(.caption)


Button("OK") {
viewModel.showSettings = !viewModel.showSettings
}.keyboardShortcut(.defaultAction)
}
.padding()
.frame(minWidth: 420)
.frame(minWidth: SizeConstants.totalWidth, maxWidth: SizeConstants.totalWidth)
.onAppear() {
diskSize = String(viewModel.diskSize)
if let hardDiskDirectoryBookmarkData = UserDefaults.standard.hardDiskDirectoryBookmarkData,
let hardDiskURL = Bookmark.startAccess(data: hardDiskDirectoryBookmarkData, forType: .hardDisk)
{
hardDisk = .custom
hardDiskLocation = .custom
viewModel.customHardDiskURL = hardDiskURL
}
}
}

// MARK: - Private

fileprivate func selectCustomHardDiskLocation() {
let openPanel = NSOpenPanel()
openPanel.directoryURL = URL(fileURLWithPath: URL.basePath, isDirectory: true)
Expand All @@ -144,7 +152,7 @@ struct SettingsView: View {
UserDefaults.standard.hardDiskDirectoryBookmarkData = hardDiskDirectoryBookmarkData
}
}

fileprivate func selectRestoreImage() {
guard let ipswContentType = UTType(filenameExtension: "ipsw") else {
return
Expand All @@ -159,13 +167,12 @@ struct SettingsView: View {
viewModel.customRestoreImageURL = selectedURL
}
}

}

struct SettingsViewProvider_Previews: PreviewProvider {
static var previews: some View {
VStack {
SettingsView(viewModel: MainViewModel())
SettingsView(viewModel: ViewModel())
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions virtualOS/virtualOS.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,5 @@
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.document-scope</key>
<true/>
</dict>
</plist>
Loading

0 comments on commit 45f211b

Please sign in to comment.