Quellcode durchsuchen

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 vor 2 Monaten
Ursprung
Commit
1e6c0fde28
1 geänderte Dateien mit 43 neuen und 1 gelöschten Zeilen
  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 {
     private let findJobsCTAChrome = HoverableView()
     private var findJobsCTAGradientLayer: CAGradientLayer?
     private let chatStatusStack = NSStackView()
+    private let chatStatusSymbolContainer = NSView()
     private let chatStatusIcon = NSImageView()
+    private let chatStatusLoadingIndicator = NSProgressIndicator()
     private let chatStatusLabel = NSTextField(labelWithString: "Opening the vault...")
     private let chatScrollView = NSScrollView()
     private let chatDocumentView = JobListingsDocumentView()
@@ -282,20 +284,47 @@ final class DashboardView: NSView, NSTextFieldDelegate {
         chatStatusStack.alignment = .centerX
         chatStatusStack.translatesAutoresizingMaskIntoConstraints = false
 
+        chatStatusSymbolContainer.translatesAutoresizingMaskIntoConstraints = false
+
         chatStatusIcon.translatesAutoresizingMaskIntoConstraints = false
         chatStatusIcon.wantsLayer = true
         chatStatusIcon.symbolConfiguration = NSImage.SymbolConfiguration(pointSize: 36, weight: .regular)
         chatStatusIcon.image = NSImage(systemSymbolName: "sparkles", accessibilityDescription: "Assistant status")
         chatStatusIcon.contentTintColor = Theme.brandBlue
 
+        chatStatusLoadingIndicator.translatesAutoresizingMaskIntoConstraints = false
+        chatStatusLoadingIndicator.style = .spinning
+        chatStatusLoadingIndicator.isIndeterminate = true
+        chatStatusLoadingIndicator.isDisplayedWhenStopped = false
+        chatStatusLoadingIndicator.controlSize = .regular
+        chatStatusLoadingIndicator.isHidden = true
+        chatStatusLoadingIndicator.setAccessibilityRole(.progressIndicator)
+        chatStatusLoadingIndicator.setAccessibilityLabel("Searching for jobs")
+
+        chatStatusSymbolContainer.addSubview(chatStatusIcon)
+        chatStatusSymbolContainer.addSubview(chatStatusLoadingIndicator)
+
+        NSLayoutConstraint.activate([
+            chatStatusSymbolContainer.widthAnchor.constraint(equalToConstant: 40),
+            chatStatusSymbolContainer.heightAnchor.constraint(equalToConstant: 40),
+            chatStatusIcon.centerXAnchor.constraint(equalTo: chatStatusSymbolContainer.centerXAnchor),
+            chatStatusIcon.centerYAnchor.constraint(equalTo: chatStatusSymbolContainer.centerYAnchor),
+            chatStatusLoadingIndicator.centerXAnchor.constraint(equalTo: chatStatusSymbolContainer.centerXAnchor),
+            chatStatusLoadingIndicator.centerYAnchor.constraint(equalTo: chatStatusSymbolContainer.centerYAnchor),
+            chatStatusLoadingIndicator.widthAnchor.constraint(equalToConstant: 32),
+            chatStatusLoadingIndicator.heightAnchor.constraint(equalToConstant: 32)
+        ])
+
         chatStatusLabel.font = .systemFont(ofSize: 20, weight: .semibold)
         chatStatusLabel.textColor = Theme.primaryText
         chatStatusLabel.alignment = .center
         chatStatusLabel.maximumNumberOfLines = 1
 
-        chatStatusStack.addArrangedSubview(chatStatusIcon)
+        chatStatusStack.addArrangedSubview(chatStatusSymbolContainer)
         chatStatusStack.addArrangedSubview(chatStatusLabel)
 
+        syncChatStatusLoadingIndicator(forStatusText: chatStatusLabel.stringValue)
+
         chatDocumentView.translatesAutoresizingMaskIntoConstraints = false
         chatStack.orientation = .vertical
         chatStack.spacing = 18
@@ -332,9 +361,22 @@ final class DashboardView: NSView, NSTextFieldDelegate {
 
     private func setChatStatusLabel(_ text: String) {
         chatStatusLabel.stringValue = text
+        syncChatStatusLoadingIndicator(forStatusText: text)
         syncChatStatusSparkleAnimation()
     }
 
+    private func syncChatStatusLoadingIndicator(forStatusText text: String) {
+        let loading = (text == "Thinking...")
+        if loading {
+            chatStatusIcon.isHidden = true
+            chatStatusLoadingIndicator.isHidden = false
+            chatStatusLoadingIndicator.startAnimation(nil)
+        } else {
+            chatStatusLoadingIndicator.stopAnimation(nil)
+            chatStatusIcon.isHidden = false
+        }
+    }
+
     private func isWelcomeHeroVisible() -> Bool {
         !mainOverlay.isHidden
     }