소스 검색

Add spinner while job search response loads

Show an indeterminate NSProgressIndicator in the chat status area when the
status reads Thinking..., replacing the sparkles icon until the API returns.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 3 주 전
부모
커밋
1e6c0fde28
1개의 변경된 파일43개의 추가작업 그리고 1개의 파일을 삭제
  1. 43 1
      App for Indeed/Views/DashboardView.swift

+ 43 - 1
App for Indeed/Views/DashboardView.swift

@@ -82,7 +82,9 @@ final class DashboardView: NSView, NSTextFieldDelegate {
82 82
     private let findJobsCTAChrome = HoverableView()
83 83
     private var findJobsCTAGradientLayer: CAGradientLayer?
84 84
     private let chatStatusStack = NSStackView()
85
+    private let chatStatusSymbolContainer = NSView()
85 86
     private let chatStatusIcon = NSImageView()
87
+    private let chatStatusLoadingIndicator = NSProgressIndicator()
86 88
     private let chatStatusLabel = NSTextField(labelWithString: "Opening the vault...")
87 89
     private let chatScrollView = NSScrollView()
88 90
     private let chatDocumentView = JobListingsDocumentView()
@@ -282,20 +284,47 @@ final class DashboardView: NSView, NSTextFieldDelegate {
282 284
         chatStatusStack.alignment = .centerX
283 285
         chatStatusStack.translatesAutoresizingMaskIntoConstraints = false
284 286
 
287
+        chatStatusSymbolContainer.translatesAutoresizingMaskIntoConstraints = false
288
+
285 289
         chatStatusIcon.translatesAutoresizingMaskIntoConstraints = false
286 290
         chatStatusIcon.wantsLayer = true
287 291
         chatStatusIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 36, weight: .regular)
288 292
         chatStatusIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: "Assistant status")
289 293
         chatStatusIcon.contentTintColor = Theme.brandBlue
290 294
 
295
+        chatStatusLoadingIndicator.translatesAutoresizingMaskIntoConstraints = false
296
+        chatStatusLoadingIndicator.style = .spinning
297
+        chatStatusLoadingIndicator.isIndeterminate = true
298
+        chatStatusLoadingIndicator.isDisplayedWhenStopped = false
299
+        chatStatusLoadingIndicator.controlSize = .regular
300
+        chatStatusLoadingIndicator.isHidden = true
301
+        chatStatusLoadingIndicator.setAccessibilityRole(.progressIndicator)
302
+        chatStatusLoadingIndicator.setAccessibilityLabel("Searching for jobs")
303
+
304
+        chatStatusSymbolContainer.addSubview(chatStatusIcon)
305
+        chatStatusSymbolContainer.addSubview(chatStatusLoadingIndicator)
306
+
307
+        NSLayoutConstraint.activate([
308
+            chatStatusSymbolContainer.widthAnchor.constraint(equalToConstant: 40),
309
+            chatStatusSymbolContainer.heightAnchor.constraint(equalToConstant: 40),
310
+            chatStatusIcon.centerXAnchor.constraint(equalTo: chatStatusSymbolContainer.centerXAnchor),
311
+            chatStatusIcon.centerYAnchor.constraint(equalTo: chatStatusSymbolContainer.centerYAnchor),
312
+            chatStatusLoadingIndicator.centerXAnchor.constraint(equalTo: chatStatusSymbolContainer.centerXAnchor),
313
+            chatStatusLoadingIndicator.centerYAnchor.constraint(equalTo: chatStatusSymbolContainer.centerYAnchor),
314
+            chatStatusLoadingIndicator.widthAnchor.constraint(equalToConstant: 32),
315
+            chatStatusLoadingIndicator.heightAnchor.constraint(equalToConstant: 32)
316
+        ])
317
+
291 318
         chatStatusLabel.font = .systemFont(ofSize: 20, weight: .semibold)
292 319
         chatStatusLabel.textColor = Theme.primaryText
293 320
         chatStatusLabel.alignment = .center
294 321
         chatStatusLabel.maximumNumberOfLines = 1
295 322
 
296
-        chatStatusStack.addArrangedSubview(chatStatusIcon)
323
+        chatStatusStack.addArrangedSubview(chatStatusSymbolContainer)
297 324
         chatStatusStack.addArrangedSubview(chatStatusLabel)
298 325
 
326
+        syncChatStatusLoadingIndicator(forStatusText: chatStatusLabel.stringValue)
327
+
299 328
         chatDocumentView.translatesAutoresizingMaskIntoConstraints = false
300 329
         chatStack.orientation = .vertical
301 330
         chatStack.spacing = 18
@@ -332,9 +361,22 @@ final class DashboardView: NSView, NSTextFieldDelegate {
332 361
 
333 362
     private func setChatStatusLabel(_ text: String) {
334 363
         chatStatusLabel.stringValue = text
364
+        syncChatStatusLoadingIndicator(forStatusText: text)
335 365
         syncChatStatusSparkleAnimation()
336 366
     }
337 367
 
368
+    private func syncChatStatusLoadingIndicator(forStatusText text: String) {
369
+        let loading = (text == "Thinking...")
370
+        if loading {
371
+            chatStatusIcon.isHidden = true
372
+            chatStatusLoadingIndicator.isHidden = false
373
+            chatStatusLoadingIndicator.startAnimation(nil)
374
+        } else {
375
+            chatStatusLoadingIndicator.stopAnimation(nil)
376
+            chatStatusIcon.isHidden = false
377
+        }
378
+    }
379
+
338 380
     private func isWelcomeHeroVisible() -> Bool {
339 381
         !mainOverlay.isHidden
340 382
     }