Skip to content

Commit 19f8e84

Browse files
committed
Split downloader app into separate files
1 parent 7fb1d9e commit 19f8e84

File tree

7 files changed

+542
-534
lines changed

7 files changed

+542
-534
lines changed

tools/ResourceDownloader/ResourceDownloader.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 56;
6+
objectVersion = 70;
77
objects = {
88

99
/* Begin PBXContainerItemProxy section */
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import SwiftUI
2+
3+
struct CompletionView: View {
4+
var body: some View {
5+
VStack(spacing: 20) {
6+
Image(systemName: "checkmark.seal.fill")
7+
.resizable()
8+
.scaledToFit()
9+
.frame(width: 80, height: 80)
10+
.foregroundColor(.green)
11+
12+
Text("All Done!")
13+
.font(.title)
14+
.fontWeight(.bold)
15+
16+
Text("All components were installed successfully. To start using OpenVINO features in Audacity, please restart the application.")
17+
.font(.body)
18+
.multilineTextAlignment(.center)
19+
.padding(.horizontal)
20+
21+
Text("Once restarted, you'll be able to access enhanced AI-powered effects and tools powered by OpenVINO.")
22+
.font(.footnote)
23+
.multilineTextAlignment(.center)
24+
.foregroundColor(.secondary)
25+
.padding(.horizontal)
26+
Spacer()
27+
HStack {
28+
Spacer()
29+
Button("Finish") {
30+
closeWindow()
31+
}
32+
.buttonStyle(.borderedProminent)
33+
Spacer()
34+
}
35+
}
36+
.padding()
37+
.navigationTitle("Model Downloader")
38+
}
39+
func closeWindow() {
40+
NSApp.keyWindow?.close()
41+
}
42+
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import SwiftUI
2+
3+
struct ContentView: View {
4+
@ObservedObject var modelStore: ModelStore
5+
@StateObject var viewModel = TreeViewModel()
6+
7+
var onBack: () -> Void
8+
var onContinue: () -> Void
9+
10+
init(modelStore: ModelStore, onBack: @escaping () -> Void, onContinue: @escaping () -> Void) {
11+
self.modelStore = modelStore
12+
self.onBack = onBack
13+
self.onContinue = onContinue
14+
_viewModel = StateObject(wrappedValue: TreeViewModel(nodes: modelStore.nodes))
15+
}
16+
17+
var body: some View {
18+
VStack(spacing: 0) {
19+
List {
20+
OutlineGroup(viewModel.nodes, id: \.id, children: \.children) { node in
21+
CheckboxView(node: node)
22+
.onTapGesture { viewModel.toggle(node: node) }
23+
}
24+
}
25+
.listStyle(.bordered(alternatesRowBackgrounds: false))
26+
27+
Divider()
28+
29+
HStack {
30+
SizeInfoView(
31+
label: "Total Download Size:",
32+
size: viewModel.totalDownloadSize
33+
)
34+
SizeInfoView(
35+
label: "Total Extracted Size:",
36+
size: viewModel.totalExtractedSize
37+
)
38+
}
39+
.padding()
40+
41+
HStack {
42+
Spacer()
43+
Button("Download selected", systemImage: "arrow.down.to.line") {
44+
onContinue()
45+
}
46+
.buttonStyle(.borderedProminent)
47+
Spacer()
48+
}
49+
.padding()
50+
}
51+
.navigationTitle("Model Downloader")
52+
}
53+
}
54+
55+
struct CheckboxView: View {
56+
@ObservedObject var node: Node
57+
58+
var body: some View {
59+
HStack(spacing: 8) {
60+
VStack(alignment: .leading, spacing: 4) {
61+
HStack {
62+
Image(systemName: systemImageName)
63+
.foregroundColor(node.state == .checked ? .blue : .primary)
64+
Text(node.name)
65+
.font(.body)
66+
}
67+
HStack(spacing: 16) {
68+
Text("Download: \(node.downloadSizeRecursive.formatted(.byteCount(style: .file)))")
69+
.foregroundColor(.secondary)
70+
Text("Extracted: \(node.extractedSizeRecursive.formatted(.byteCount(style: .file)))")
71+
.foregroundColor(.secondary)
72+
}
73+
.font(.caption)
74+
}
75+
}
76+
.padding(.leading, node.children != nil ? 0 : 16)
77+
}
78+
79+
private var systemImageName: String {
80+
switch node.state {
81+
case .checked: return "checkmark.square.fill"
82+
case .unchecked: return "square"
83+
case .mixed: return "minus.square.fill"
84+
}
85+
}
86+
}
87+
88+
struct SizeInfoView: View {
89+
let label: String
90+
let size: Int
91+
92+
var body: some View {
93+
VStack(alignment: .leading) {
94+
Text(label)
95+
.font(.caption)
96+
.foregroundColor(.secondary)
97+
Text(size.formatted(.byteCount(style: .file)))
98+
.font(.system(.body, design: .monospaced))
99+
}
100+
.frame(maxWidth: .infinity, alignment: .leading)
101+
.padding(8)
102+
.background(RoundedRectangle(cornerRadius: 8).fill(Color(nsColor: .controlBackgroundColor)))
103+
}
104+
}
105+
106+
class TreeViewModel: ObservableObject {
107+
108+
@Published var nodes: [Node]
109+
110+
@Published var totalDownloadSize = 0
111+
@Published var totalExtractedSize = 0
112+
113+
init(nodes: [Node] = []) {
114+
self.nodes = nodes
115+
self.totalDownloadSize = totalDownloadSize
116+
self.totalExtractedSize = totalExtractedSize
117+
}
118+
119+
func toggle(node: Node) {
120+
let newState: CheckState = node.state == .checked ? .unchecked : .checked
121+
node.state = newState
122+
updateChildren(node: node, state: newState)
123+
updateParentState(node.parent)
124+
calculateTotals()
125+
}
126+
127+
private func calculateTotals() {
128+
totalDownloadSize = calculateTotal(for: \.downloadSizeRecursive)
129+
totalExtractedSize = calculateTotal(for: \.extractedSizeRecursive)
130+
}
131+
132+
private func updateChildren(node: Node, state: CheckState) {
133+
node.children?.forEach {
134+
$0.state = state
135+
updateChildren(node: $0, state: state)
136+
}
137+
}
138+
139+
private func updateParentState(_ parent: Node?) {
140+
guard let parent = parent else { return }
141+
142+
let childrenStates = parent.children?.map { $0.state } ?? []
143+
let allChecked = childrenStates.allSatisfy { $0 == .checked }
144+
let allUnchecked = childrenStates.allSatisfy { $0 == .unchecked }
145+
146+
parent.state = allChecked ? .checked :
147+
allUnchecked ? .unchecked : .mixed
148+
149+
updateParentState(parent.parent)
150+
}
151+
152+
private func calculateTotal(for keyPath: KeyPath<Node, Int>) -> Int {
153+
var total = 0
154+
for node in nodes {
155+
if node.state != .unchecked {
156+
total += node[keyPath: keyPath]
157+
}
158+
}
159+
return total
160+
}
161+
}

0 commit comments

Comments
 (0)