Skip to content

Commit 8f203df

Browse files
committed
add Cancel button to add source view
1 parent 881b537 commit 8f203df

13 files changed

+309
-263
lines changed

Diff for: LlamaChat.xcodeproj/project.pbxproj

+12
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
82C68BEE29E77F3700A7A4AE /* CheckForUpdatesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82C68BED29E77F3700A7A4AE /* CheckForUpdatesViewModel.swift */; };
8989
82E3F1D829DF2865003F0368 /* ConfigureSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E3F1D729DF2865003F0368 /* ConfigureSourceViewModel.swift */; };
9090
82E3F1DC29DF37DA003F0368 /* AddSourceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E3F1DB29DF37DA003F0368 /* AddSourceViewModel.swift */; };
91+
82E43C9429E8AE6E003E69D1 /* ConvertSourcePrimaryActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E43C9329E8AE6E003E69D1 /* ConvertSourcePrimaryActionsView.swift */; };
92+
82E43C9629E8AF1E003E69D1 /* ConvertSourceStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E43C9529E8AF1E003E69D1 /* ConvertSourceStepView.swift */; };
93+
82E43C9829E8B099003E69D1 /* ConfigureSourcePrimaryActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E43C9729E8B099003E69D1 /* ConfigureSourcePrimaryActionsView.swift */; };
9194
82E7FFE329DE4CA800BF0251 /* ConfigureLocalModelPathSelectorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E7FFE229DE4CA800BF0251 /* ConfigureLocalModelPathSelectorViewModel.swift */; };
9295
82E7FFE729DE5B1F00BF0251 /* ConfigureLocalModelSizePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E7FFE629DE5B1F00BF0251 /* ConfigureLocalModelSizePickerView.swift */; };
9396
82E7FFE929DE5B7100BF0251 /* ConfigureLocalModelSizePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82E7FFE829DE5B7100BF0251 /* ConfigureLocalModelSizePickerViewModel.swift */; };
@@ -181,6 +184,9 @@
181184
82C68BEF29E7FB8100A7A4AE /* LlamaChat.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = LlamaChat.xcconfig; sourceTree = "<group>"; };
182185
82E3F1D729DF2865003F0368 /* ConfigureSourceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigureSourceViewModel.swift; sourceTree = "<group>"; };
183186
82E3F1DB29DF37DA003F0368 /* AddSourceViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSourceViewModel.swift; sourceTree = "<group>"; };
187+
82E43C9329E8AE6E003E69D1 /* ConvertSourcePrimaryActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertSourcePrimaryActionsView.swift; sourceTree = "<group>"; };
188+
82E43C9529E8AF1E003E69D1 /* ConvertSourceStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertSourceStepView.swift; sourceTree = "<group>"; };
189+
82E43C9729E8B099003E69D1 /* ConfigureSourcePrimaryActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigureSourcePrimaryActionsView.swift; sourceTree = "<group>"; };
184190
82E7FFE229DE4CA800BF0251 /* ConfigureLocalModelPathSelectorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigureLocalModelPathSelectorViewModel.swift; sourceTree = "<group>"; };
185191
82E7FFE629DE5B1F00BF0251 /* ConfigureLocalModelSizePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigureLocalModelSizePickerView.swift; sourceTree = "<group>"; };
186192
82E7FFE829DE5B7100BF0251 /* ConfigureLocalModelSizePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigureLocalModelSizePickerViewModel.swift; sourceTree = "<group>"; };
@@ -226,6 +232,8 @@
226232
isa = PBXGroup;
227233
children = (
228234
821B254229E0A46B00CF1001 /* ConvertSourceView.swift */,
235+
82E43C9329E8AE6E003E69D1 /* ConvertSourcePrimaryActionsView.swift */,
236+
82E43C9529E8AF1E003E69D1 /* ConvertSourceStepView.swift */,
229237
);
230238
path = convert;
231239
sourceTree = "<group>";
@@ -514,6 +522,7 @@
514522
8227DA8029D88228000E554D /* ConfigureLocalModelSourceView.swift */,
515523
82A7B4E529DE46F600BCBB6B /* ConfigureLocalPyTorchModelSettingsView.swift */,
516524
82A7B4E829DE472800BCBB6B /* ConfigureLocalGgmlModelSettingsView.swift */,
525+
82E43C9729E8B099003E69D1 /* ConfigureSourcePrimaryActionsView.swift */,
517526
82A7B4E729DE470000BCBB6B /* components */,
518527
);
519528
path = configure;
@@ -727,6 +736,7 @@
727736
82718D0629D368EA00545C32 /* ChatView.swift in Sources */,
728737
82718D0729D368EA00545C32 /* ComposeView.swift in Sources */,
729738
82718CFE29D368E500545C32 /* ChatViewModel.swift in Sources */,
739+
82E43C9429E8AE6E003E69D1 /* ConvertSourcePrimaryActionsView.swift in Sources */,
730740
82AE199829D83206008189DF /* SettingsViewModel.swift in Sources */,
731741
82F14EA329E45C5D001E9C1E /* AvatarPickerView.swift in Sources */,
732742
8227DA9729D911A4000E554D /* LlamaChatApp.swift in Sources */,
@@ -767,6 +777,7 @@
767777
8227DA7329D8626F000E554D /* SourcesSettingsDetailView.swift in Sources */,
768778
82914CDA29D79DFD00858B2C /* StaticMessageViewModel.swift in Sources */,
769779
8227DA6B29D8586E000E554D /* ConfirmSheetDeletionContentView.swift in Sources */,
780+
82E43C9629E8AF1E003E69D1 /* ConvertSourceStepView.swift in Sources */,
770781
821B255729E1F05000CF1001 /* NSScrollView+Bottom.swift in Sources */,
771782
8227DA8D29D8D7E9000E554D /* ChatWindowContentViewModel.swift in Sources */,
772783
8227DA7829D86633000E554D /* SourcesSettingsDetailViewModel.swift in Sources */,
@@ -779,6 +790,7 @@
779790
82914CCC29D76ABE00858B2C /* StaticMessage.swift in Sources */,
780791
82914CE029D7A06C00858B2C /* Message.swift in Sources */,
781792
82AE198B29D7A330008189DF /* GeneratedMessageView.swift in Sources */,
793+
82E43C9829E8B099003E69D1 /* ConfigureSourcePrimaryActionsView.swift in Sources */,
782794
8227DA8129D88228000E554D /* ConfigureLocalModelSourceView.swift in Sources */,
783795
8227DA9E29D9812F000E554D /* AddSourceFlowPresentationStyle.swift in Sources */,
784796
8255EA5C29D59690000B9F83 /* SelectSourceTypeView.swift in Sources */,

