From 94a3d76af9693c597ae49dc7a00aa305ace3e0bf Mon Sep 17 00:00:00 2001 From: tigerenwork Date: Mon, 29 Jun 2026 01:01:01 +0800 Subject: [PATCH] fix: badge shows active count, floating widget shows priorities, record URL deep link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Menu bar badge and floating widget now show total active bugs count (was showing unseen-only count). Unseen dot still works independently in the bug list rows. 2. Floating widget now shows priority breakdown: 🐜 12 🔴3 🟡4 🔵2 ⚪3 Each priority gets a colored dot + count. Only non-zero priorities shown. 3. Fixed Feishu record URL format: now uses query-parameter deep link /base/{appToken}?table={tableId}&record={recordId} instead of path segments, which opens the specific record row directly in Feishu. Co-Authored-By: Claude --- Sources/AppDelegate.swift | 2 +- Sources/Services/PollerService.swift | 2 +- Sources/Utils/URL+Feishu.swift | 3 +- .../FloatingWidget/FloatingWidgetWindow.swift | 47 ++++++++++++++----- Sources/Views/MenuBar/BugListPopover.swift | 4 +- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/Sources/AppDelegate.swift b/Sources/AppDelegate.swift index d967f6e..bf03572 100644 --- a/Sources/AppDelegate.swift +++ b/Sources/AppDelegate.swift @@ -38,7 +38,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate { button.action = #selector(togglePopover) button.target = self } - updateBadge(count: bugStore.unseenActiveCount) + updateBadge(count: bugStore.activeBugs.count) } private func setupPopover() { diff --git a/Sources/Services/PollerService.swift b/Sources/Services/PollerService.swift index 39d1fc4..d6839eb 100644 --- a/Sources/Services/PollerService.swift +++ b/Sources/Services/PollerService.swift @@ -76,7 +76,7 @@ final class PollerService { await MainActor.run { bugStore.update(with: bugs) bugStore.setLoading(false) - AppDelegate.shared?.updateBadge(count: bugStore.unseenActiveCount) + AppDelegate.shared?.updateBadge(count: bugStore.activeBugs.count) } } catch FeishuError.unauthorized { await MainActor.run { diff --git a/Sources/Utils/URL+Feishu.swift b/Sources/Utils/URL+Feishu.swift index aa2b223..b0001b8 100644 --- a/Sources/Utils/URL+Feishu.swift +++ b/Sources/Utils/URL+Feishu.swift @@ -7,7 +7,8 @@ enum FeishuURLBuilder { tableId: String, recordId: String ) -> URL { - URL(string: "https://\(baseDomain)/base/\(appToken)/table/\(tableId)/record/\(recordId)")! + // Feishu Bitable record deep link: uses query parameters + URL(string: "https://\(baseDomain)/base/\(appToken)?table=\(tableId)&record=\(recordId)")! } static func tableURL(baseDomain: String, appToken: String) -> URL { diff --git a/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift b/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift index 36f1bd3..7d2d6bd 100644 --- a/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift +++ b/Sources/Views/FloatingWidget/FloatingWidgetWindow.swift @@ -4,7 +4,7 @@ import SwiftUI final class FloatingWidgetWindow: NSPanel { init() { super.init( - contentRect: NSRect(x: 0, y: 0, width: 80, height: 60), + contentRect: NSRect(x: 0, y: 0, width: 140, height: 70), styleMask: [.borderless, .nonactivatingPanel], backing: .buffered, defer: false @@ -35,22 +35,47 @@ final class FloatingWidgetWindow: NSPanel { struct FloatingWidgetView: View { @State private var bugStore = BugStore.shared + private var priorityCounts: [(BugPriority, Int)] { + let active = bugStore.activeBugs + return BugPriority.allCases + .filter { $0 != .unknown } + .map { priority in + (priority, active.filter { $0.priority == priority }.count) + } + .filter { $0.1 > 0 } + } + var body: some View { Button { AppDelegate.shared?.togglePopover() } label: { - HStack(spacing: 6) { - Image(systemName: "ant.fill") - .font(.title3) - Text("\(bugStore.unseenActiveCount)") - .font(.title2) - .fontWeight(.bold) - .contentTransition(.numericText()) + VStack(spacing: 4) { + HStack(spacing: 4) { + Image(systemName: "ant.fill") + .font(.caption) + Text("\(bugStore.activeBugs.count)") + .font(.title3) + .fontWeight(.bold) + } + if !priorityCounts.isEmpty { + HStack(spacing: 6) { + ForEach(priorityCounts, id: \.0) { priority, count in + HStack(spacing: 2) { + Circle() + .fill(priority.color) + .frame(width: 6, height: 6) + Text("\(count)") + .font(.caption2) + .fontWeight(.medium) + } + } + } + } } - .padding(.horizontal, 12) - .padding(.vertical, 8) + .padding(.horizontal, 14) + .padding(.vertical, 10) .background( - RoundedRectangle(cornerRadius: 12) + RoundedRectangle(cornerRadius: 14) .fill(.ultraThinMaterial) .shadow(color: .black.opacity(0.15), radius: 8, x: 0, y: 4) ) diff --git a/Sources/Views/MenuBar/BugListPopover.swift b/Sources/Views/MenuBar/BugListPopover.swift index 6b73a2c..18215d6 100644 --- a/Sources/Views/MenuBar/BugListPopover.swift +++ b/Sources/Views/MenuBar/BugListPopover.swift @@ -35,7 +35,7 @@ struct BugListPopover: View { } Button("Mark all seen") { bugStore.markAllSeen() - AppDelegate.shared?.updateBadge(count: bugStore.unseenActiveCount) + AppDelegate.shared?.updateBadge(count: bugStore.activeBugs.count) } .font(.caption) } @@ -62,7 +62,7 @@ struct BugListPopover: View { .onTapGesture { openInFeishu(bug) bugStore.markSeen(bug.id) - AppDelegate.shared?.updateBadge(count: bugStore.unseenActiveCount) + AppDelegate.shared?.updateBadge(count: bugStore.activeBugs.count) } Divider().padding(.leading, 44) }