fix: badge shows active count, floating widget shows priorities, record URL deep link

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 <noreply@anthropic.com>
This commit is contained in:
tigerenwork 2026-06-29 01:01:01 +08:00
parent 723c50fc9d
commit 94a3d76af9
5 changed files with 42 additions and 16 deletions

View File

@ -38,7 +38,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
button.action = #selector(togglePopover) button.action = #selector(togglePopover)
button.target = self button.target = self
} }
updateBadge(count: bugStore.unseenActiveCount) updateBadge(count: bugStore.activeBugs.count)
} }
private func setupPopover() { private func setupPopover() {

View File

@ -76,7 +76,7 @@ final class PollerService {
await MainActor.run { await MainActor.run {
bugStore.update(with: bugs) bugStore.update(with: bugs)
bugStore.setLoading(false) bugStore.setLoading(false)
AppDelegate.shared?.updateBadge(count: bugStore.unseenActiveCount) AppDelegate.shared?.updateBadge(count: bugStore.activeBugs.count)
} }
} catch FeishuError.unauthorized { } catch FeishuError.unauthorized {
await MainActor.run { await MainActor.run {

View File

@ -7,7 +7,8 @@ enum FeishuURLBuilder {
tableId: String, tableId: String,
recordId: String recordId: String
) -> URL { ) -> 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 { static func tableURL(baseDomain: String, appToken: String) -> URL {

View File

@ -4,7 +4,7 @@ import SwiftUI
final class FloatingWidgetWindow: NSPanel { final class FloatingWidgetWindow: NSPanel {
init() { init() {
super.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], styleMask: [.borderless, .nonactivatingPanel],
backing: .buffered, backing: .buffered,
defer: false defer: false
@ -35,22 +35,47 @@ final class FloatingWidgetWindow: NSPanel {
struct FloatingWidgetView: View { struct FloatingWidgetView: View {
@State private var bugStore = BugStore.shared @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 { var body: some View {
Button { Button {
AppDelegate.shared?.togglePopover() AppDelegate.shared?.togglePopover()
} label: { } label: {
HStack(spacing: 6) { VStack(spacing: 4) {
HStack(spacing: 4) {
Image(systemName: "ant.fill") Image(systemName: "ant.fill")
.font(.caption)
Text("\(bugStore.activeBugs.count)")
.font(.title3) .font(.title3)
Text("\(bugStore.unseenActiveCount)")
.font(.title2)
.fontWeight(.bold) .fontWeight(.bold)
.contentTransition(.numericText())
} }
.padding(.horizontal, 12) if !priorityCounts.isEmpty {
.padding(.vertical, 8) 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, 14)
.padding(.vertical, 10)
.background( .background(
RoundedRectangle(cornerRadius: 12) RoundedRectangle(cornerRadius: 14)
.fill(.ultraThinMaterial) .fill(.ultraThinMaterial)
.shadow(color: .black.opacity(0.15), radius: 8, x: 0, y: 4) .shadow(color: .black.opacity(0.15), radius: 8, x: 0, y: 4)
) )

View File

@ -35,7 +35,7 @@ struct BugListPopover: View {
} }
Button("Mark all seen") { Button("Mark all seen") {
bugStore.markAllSeen() bugStore.markAllSeen()
AppDelegate.shared?.updateBadge(count: bugStore.unseenActiveCount) AppDelegate.shared?.updateBadge(count: bugStore.activeBugs.count)
} }
.font(.caption) .font(.caption)
} }
@ -62,7 +62,7 @@ struct BugListPopover: View {
.onTapGesture { .onTapGesture {
openInFeishu(bug) openInFeishu(bug)
bugStore.markSeen(bug.id) bugStore.markSeen(bug.id)
AppDelegate.shared?.updateBadge(count: bugStore.unseenActiveCount) AppDelegate.shared?.updateBadge(count: bugStore.activeBugs.count)
} }
Divider().padding(.leading, 44) Divider().padding(.leading, 44)
} }