Diff for: LlamaChat/ui/settings/tabs/sources/SourcesSettingsDetailView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,6 @@ struct SourcesSettingsDetailView: View {
8282
}
8383
}
8484
}
85-
.formStyle(GroupedFormStyle())
85+
.formStyle(.grouped)
8686
}
8787
}

Diff for: LlamaChat/ui/sources/AddSourceContentView.swift

+45-11
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,62 @@
77

88
import SwiftUI
99

10+
fileprivate struct StepView<Content, PrimaryActions>: View where Content: View, PrimaryActions: View {
11+
@ObservedObject var viewModel: AddSourceViewModel
12+
13+
typealias ContentBuilder = () -> Content
14+
typealias PrimaryActionsBuilder = () -> PrimaryActions
15+
16+
@ViewBuilder let content: ContentBuilder
17+
@ViewBuilder let primaryActions: PrimaryActionsBuilder
18+
19+
var body: some View {
20+
VStack(spacing: 0) {
21+
content()
22+
Spacer()
23+
HStack {
24+
Button("Cancel", action: { viewModel.cancel() })
25+
Spacer()
26+
primaryActions()
27+
}
28+
.padding(20)
29+
}
30+
}
31+
}
32+
1033
struct AddSourceContentView: View {
1134
@ObservedObject var viewModel: AddSourceViewModel
1235

1336
var body: some View {
1437
NavigationStack(path: $viewModel.navigationPath) {
15-
SelectSourceTypeView(viewModel: viewModel.selectSourceTypeViewModel)
16-
.navigationTitle("Add Chat Source")
17-
.navigationDestination(for: AddSourceStep.self) { step in
18-
switch step {
19-
case .configureSource:
20-
if let configureSourceViewModel = viewModel.configureSourceViewModel {
38+
StepView(viewModel: viewModel, content: {
39+
SelectSourceTypeView(viewModel: viewModel.selectSourceTypeViewModel)
40+
.padding(EdgeInsets(top: 20, leading: 20, bottom: 0, trailing: 20))
41+
}, primaryActions: {})
42+
.navigationTitle("Add Chat Source")
43+
.navigationDestination(for: AddSourceStep.self) { step in
44+
switch step {
45+
case .configureSource:
46+
if let configureSourceViewModel = viewModel.configureSourceViewModel {
47+
StepView(viewModel: viewModel, content: {
2148
makeConfigureSourceView(from: configureSourceViewModel)
2249
.navigationTitle("Set up \(configureSourceViewModel.chatSourceType.readableName) model")
23-
}
24-
case .convertPyTorchSource:
25-
if let convertSourceViewModel = viewModel.convertSourceViewModel {
50+
}, primaryActions: {
51+
ConfigureSourcePrimaryActionsView(viewModel: configureSourceViewModel.primaryActionsViewModel)
52+
})
53+
}
54+
case .convertPyTorchSource:
55+
if let convertSourceViewModel = viewModel.convertSourceViewModel {
56+
StepView(viewModel: viewModel, content: {
2657
ConvertSourceView(viewModel: convertSourceViewModel)
2758
.navigationTitle("Convert PyTorch model files")
28-
}
59+
}, primaryActions: {
60+
ConvertSourcePrimaryActionsView(viewModel: convertSourceViewModel)
61+
})
2962
}
3063
}
64+
}
3165
}
32-
.frame(width: 620, height: 430)
66+
.frame(width: 640, height: 450)
3367
}
3468
}

Diff for: LlamaChat/ui/sources/configure/ConfigureLocalModelSourceView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,6 @@ struct ConfigureLocalModelSourceView: View {
9090
}
9191
}
9292
}
93-
.formStyle(GroupedFormStyle())
93+
.formStyle(.grouped)
9494
}
9595
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// ConfigureSourcePrimaryActionsView.swift
3+
// LlamaChat
4+
//
5+
// Created by Alex Rozanski on 13/04/2023.
6+
//
7+
8+
import SwiftUI
9+
10+
protocol ConfigureSourcePrimaryActionsViewModelDelegate: AnyObject {
11+
func next()
12+
}
13+
14+
class ConfigureSourcePrimaryActionsViewModel: ObservableObject {
15+
@Published var showContinueButton: Bool = false
16+
@Published var canContinue: Bool = false
17+
@Published var nextButtonTitle: String = "Add"
18+
19+
weak var delegate: ConfigureSourcePrimaryActionsViewModelDelegate?
20+
21+
func next() {
22+
delegate?.next()
23+
}
24+
}
25+
26+
struct ConfigureSourcePrimaryActionsView: View {
27+
@ObservedObject var viewModel: ConfigureSourcePrimaryActionsViewModel
28+
29+
var body: some View {
30+
HStack {
31+
Spacer()
32+
if viewModel.showContinueButton {
33+
Button(viewModel.nextButtonTitle) {
34+
viewModel.next()
35+
}
36+
.keyboardShortcut(.return)
37+
.disabled(!viewModel.canContinue)
38+
}
39+
}
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// ConvertSourcePrimaryActionsView.swift
3+
// LlamaChat
4+
//
5+
// Created by Alex Rozanski on 13/04/2023.
6+
//
7+
8+
import SwiftUI
9+
10+
struct ConvertSourcePrimaryActionsView: View {
11+
@ObservedObject var viewModel: ConvertSourceViewModel
12+
13+
@ViewBuilder var primaryButton: some View {
14+
Button(action: {
15+
switch viewModel.state {
16+
case .finishedConverting:
17+
viewModel.finish()
18+
case .failedToConvert:
19+
viewModel.retryConversion()
20+
case .notStarted, .converting:
21+
viewModel.startConversion()
22+
}
23+
}) {
24+
switch viewModel.state {
25+
case .finishedConverting:
26+
Text("Finish")
27+
case .failedToConvert:
28+
Text("Retry")
29+
case .notStarted, .converting:
30+
Text("Start")
31+
}
32+
}
33+
.keyboardShortcut(.return)
34+
.disabled(viewModel.state.isConverting)
35+
}
36+
37+
@ViewBuilder var stopButton: some View {
38+
Button(action: {
39+
viewModel.stopConversion()
40+
}) {
41+
Text("Stop")
42+
}
43+
}
44+
45+
var body: some View {
46+
HStack {
47+
if viewModel.state.isConverting {
48+
stopButton
49+
}
50+
primaryButton
51+
}
52+
}
53+
}
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
//
2+
// ConvertSourceStepView.swift
3+
// LlamaChat
4+
//
5+
// Created by Alex Rozanski on 13/04/2023.
6+
//
7+
8+
import SwiftUI
9+
10+
fileprivate struct RunTimeLabel: View {
11+
@ObservedObject var viewModel: ConvertSourceStepViewModel
12+
13+
@ViewBuilder var label: some View {
14+
if let runTime = viewModel.runTime {
15+
switch viewModel.state {
16+
case .notStarted, .skipped, .cancelled:
17+
EmptyView()
18+
case .running:
19+
Text("Running for \(String(format: "%.1f", floor(runTime))) seconds...")
20+
.font(.footnote)
21+
.padding(.horizontal, 14)
22+
.padding(.vertical, 8)
23+
case .finished:
24+
Text("Finished in \(String(format: "%.1f", runTime)) seconds")
25+
.font(.footnote)
26+
.padding(.horizontal, 14)
27+
.padding(.vertical, 8)
28+
}
29+
}
30+
}
31+
32+
var body: some View {
33+
label
34+
}
35+
}
36+
37+
fileprivate struct DetailView: View {
38+
@ObservedObject var viewModel: ConvertSourceStepViewModel
39+
40+
var body: some View {
41+
VStack(spacing: 0) {
42+
NonEditableTextView(viewModel: viewModel.textViewModel, scrollBehavior: .pinToBottom)
43+
.frame(maxWidth: .infinity)
44+
.frame(height: 100)
45+
Rectangle()
46+
.fill(Color(nsColor: .separatorColor))
47+
.frame(maxWidth: .infinity)
48+
.padding(.horizontal, 0.5)
49+
.frame(height: 1)
50+
HStack(spacing: 0) {
51+
RunTimeLabel(viewModel: viewModel)
52+
Spacer()
53+
Rectangle()
54+
.fill(Color(nsColor: .separatorColor))
55+
.frame(maxHeight: .infinity)
56+
.padding(.vertical, 0.5)
57+
.frame(width: 1)
58+
Text("Exit Code: `\(viewModel.exitCode.map { String($0) } ?? "-")`")
59+
.font(.footnote)
60+
.padding(.horizontal, 14)
61+
.padding(.vertical, 8)
62+
}
63+
}
64+
.background(Color(nsColor: .controlBackgroundColor))
65+
.mask(RoundedRectangle(cornerRadius: 4))
66+
.overlay(
67+
RoundedRectangle(cornerRadius: 4)
68+
.stroke(Color(nsColor: .separatorColor))
69+
)
70+
}
71+
}
72+
73+
struct ConvertSourceStepView: View {
74+
@ObservedObject var viewModel: ConvertSourceStepViewModel
75+
76+
var body: some View {
77+
VStack {
78+
LabeledContent(content: {
79+
switch viewModel.state {
80+
case .notStarted:
81+
EmptyView()
82+
case .skipped:
83+
Image(systemName: "exclamationmark.octagon")
84+
.foregroundColor(.gray)
85+
case .running:
86+
ProgressView()
87+
.progressViewStyle(.circular)
88+
.controlSize(.small)
89+
case .cancelled:
90+
Image(systemName: "xmark.circle.fill")
91+
.foregroundColor(.red)
92+
case .finished(result: let result):
93+
switch result {
94+
case .success(let exitCode):
95+
if exitCode == 0 {
96+
Image(systemName: "checkmark.circle.fill")
97+
.foregroundColor(.green)
98+
} else {
99+
Image(systemName: "xmark.circle.fill")
100+
.foregroundColor(.red)
101+
}
102+
case .failure:
103+
Image(systemName: "xmark.circle.fill")
104+
.foregroundColor(.red)
105+
}
106+
}
107+
}, label: {
108+
HStack(spacing: 4) {
109+
Button(action: {
110+
viewModel.toggleExpansion()
111+
}, label: {
112+
Image(systemName: viewModel.expanded ? "arrowtriangle.down.fill" : "arrowtriangle.forward.fill")
113+
.resizable()
114+
.scaledToFit()
115+
.foregroundColor(.gray)
116+
.frame(width: 8, height: 8)
117+
.padding(.trailing, 4)
118+
})
119+
.buttonStyle(.borderless)
120+
Text(viewModel.label)
121+
}
122+
})
123+
if viewModel.expanded {
124+
DetailView(viewModel: viewModel)
125+
}
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)