Gmail notifier run on macOS menu bar.
- Swift 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| Config | ||
| docs | ||
| Magpie | ||
| Magpie.xcodeproj | ||
| MagpieTests | ||
| .gitignore | ||
| AGENTS.md | ||
| README.md | ||
Magpie
macOS 選單列 App:監看多個 Gmail 帳號未讀數,以指定瀏覽器開啟 Gmail。
- Swift 6、SwiftUI + AppKit、macOS 14+,無外部相依
- Google OAuth 2.0(PKCE + loopback),token 存 Keychain
- Gmail API:
labels.list探索標籤、labels.get取未讀數,只需gmail.labelsscope
設定
Google Cloud 與 client ID 設定見 docs/google-oauth-setup.md。 尚未實作與改進項目見 docs/roadmap.md。 未設定 client ID 時以示範模式執行(假帳號、不保存)。
結構
Config/ xcconfig、Info.plist(OAuth client ID 注入)
Magpie/
App/ 進入點、AppEnvironment(composition root / DI)
Models/ Account、GmailLabel、LabelCatalog、AccountStatus、UnreadCount、Browser、OAuthToken
Services/ 外部相依的 protocol 與實作(Keychain、UserDefaults、檔案、NSWorkspace、Gmail HTTP)
OAuth/ GoogleOAuthManager、PKCE、LoopbackRedirectServer、IDToken
Mock/ MockGmailAPIClient、MockOAuthManager、SampleData
Domain/ AccountManager、LabelManager(actor)、LabelIndex、GmailRequestExecutor、RefreshScheduler(actor)
ViewModels/ MenuBarViewModel、SettingsViewModel、LabelPickerModel
Views/ MenuBar/、Settings/、Shared/
MagpieTests/ Swift Testing 單元測試與替身
資料流:View → ViewModel → AccountManager → OAuthManager / GmailAPIClient / SettingsStore / LabelCatalogStore。
標籤與未讀數
- 標籤以 Gmail label ID 識別;名稱只是快取,改名後同步更新,不影響監看。
- 探索(
labels.list,無分頁)與輪詢(labels.get)分開:- 探索:新增帳號、設定中尚無清單、使用者按重新整理、清單超過 1 小時或上次失敗時。結果存 Application Support JSON。
- 輪詢:只請求收件匣 + 監看標籤(500 個標籤監看 5 個 → 每輪 6 個請求)。預設每 5 分鐘;資料仍新時略過。
- 收件匣一律監看。選單列總數只加總各帳號收件匣,不加監看標籤,避免重複計算。預設以會話(
threadsUnread)計。 - 清單中找不到的監看標籤標示「無法使用」並停止輪詢;只在成功取得完整清單後判定,同名新標籤不會被誤認。
- 每帳號最多 4 個並行請求;同帳號刷新不重疊。5xx/429/限流 403/網路錯誤以指數退避 + jitter 重試(最多 3 次,遵守
Retry-After);401 先更新 token 重試一次。失敗時保留上次數字並標示過時。 - 系統睡眠時暫停排程,喚醒、回到前景或開啟選單時補刷新過時資料。
建置與測試
xcodebuild -project Magpie.xcodeproj -scheme Magpie -destination 'platform=macOS' test
Xcode 專案使用資料夾同步群組,新增檔案不需改 project.pbxproj。