Переглянути джерело

Add hover feedback to settings list rows.

Match the sidebar interaction pattern so action, toggle, and popup rows highlight on pointer hover.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 місяць тому
батько
коміт
bce13572cd
1 змінених файлів з 33 додано та 5 видалено
  1. 33 5
      smart_printer/SettingsView.swift

+ 33 - 5
smart_printer/SettingsView.swift

@@ -215,17 +215,45 @@ private final class SettingsIconBadge: NSView, AppearanceRefreshable {
 
 // MARK: - Rows
 
-private class SettingsRowBase: NSView {
-    init(isLast: Bool) {
+private class SettingsRowBase: NSView, AppearanceRefreshable {
+    private var hoverTracker: HoverTracker?
+    private var isHovered = false
+    private let isInteractive: Bool
+
+    init(isLast: Bool, isInteractive: Bool = false) {
+        self.isInteractive = isInteractive
         super.init(frame: .zero)
         translatesAutoresizingMaskIntoConstraints = false
         heightAnchor.constraint(equalToConstant: 56).isActive = true
         if !isLast { addDivider() }
+
+        if isInteractive {
+            wantsLayer = true
+            hoverTracker = HoverTracker(view: self) { [weak self] hovering in
+                self?.setHovered(hovering)
+            }
+        }
     }
 
     @available(*, unavailable)
     required init?(coder: NSCoder) { nil }
 
+    func refreshAppearance() {
+        updateHoverAppearance()
+    }
+
+    private func setHovered(_ hovering: Bool) {
+        isHovered = hovering
+        updateHoverAppearance()
+    }
+
+    private func updateHoverAppearance() {
+        guard isInteractive else { return }
+        animateHover {
+            layer?.backgroundColor = (isHovered ? AppTheme.sidebarHoverBackground : .clear).cgColor
+        }
+    }
+
     func addDivider() {
         let divider = NSBox()
         divider.boxType = .separator
@@ -267,7 +295,7 @@ private class SettingsRowBase: NSView {
 
 private final class SettingsActionRow: SettingsRowBase {
     init(symbolName: String, title: String, isLast: Bool = false, action: @escaping () -> Void) {
-        super.init(isLast: isLast)
+        super.init(isLast: isLast, isInteractive: true)
 
         let badge = SettingsIconBadge(symbolName: symbolName)
         let titleLabel = NSTextField.themeLabel(title, style: .primary, font: AppTheme.mediumFont(size: 15))
@@ -304,7 +332,7 @@ private final class SettingsPopupRow: SettingsRowBase {
 
     init(symbolName: String, title: String, options: [String], selection: String, isLast: Bool = false, onChange: @escaping (String) -> Void) {
         popupTarget = PopupTarget(handler: onChange)
-        super.init(isLast: isLast)
+        super.init(isLast: isLast, isInteractive: true)
 
         let popup = NSPopUpButton()
         popup.bezelStyle = .rounded
@@ -326,7 +354,7 @@ private final class SettingsToggleRow: SettingsRowBase {
 
     init(symbolName: String, title: String, isOn: Bool, isLast: Bool = false, onChange: @escaping (Bool) -> Void) {
         toggleTarget = ToggleTarget(handler: onChange)
-        super.init(isLast: isLast)
+        super.init(isLast: isLast, isInteractive: true)
 
         let toggle = NSSwitch()
         toggle.state = isOn ? .on : .off