Преглед изворни кода

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
     private let findJobsCTAChrome = HoverableView()
82
     private let findJobsCTAChrome = HoverableView()
83
     private var findJobsCTAGradientLayer: CAGradientLayer?
83
     private var findJobsCTAGradientLayer: CAGradientLayer?
84
     private let chatStatusStack = NSStackView()
84
     private let chatStatusStack = NSStackView()
85
+    private let chatStatusSymbolContainer = NSView()
85
     private let chatStatusIcon = NSImageView()
86
     private let chatStatusIcon = NSImageView()
87
+    private let chatStatusLoadingIndicator = NSProgressIndicator()
86
     private let chatStatusLabel = NSTextField(labelWithString: "Opening the vault...")
88
     private let chatStatusLabel = NSTextField(labelWithString: "Opening the vault...")
87
     private let chatScrollView = NSScrollView()
89
     private let chatScrollView = NSScrollView()
88
     private let chatDocumentView = JobListingsDocumentView()
90
     private let chatDocumentView = JobListingsDocumentView()
@@ -282,20 +284,47 @@ final class DashboardView: NSView, NSTextFieldDelegate {
282
         chatStatusStack.alignment = .centerX
284
         chatStatusStack.alignment = .centerX
283
         chatStatusStack.translatesAutoresizingMaskIntoConstraints = false
285
         chatStatusStack.translatesAutoresizingMaskIntoConstraints = false
284
 
286
 
287
+        chatStatusSymbolContainer.translatesAutoresizingMaskIntoConstraints = false
288
+
285
         chatStatusIcon.translatesAutoresizingMaskIntoConstraints = false
289
         chatStatusIcon.translatesAutoresizingMaskIntoConstraints = false
286
         chatStatusIcon.wantsLayer = true
290
         chatStatusIcon.wantsLayer = true
287
         chatStatusIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 36, weight: .regular)
291
         chatStatusIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 36, weight: .regular)
288
         chatStatusIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: "Assistant status")
292
         chatStatusIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: "Assistant status")
289
         chatStatusIcon.contentTintColor = Theme.brandBlue
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
         chatStatusLabel.font = .systemFont(ofSize: 20, weight: .semibold)
318
         chatStatusLabel.font = .systemFont(ofSize: 20, weight: .semibold)
292
         chatStatusLabel.textColor = Theme.primaryText
319
         chatStatusLabel.textColor = Theme.primaryText
293
         chatStatusLabel.alignment = .center
320
         chatStatusLabel.alignment = .center
294
         chatStatusLabel.maximumNumberOfLines = 1
321
         chatStatusLabel.maximumNumberOfLines = 1
295
 
322
 
296
-        chatStatusStack.addArrangedSubview(chatStatusIcon)
323
+        chatStatusStack.addArrangedSubview(chatStatusSymbolContainer)
297
         chatStatusStack.addArrangedSubview(chatStatusLabel)
324
         chatStatusStack.addArrangedSubview(chatStatusLabel)
298
 
325
 
326
+        syncChatStatusLoadingIndicator(forStatusText: chatStatusLabel.stringValue)
327
+
299
         chatDocumentView.translatesAutoresizingMaskIntoConstraints = false
328
         chatDocumentView.translatesAutoresizingMaskIntoConstraints = false
300
         chatStack.orientation = .vertical
329
         chatStack.orientation = .vertical
301
         chatStack.spacing = 18
330
         chatStack.spacing = 18
@@ -332,9 +361,22 @@ final class DashboardView: NSView, NSTextFieldDelegate {
332
 
361
 
333
     private func setChatStatusLabel(_ text: String) {
362
     private func setChatStatusLabel(_ text: String) {
334
         chatStatusLabel.stringValue = text
363
         chatStatusLabel.stringValue = text
364
+        syncChatStatusLoadingIndicator(forStatusText: text)
335
         syncChatStatusSparkleAnimation()
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
     private func isWelcomeHeroVisible() -> Bool {
380
     private func isWelcomeHeroVisible() -> Bool {
339
         !mainOverlay.isHidden
381
         !mainOverlay.isHidden
340
     }
382
     }