Skip to content

Commit 45f211b

Browse files
author
*
committed
Add button to show hard disk location in finder
1 parent a67f096 commit 45f211b

File tree

9 files changed

+76
-77
lines changed

9 files changed

+76
-77
lines changed

virtualOS.xcodeproj/project.pbxproj

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
0005A77A27E2809E0013BE83 /* VirtualMachineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0005A77927E2809E0013BE83 /* VirtualMachineView.swift */; };
1111
002E64922871B2DD00CE95A0 /* UserDefaults+Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 002E64912871B2DD00CE95A0 /* UserDefaults+Settings.swift */; };
12-
0044A65527F601E60007988A /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0044A65427F601E60007988A /* MainViewModel.swift */; };
12+
0044A65527F601E60007988A /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0044A65427F601E60007988A /* ViewModel.swift */; };
1313
0044A65A27F76BD30007988A /* URL+Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0044A65927F76BD30007988A /* URL+Paths.swift */; };
1414
006504E727F9D59300723BCA /* ConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 006504E627F9D59300723BCA /* ConfigurationView.swift */; };
1515
007987AF27E2487200960D74 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 007987AE27E2487200960D74 /* LICENSE */; };
@@ -49,7 +49,7 @@
4949
/* Begin PBXFileReference section */
5050
0005A77927E2809E0013BE83 /* VirtualMachineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VirtualMachineView.swift; sourceTree = "<group>"; };
5151
002E64912871B2DD00CE95A0 /* UserDefaults+Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Settings.swift"; sourceTree = "<group>"; };
52-
0044A65427F601E60007988A /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = "<group>"; };
52+
0044A65427F601E60007988A /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = "<group>"; };
5353
0044A65927F76BD30007988A /* URL+Paths.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Paths.swift"; sourceTree = "<group>"; };
5454
006504E627F9D59300723BCA /* ConfigurationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationView.swift; sourceTree = "<group>"; };
5555
007987AE27E2487200960D74 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
@@ -135,8 +135,8 @@
135135
children = (
136136
00BA26AC2826DAF200E80B76 /* Info.plist */,
137137
00989C6327E2340C0048776B /* virtualOSApp.swift */,
138-
00989C9127E236A10048776B /* Model */,
139138
00989C9327E236A10048776B /* View */,
139+
00989C9127E236A10048776B /* Model */,
140140
0090AF5F27E25F6F0077D35F /* Extension */,
141141
00989C6727E2340D0048776B /* Assets.xcassets */,
142142
00989C6C27E2340D0048776B /* virtualOS.entitlements */,
@@ -174,7 +174,7 @@
174174
isa = PBXGroup;
175175
children = (
176176
01FCAD8329AB707C00F12689 /* ApplicationDelegate.swift */,
177-
0044A65427F601E60007988A /* MainViewModel.swift */,
177+
0044A65427F601E60007988A /* ViewModel.swift */,
178178
007987B027E24A8400960D74 /* VirtualMac.swift */,
179179
00989C9927E238930048776B /* VirtualMacConfiguration.swift */,
180180
01B042F129CD9F6A003CD5C2 /* Bookmark.swift */,
@@ -338,7 +338,7 @@
338338
00989C9A27E238930048776B /* VirtualMacConfiguration.swift in Sources */,
339339
01B042F229CD9F6A003CD5C2 /* Bookmark.swift in Sources */,
340340
0090AF6127E25F6F0077D35F /* UInt64+Byte.swift in Sources */,
341-
0044A65527F601E60007988A /* MainViewModel.swift in Sources */,
341+
0044A65527F601E60007988A /* ViewModel.swift in Sources */,
342342
);
343343
runOnlyForDeploymentPostprocessing = 0;
344344
};
@@ -500,7 +500,7 @@
500500
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
501501
CODE_SIGN_STYLE = Automatic;
502502
COMBINE_HIDPI_IMAGES = YES;
503-
CURRENT_PROJECT_VERSION = 9;
503+
CURRENT_PROJECT_VERSION = 12;
504504
DEAD_CODE_STRIPPING = YES;
505505
DEVELOPMENT_ASSET_PATHS = "\"virtualOS/Preview Content\"";
506506
DEVELOPMENT_TEAM = 2AD47BTDQ6;
@@ -515,7 +515,7 @@
515515
"@executable_path/../Frameworks",
516516
);
517517
MACOSX_DEPLOYMENT_TARGET = 12.0;
518-
MARKETING_VERSION = 1.3;
518+
MARKETING_VERSION = 1.3.2;
519519
PRODUCT_BUNDLE_IDENTIFIER = com.github.yep.ios.virtualOS;
520520
PRODUCT_NAME = "$(TARGET_NAME)";
521521
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -533,7 +533,7 @@
533533
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
534534
CODE_SIGN_STYLE = Automatic;
535535
COMBINE_HIDPI_IMAGES = YES;
536-
CURRENT_PROJECT_VERSION = 9;
536+
CURRENT_PROJECT_VERSION = 12;
537537
DEAD_CODE_STRIPPING = YES;
538538
DEVELOPMENT_ASSET_PATHS = "\"virtualOS/Preview Content\"";
539539
DEVELOPMENT_TEAM = 2AD47BTDQ6;
@@ -548,7 +548,7 @@
548548
"@executable_path/../Frameworks",
549549
);
550550
MACOSX_DEPLOYMENT_TARGET = 12.0;
551-
MARKETING_VERSION = 1.3;
551+
MARKETING_VERSION = 1.3.2;
552552
PRODUCT_BUNDLE_IDENTIFIER = com.github.yep.ios.virtualOS;
553553
PRODUCT_NAME = "$(TARGET_NAME)";
554554
SWIFT_EMIT_LOC_STRINGS = YES;

