Clear the app badge when the inbox is read !119
merged
merged by cmc on 2026-09-21 01:25 UTC
· krz/gitbay-ios:badge-clear into main
3 files changed, +32 −1
Layout: unified · split
gitbay/Account/NotificationsViewModel.swift
+7
| @@ -124,6 +124,13 @@ final class NotificationsViewModel { |
| 124 | |
124 | |
| 125 | func markAllRead() async { |
125 | func markAllRead() async { |
| 126 | await perform(["notifications", "read", "--all"]) |
126 | await perform(["notifications", "read", "--all"]) |
| |
127 | // Nothing else tells iOS the count dropped: a push sets the badge |
| |
128 | // on arrival and no one lowers it, so it would sit at whatever the |
| |
129 | // last one said. Zero is exact here. Marking a single row read has |
| |
130 | // no reliable count to work from — the inbox list is paged, so the |
| |
131 | // rows in hand are not the unread total — and is left to the |
| |
132 | // dashboard's resync. |
| |
133 | await setAppBadge(0) |
| 127 | } |
134 | } |
| 128 | |
135 | |
| 129 | func loadPushSettings() async { |
136 | func loadPushSettings() async { |
gitbay/Dashboard/DashboardViewModel.swift
+6 −1
| @@ -19,7 +19,12 @@ final class DashboardViewModel { |
| 19 | |
19 | |
| 20 | func load() async { |
20 | func load() async { |
| 21 | do { |
21 | do { |
| 22 | state = .loaded(try await client.read(["dashboard"], as: DashboardData.self)) |
22 | let data = try await client.read(["dashboard"], as: DashboardData.self) |
| |
23 | state = .loaded(data) |
| |
24 | // The authoritative resync. A push sets the badge on arrival |
| |
25 | // and nothing lowers it afterwards, so this is what corrects |
| |
26 | // it — on every app open, against the account you are in. |
| |
27 | await setAppBadge(data.unread) |
| 23 | } catch { |
28 | } catch { |
| 24 | state = .from(error) |
29 | state = .from(error) |
| 25 | } |
30 | } |
gitbay/Push/AppBadge.swift
added
+19
| @@ -0,0 +1,19 @@ |
| |
1 | import UserNotifications |
| |
2 | |
| |
3 | /// Sets the app icon badge to an unread count. |
| |
4 | /// |
| |
5 | /// A push carries `aps.badge` and iOS applies it on arrival, so the badge |
| |
6 | /// is right the moment a notification lands. It is not right afterwards: |
| |
7 | /// nothing tells iOS the count dropped when the inbox is read in the app, |
| |
8 | /// and the number sits there until the next push. These calls close that. |
| |
9 | /// |
| |
10 | /// The value is always the active account's unread count. The badge is |
| |
11 | /// per-device and unread is per-account, so with two accounts signed in |
| |
12 | /// the last writer wins — a push for one account, then a dashboard load |
| |
13 | /// on the other, disagree. Exact for a single account. |
| |
14 | /// |
| |
15 | /// Failures are ignored. A badge that did not take is not worth telling |
| |
16 | /// anyone about, and the next writer corrects it. |
| |
17 | func setAppBadge(_ count: Int) async { |
| |
18 | try? await UNUserNotificationCenter.current().setBadgeCount(max(0, count)) |
| |
19 | } |