Skip to content

Commit 41089c0

Browse files
author
Atacan Durmusoglu
committed
spinner appkit small size
2 parents e77d688 + 47c87d1 commit 41089c0

File tree

4 files changed

+109
-20
lines changed

4 files changed

+109
-20
lines changed

Shared/FileSearch/FileSearchModel.swift

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,20 @@ extension String {
1414
struct FileModel: Identifiable {
1515
let id = UUID()
1616
let path: String
17-
var url: URL {
17+
var url: URL {
1818
URL(fileURLWithPath: path)
1919
}
2020
}
2121

2222
class FileSearch: ObservableObject {
2323
@Published var searchText: String = ""
24-
var pickedPath = ""
24+
@Published var pickedPath = ""
2525
// @Published var foundFiles: [String] = []
2626
@Published var foundFiles: [FileModel] = []
2727
// @Published var selectedFile: String = ""
2828
@Published var selectedFile: FileModel? = nil // .init(name: "")
2929
@Published var selectedFileContent: String = ""
30+
@Published var isSearching = false
3031
var cancellables: Set<AnyCancellable> = []
3132

3233
init() {
@@ -46,17 +47,9 @@ class FileSearch: ObservableObject {
4647
openPanel.canChooseFiles = false
4748
openPanel.begin { [weak self] result in
4849
if result.rawValue == NSApplication.ModalResponse.OK.rawValue {
49-
if let selectedPath = openPanel.url?.path.escapingSpaces(), let searchText = self?.searchText {
50+
if let selectedPath = openPanel.url?.path.escapingSpaces() {
51+
self?.isSearching = true
5052
self?.pickedPath = selectedPath
51-
let command = "grep -rl '\(searchText)' \(selectedPath)"
52-
do {
53-
print(command)
54-
self?.foundFiles = try safeShell(command).components(separatedBy: "\n").map { name in
55-
FileModel(path: name)
56-
}
57-
} catch {
58-
print(error)
59-
}
6053
}
6154
}
6255
}
@@ -68,16 +61,77 @@ class FileSearch: ObservableObject {
6861
}
6962
}
7063

64+
func runCommand(_ command: String) async -> [FileModel] {
65+
do {
66+
let shellOutput = try safeShell(command)
67+
guard !shellOutput.isEmpty else { return [] }
68+
69+
let lines = shellOutput.components(separatedBy: "\n")
70+
return lines.map { name in
71+
FileModel(path: name)
72+
}
73+
} catch {
74+
return [FileModel(path: error.localizedDescription)]
75+
}
76+
}
77+
78+
func readFile(contentsOfFile path: String) async -> String {
79+
do {
80+
let content = try String(contentsOfFile: path)
81+
return content
82+
} catch {
83+
return error.localizedDescription
84+
}
85+
}
86+
7187
func makePublishers() {
72-
$selectedFile.sink { file in
73-
do {
88+
$selectedFile
89+
.asyncMap { file -> String in
7490
if let fileUnwrap = file {
75-
self.selectedFileContent = try String(contentsOfFile: fileUnwrap.path)
91+
return await self.readFile(contentsOfFile: fileUnwrap.path)
92+
} else {
93+
return "No file selected"
94+
}
95+
}
96+
.receive(on: RunLoop.main)
97+
.sink { [weak self] content in
98+
self?.selectedFileContent = content
99+
}
100+
.store(in: &cancellables)
101+
102+
$pickedPath
103+
.asyncMap { selectedPath -> [FileModel] in
104+
guard !selectedPath.isEmpty else {
105+
return [FileModel(path: "No directory selected")]
106+
}
107+
let command = "grep -rl '\(self.searchText)' \(selectedPath)"
108+
let files = await self.runCommand(command)
109+
110+
if files.isEmpty {
111+
return [FileModel(path: "No files found in \(selectedPath)")]
112+
}
113+
return files
114+
}
115+
.receive(on: RunLoop.main)
116+
.sink { [weak self] files in
117+
self?.foundFiles = files
118+
self?.isSearching = false
119+
}
120+
.store(in: &cancellables)
121+
}
122+
}
123+
124+
extension Publisher {
125+
func asyncMap<T>(
126+
_ transform: @escaping (Output) async -> T
127+
) -> Publishers.FlatMap<Future<T, Never>, Self> {
128+
flatMap { value in
129+
Future { promise in
130+
Task {
131+
let output = await transform(value)
132+
promise(.success(output))
76133
}
77-
} catch {
78-
self.selectedFileContent = error.localizedDescription
79134
}
80135
}
81-
.store(in: &cancellables)
82136
}
83137
}

Shared/FileSearch/Views/ButtonFilePickerPanelView.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ struct ButtonFilePickerPanelView: View {
2020
} label: {
2121
Text("Search in \(Image(systemName: "folder")) Directory...")
2222
} // <-Button
23+
if fileSearchModel.isSearching {
24+
// ProgressView("Please wait...")
25+
HStack(alignment: .center) {
26+
MacProgressSpinner()
27+
Text("Please wait...")
28+
.foregroundColor(.secondary)
29+
} // <-HStack
30+
}
2331
Spacer()
2432
} // <-HStack
2533
.padding(.top)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// https://github.com/atacan
3+
// 02.07.22
4+
5+
6+
import SwiftUI
7+
8+
struct MacProgressSpinner: NSViewRepresentable {
9+
10+
func makeNSView(context: Context) -> NSProgressIndicator {
11+
let myProgressIndicator = NSProgressIndicator()
12+
myProgressIndicator.style = .spinning
13+
myProgressIndicator.controlSize = .small
14+
myProgressIndicator.startAnimation(nil)
15+
return myProgressIndicator
16+
}
17+
18+
func updateNSView(_ nsView: NSProgressIndicator, context: Context) {
19+
//
20+
}
21+
22+
typealias NSViewType = NSProgressIndicator
23+
24+
25+
}

Shared/Main/ShellCommand.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ func safeShell(_ command: String) throws -> String {
2424
try task.run() // <--updated
2525

2626
let data = pipe.fileHandleForReading.readDataToEndOfFile()
27-
let output = String(data: data, encoding: .utf8)!
27+
if let output = String(data: data, encoding: .utf8) {
28+
return output
29+
}
2830

29-
return output
31+
return ""
3032
}

0 commit comments

Comments
 (0)