Bladeren bron

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 5 dagen geleden
bovenliggende
commit
f1e39c14e0
1 gewijzigde bestanden met toevoegingen van 40 en 2 verwijderingen
  1. 40 2
      zoom_app/ViewController.swift

+ 40 - 2
zoom_app/ViewController.swift

@@ -53,6 +53,7 @@ class ViewController: NSViewController {
53 53
     private weak var meetingsPrevDayButton: NSButton?
54 54
     private weak var meetingsNextDayButton: NSButton?
55 55
     private weak var meetingsTodayButton: NSButton?
56
+    private weak var refreshMeetingsButton: NSButton?
56 57
     private weak var homeSearchField: NSTextField?
57 58
     private weak var homeSearchPill: NSView?
58 59
     private var allScheduledMeetings: [ScheduledMeeting] = []
@@ -266,9 +267,37 @@ class ViewController: NSViewController {
266 267
     }
267 268
 
268 269
     @objc private func refreshMeetingsTapped() {
270
+        Task { @MainActor in
271
+            self.animateMeetingsRefresh()
272
+            self.setMeetingsLoadingUI(true)
273
+        }
269 274
         triggerMeetingsRefresh(force: true)
270 275
     }
271 276
 
277
+    @MainActor
278
+    private func setMeetingsLoadingUI(_ loading: Bool) {
279
+        refreshMeetingsButton?.isEnabled = loading == false
280
+    }
281
+
282
+    @MainActor
283
+    private func animateMeetingsRefresh() {
284
+        guard let stack = meetingsListStack, stack.arrangedSubviews.isEmpty == false else { return }
285
+        let views = stack.arrangedSubviews
286
+        let dimmed: CGFloat = 0.86
287
+
288
+        NSAnimationContext.runAnimationGroup { context in
289
+            context.duration = 0.07
290
+            context.timingFunction = CAMediaTimingFunction(name: .linear)
291
+            views.forEach { $0.animator().alphaValue = dimmed }
292
+        } completionHandler: {
293
+            NSAnimationContext.runAnimationGroup { context in
294
+                context.duration = 0.08
295
+                context.timingFunction = CAMediaTimingFunction(name: .linear)
296
+                views.forEach { $0.animator().alphaValue = 1.0 }
297
+            }
298
+        }
299
+    }
300
+
272 301
     private func startMeetingsAutoRefresh() {
273 302
         meetingsRefreshTimer?.invalidate()
274 303
         // Poll Zoom meetings periodically so newly scheduled meetings appear automatically.
@@ -550,7 +579,15 @@ class ViewController: NSViewController {
550 579
     private func loadScheduledMeetings() async {
551 580
         if isLoadingMeetings { return }
552 581
         isLoadingMeetings = true
553
-        defer { isLoadingMeetings = false }
582
+        defer {
583
+            isLoadingMeetings = false
584
+            Task { @MainActor in
585
+                self.setMeetingsLoadingUI(false)
586
+            }
587
+        }
588
+        await MainActor.run {
589
+            self.setMeetingsLoadingUI(true)
590
+        }
554 591
         do {
555 592
             let zoomToken = try await zoomOAuth.validAccessToken(presentingWindow: view.window)
556 593
             let zoomMeetings = try await fetchZoomScheduledMeetings(accessToken: zoomToken)
@@ -1101,6 +1138,7 @@ class ViewController: NSViewController {
1101 1138
         refreshMeetingsButton.layer?.cornerRadius = 11
1102 1139
         refreshMeetingsButton.layer?.borderWidth = 1
1103 1140
         refreshMeetingsButton.layer?.borderColor = NSColor.white.withAlphaComponent(0.07).cgColor
1141
+        self.refreshMeetingsButton = refreshMeetingsButton
1104 1142
 
1105 1143
         let contentColumn = NSView()
1106 1144
         contentColumn.translatesAutoresizingMaskIntoConstraints = false
@@ -1193,7 +1231,7 @@ class ViewController: NSViewController {
1193 1231
 
1194 1232
             panel.topAnchor.constraint(equalTo: actions.bottomAnchor, constant: 18),
1195 1233
             panel.centerXAnchor.constraint(equalTo: contentColumn.centerXAnchor),
1196
-            panel.widthAnchor.constraint(equalToConstant: 640),
1234
+            panel.widthAnchor.constraint(equalToConstant: 610),
1197 1235
             panel.leadingAnchor.constraint(greaterThanOrEqualTo: contentColumn.leadingAnchor, constant: 6),
1198 1236
             panel.trailingAnchor.constraint(lessThanOrEqualTo: contentColumn.trailingAnchor, constant: -6),
1199 1237
             panel.heightAnchor.constraint(greaterThanOrEqualToConstant: 280),