virtualOS/Model/Bookmark.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,9 @@ struct Bookmark {
3535
previousURL.stopAccessingSecurityScopedResource()
3636
}
3737

38-
if accessedURLs[key] == bookmarkURL {
39-
// resource already accessed, do nothing
40-
} else {
41-
// start access resource
42-
if !bookmarkURL.startAccessingSecurityScopedResource() {
43-
// access failed
44-
bookmarkURL.stopAccessingSecurityScopedResource()
45-
return nil
46-
}
38+
if accessedURLs[key] != bookmarkURL {
39+
// resource not already accessed, start access
40+
_ = bookmarkURL.startAccessingSecurityScopedResource()
4741
accessedURLs[key] = bookmarkURL
4842
}
4943
return bookmarkURL
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// MainViewModel.swift
2+
// ViewModel.swift
33
// virtualOS
44
//
55
// Created by Jahn Bertsch on 31.03.22.
@@ -11,7 +11,7 @@ import Foundation
1111
import Virtualization
1212
import OSLog
1313

14-
final class MainViewModel: NSObject, ObservableObject {
14+
final class ViewModel: NSObject, ObservableObject {
1515
enum State: String {
1616
case Downloading
1717
case Installing
@@ -342,7 +342,7 @@ final class MainViewModel: NSObject, ObservableObject {
342342
}
343343
}
344344

345-
extension MainViewModel: VZVirtualMachineDelegate {
345+
extension ViewModel: VZVirtualMachineDelegate {
346346
func guestDidStop(_ vm: VZVirtualMachine) {
347347
state = .Stopped
348348
}

virtualOS/View/ConfigurationView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct ConfigurationView: View {
1919
case custom = 2
2020
}
2121

22-
@ObservedObject var viewModel: MainViewModel
22+
@ObservedObject var viewModel: ViewModel
2323
@State fileprivate var cpuCountSliderValue: Float = 0 {
2424
didSet {
2525
viewModel.virtualMac.parameters.cpuCount = Int(cpuCountSliderValue)
@@ -125,7 +125,7 @@ struct ConfigurationView: View {
125125
Text("Shared Folder").frame(minWidth: textWidth, alignment: .leading)
126126
VStack(alignment: .leading, content: {
127127
Picker("", selection: $sharedFolderType) {
128-
Text("None").tag(SharedFolderType.none)
128+
Text("No shared folder").tag(SharedFolderType.none)
129129
Text("Custom").tag(SharedFolderType.custom)
130130
}.pickerStyle(.inline)
131131
Button("Select Shared Folder") {
@@ -194,7 +194,7 @@ struct ConfigurationView: View {
194194
struct ConfigurationViewProvider_Previews: PreviewProvider {
195195
static var previews: some View {
196196
VStack {
197-
ConfigurationView(viewModel: MainViewModel())
197+
ConfigurationView(viewModel: ViewModel())
198198
}
199199
}
200200
}

virtualOS/View/MainView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import SwiftUI
1111

1212
struct MainView: View {
13-
@ObservedObject var viewModel: MainViewModel
13+
@ObservedObject var viewModel: ViewModel
1414

1515
var body: some View {
1616
VStack {
@@ -51,7 +51,7 @@ struct MainView: View {
5151

5252
struct ContentView_Previews: PreviewProvider {
5353
static var previews: some View {
54-
MainView(viewModel: MainViewModel())
54+
MainView(viewModel: ViewModel())
5555
}
5656
}
5757

virtualOS/View/MenuCommands.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftUI
1010
#if arch(arm64)
1111

1212
struct MenuCommands: Commands {
13-
@ObservedObject var viewModel: MainViewModel
13+
@ObservedObject var viewModel: ViewModel
1414

1515
var body: some Commands {
1616
CommandGroup(replacing: .appInfo) {
@@ -30,7 +30,7 @@ struct MenuCommands: Commands {
3030
Divider()
3131
Button("Delete Restore Image") {
3232
viewModel.deleteRestoreImage()
33-
}.disabled(!MainViewModel.restoreImageExists)
33+
}.disabled(!ViewModel.restoreImageExists)
3434
Button("Delete Virtual Machine", action: {
3535
viewModel.deleteVirtualMachine()
3636
})

virtualOS/View/SettingsView.swift

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,59 @@
99

1010
import SwiftUI
1111
import UniformTypeIdentifiers
12+
import AppKit
1213

1314
struct SettingsView: View {
14-
@ObservedObject var viewModel: MainViewModel
15-
16-
enum HardDiskLocation: String, CaseIterable, Identifiable {
15+
fileprivate enum HardDiskLocation: String, CaseIterable, Identifiable {
1716
case sandbox = "Sandbox"
18-
case custom = "Select location where VM hard disk images will be stored."
17+
case custom = "Select location where VM hard disk image will be stored."
1918
var id: Self { self }
2019
}
21-
enum RestoreImageType: String, CaseIterable, Identifiable {
20+
fileprivate enum RestoreImageType: String, CaseIterable, Identifiable {
2221
case latest = "Downloads latest restore image from Apple."
23-
case custom = "Select custom restore image (.ipsw)\nFor example, download from [https://ipsw.me](https://ipsw.me/product/Mac)"
22+
case custom = "Select custom restore image (.ipsw)\nFor example, download from https://ipsw.me/product/mac"
2423
var id: Self { self }
2524
}
25+
fileprivate struct SizeConstants {
26+
static let totalWidth = CGFloat(470)
27+
static let infoWidth = CGFloat(300)
28+
static let diskWidth = CGFloat(140)
29+
static let locationWidth = CGFloat(450)
30+
static let minTextHeight = CGFloat(28)
31+
}
2632

27-
@State var diskSize = String(UserDefaults.standard.diskSize)
28-
@State var hardDisk = HardDiskLocation.sandbox
29-
@State var restoreImageType = RestoreImageType.latest
30-
31-
var hardDiskLocationInfo: String {
32-
if let customHardDiskURL = viewModel.customHardDiskURL {
33-
return "Using \(customHardDiskURL.path)"
34-
} else if hardDisk == .sandbox {
33+
@ObservedObject var viewModel: ViewModel
34+
@State fileprivate var diskSize = String(UserDefaults.standard.diskSize)
35+
@State fileprivate var hardDiskLocation = HardDiskLocation.sandbox
36+
@State fileprivate var restoreImageType = RestoreImageType.latest
37+
@State fileprivate var showAlert = false
38+
39+
fileprivate var hardDiskLocationString: String {
40+
if hardDiskLocation == .sandbox {
3541
return URL.basePath
3642
} else {
37-
return HardDiskLocation.custom.rawValue
43+
if let customHardDiskURL = viewModel.customHardDiskURL {
44+
return customHardDiskURL.path
45+
} else {
46+
return HardDiskLocation.custom.rawValue
47+
}
3848
}
3949
}
40-
var restoreImageInfo: String {
50+
fileprivate var restoreImageInfoString: String {
4151
if let restoreImageURL = viewModel.customRestoreImageURL {
42-
return "Using \(restoreImageURL.path)"
52+
return restoreImageURL.path
4353
} else {
4454
return restoreImageType.rawValue
4555
}
4656
}
4757

4858
var body: some View {
49-
VStack {
50-
Text("Settings")
59+
VStack() {
60+
Text("Settings").font(.headline)
5161
Form {
5262
HStack {
5363
TextField("Hard Disk Size:", text: $diskSize)
54-
.frame(maxWidth: 130)
64+
.frame(maxWidth: SizeConstants.diskWidth)
5565
.onChange(of: diskSize) { newValue in
5666
if let newDiskSize = Int(diskSize) {
5767
viewModel.diskSize = newDiskSize
@@ -62,72 +72,70 @@ struct SettingsView: View {
6272
Text("(in GB)")
6373
}
6474

65-
Picker("Hard Disk Location:", selection: $hardDisk) {
75+
Picker("Hard Disk Location:", selection: $hardDiskLocation) {
6676
Text("Default").tag(HardDiskLocation.sandbox)
6777
Text("Custom").tag(HardDiskLocation.custom)
6878
}
6979
.pickerStyle(.inline)
70-
.onChange(of: hardDisk) { newValue in
80+
.onChange(of: hardDiskLocation) { newValue in
7181
if newValue == .sandbox {
7282
UserDefaults.standard.hardDiskDirectoryBookmarkData = nil
7383
}
7484
}
75-
85+
7686
HStack {
87+
Button("Show in Finder") {
88+
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: hardDiskLocationString)
89+
}.disabled(hardDiskLocation != .sandbox && viewModel.customHardDiskURL == nil)
90+
7791
Button("Select Hard Disk Location") {
7892
selectCustomHardDiskLocation()
79-
}.disabled(hardDisk == .sandbox)
93+
}.disabled(hardDiskLocation == .sandbox)
8094
}
8195

82-
Text(.init("hardDiskLocationInfo"))
96+
Text(.init(hardDiskLocationString))
8397
.font(.caption)
84-
.frame(maxWidth: 270, alignment: .leading)
85-
.fixedSize(horizontal: false, vertical: true)
98+
.frame(maxWidth: SizeConstants.infoWidth, minHeight: SizeConstants.minTextHeight, alignment: .topLeading)
8699
.lineLimit(nil)
87-
.disabled(hardDisk == .sandbox)
100+
.disabled(hardDiskLocation == .sandbox)
88101

102+
89103
Picker("Restore Image:", selection: $restoreImageType) {
90104
Text("Latest").tag(RestoreImageType.latest)
91105
Text("Custom").tag(RestoreImageType.custom)
92106
}.pickerStyle(.inline)
107+
93108
Button("Select Restore Image") {
94109
selectRestoreImage()
95110
}.disabled(restoreImageType == .latest)
96-
Text(restoreImageInfo)
111+
112+
Text(restoreImageInfoString)
97113
.font(.caption)
98-
.frame(maxWidth: 270, alignment: .leading)
114+
.frame(maxWidth: SizeConstants.infoWidth, minHeight: SizeConstants.minTextHeight, alignment: .topLeading)
99115
.fixedSize(horizontal: false, vertical: true)
100116
.lineLimit(nil)
101117
.disabled(restoreImageType == .latest)
102118
}.padding(.bottom)
103-
104-
Text("To open the hard disk location directory:\nIn Finder, in the 'Go' menu, select 'Go to Folder' and enter the path shown above.")
105-
.frame(maxWidth: 370, alignment: .leading)
106-
.fixedSize(horizontal: false, vertical: true)
107-
.lineLimit(nil)
108-
.padding(.bottom)
109-
.textSelection(.enabled)
110-
.font(.caption)
111-
119+
112120
Button("OK") {
113121
viewModel.showSettings = !viewModel.showSettings
114122
}.keyboardShortcut(.defaultAction)
115123
}
116124
.padding()
117-
.frame(minWidth: 420)
125+
.frame(minWidth: SizeConstants.totalWidth, maxWidth: SizeConstants.totalWidth)
118126
.onAppear() {
119127
diskSize = String(viewModel.diskSize)
120128
if let hardDiskDirectoryBookmarkData = UserDefaults.standard.hardDiskDirectoryBookmarkData,
121129
let hardDiskURL = Bookmark.startAccess(data: hardDiskDirectoryBookmarkData, forType: .hardDisk)
122130
{
123-
hardDisk = .custom
131+
hardDiskLocation = .custom
124132
viewModel.customHardDiskURL = hardDiskURL
125133
}
126134
}
127135
}
128-
136+
129137
// MARK: - Private
130-
138+
131139
fileprivate func selectCustomHardDiskLocation() {
132140
let openPanel = NSOpenPanel()
133141
openPanel.directoryURL = URL(fileURLWithPath: URL.basePath, isDirectory: true)
@@ -144,7 +152,7 @@ struct SettingsView: View {
144152
UserDefaults.standard.hardDiskDirectoryBookmarkData = hardDiskDirectoryBookmarkData
145153
}
146154
}
147-
155+
148156
fileprivate func selectRestoreImage() {
149157
guard let ipswContentType = UTType(filenameExtension: "ipsw") else {
150158
return
@@ -159,13 +167,12 @@ struct SettingsView: View {
159167
viewModel.customRestoreImageURL = selectedURL
160168
}
161169
}
162-
163170
}
164171

165172
struct SettingsViewProvider_Previews: PreviewProvider {
166173
static var previews: some View {
167174
VStack {
168-
SettingsView(viewModel: MainViewModel())
175+
SettingsView(viewModel: ViewModel())
169176
}
170177
}
171178
}

virtualOS/virtualOS.entitlements

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,5 @@
1010
<true/>
1111
<key>com.apple.security.files.user-selected.read-write</key>
1212
<true/>
13-
<key>com.apple.security.files.bookmarks.document-scope</key>
14-
<true/>
1513
</dict>
1614
</plist>

0 commit comments

Comments
 (0)