Explorar o código

Add subtle meetings refresh blink

Remove refresh-button animation and instead briefly blink the meeting cards; keep refresh disabled while loading.

Made-with: Cursor
huzaifahayat12 hai 3 meses
pai
achega
f1e39c14e0
Modificáronse 1 ficheiros con 40 adicións e 2 borrados
  1. 40 2
      zoom_app/ViewController.swift

+ 40 - 2
zoom_app/ViewController.swift

@@ -53,6 +53,7 @@ class ViewController: NSViewController {
     private weak var meetingsPrevDayButton: NSButton?
     private weak var meetingsNextDayButton: NSButton?
     private weak var meetingsTodayButton: NSButton?
+    private weak var refreshMeetingsButton: NSButton?
     private weak var homeSearchField: NSTextField?
     private weak var homeSearchPill: NSView?
     private var allScheduledMeetings: [ScheduledMeeting] = []
@@ -266,9 +267,37 @@ class ViewController: NSViewController {
     }
 
     @objc private func refreshMeetingsTapped() {
+        Task { @MainActor in
+            self.animateMeetingsRefresh()
+            self.setMeetingsLoadingUI(true)
+        }
         triggerMeetingsRefresh(force: true)
     }
 
+    @MainActor
+    private func setMeetingsLoadingUI(_ loading: Bool) {
+        refreshMeetingsButton?.isEnabled = loading == false
+    }
+
+    @MainActor
+    private func animateMeetingsRefresh() {
+        guard let stack = meetingsListStack, stack.arrangedSubviews.isEmpty == false else { return }
+        let views = stack.arrangedSubviews
+        let dimmed: CGFloat = 0.86
+
+        NSAnimationContext.runAnimationGroup { context in
+            context.duration = 0.07
+            context.timingFunction = CAMediaTimingFunction(name: .linear)
+            views.forEach { $0.animator().alphaValue = dimmed }
+        } completionHandler: {
+            NSAnimationContext.runAnimationGroup { context in
+                context.duration = 0.08
+                context.timingFunction = CAMediaTimingFunction(name: .linear)
+                views.forEach { $0.animator().alphaValue = 1.0 }
+            }
+        }
+    }
+
     private func startMeetingsAutoRefresh() {
         meetingsRefreshTimer?.invalidate()
         // Poll Zoom meetings periodically so newly scheduled meetings appear automatically.
@@ -550,7 +579,15 @@ class ViewController: NSViewController {
     private func loadScheduledMeetings() async {
         if isLoadingMeetings { return }
         isLoadingMeetings = true
-        defer { isLoadingMeetings = false }
+        defer {
+            isLoadingMeetings = false
+            Task { @MainActor in
+                self.setMeetingsLoadingUI(false)
+            }
+        }
+        await MainActor.run {
+            self.setMeetingsLoadingUI(true)
+        }
         do {
             let zoomToken = try await zoomOAuth.validAccessToken(presentingWindow: view.window)
             let zoomMeetings = try await fetchZoomScheduledMeetings(accessToken: zoomToken)
@@ -1101,6 +1138,7 @@ class ViewController: NSViewController {
         refreshMeetingsButton.layer?.cornerRadius = 11
         refreshMeetingsButton.layer?.borderWidth = 1
         refreshMeetingsButton.layer?.borderColor = NSColor.white.withAlphaComponent(0.07).cgColor
+        self.refreshMeetingsButton = refreshMeetingsButton
 
         let contentColumn = NSView()
         contentColumn.translatesAutoresizingMaskIntoConstraints = false
@@ -1193,7 +1231,7 @@ class ViewController: NSViewController {
 
             panel.topAnchor.constraint(equalTo: actions.bottomAnchor, constant: 18),
             panel.centerXAnchor.constraint(equalTo: contentColumn.centerXAnchor),
-            panel.widthAnchor.constraint(equalToConstant: 640),
+            panel.widthAnchor.constraint(equalToConstant: 610),
             panel.leadingAnchor.constraint(greaterThanOrEqualTo: contentColumn.leadingAnchor, constant: 6),
             panel.trailingAnchor.constraint(lessThanOrEqualTo: contentColumn.trailingAnchor, constant: -6),
             panel.heightAnchor.constraint(greaterThanOrEqualToConstant: 280),