소스 검색

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 2 달 전
부모
커밋
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 {
     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
     }