feat: 接入消息未读数、全部已读与首页红点角标同步。

固定消息中心为首页入口,并在推送到达、已读后刷新桌面角标。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-21 18:02:43 +08:00
parent e7f1d777dd
commit caeeb9a1cf
18 changed files with 748 additions and 37 deletions

View File

@ -17,18 +17,23 @@ final class HomeCommonMenuStore {
/// URI
func savedCommonURIs(accountScope: String, roleCode: String) -> [String] {
guard let key = storageKey(accountScope: accountScope, roleCode: roleCode) else { return [] }
return defaults.stringArray(forKey: key) ?? []
let saved = defaults.stringArray(forKey: key) ?? []
let sanitized = saved.filter(HomeMenuCatalog.isCustomizable(uri:))
if sanitized != saved {
defaults.set(sanitized, forKey: key)
}
return sanitized
}
/// URI
func saveCommonURIs(_ uris: [String], accountScope: String, roleCode: String) {
guard let key = storageKey(accountScope: accountScope, roleCode: roleCode) else { return }
defaults.set(uris, forKey: key)
defaults.set(uris.filter(HomeMenuCatalog.isCustomizable(uri:)), forKey: key)
}
/// URI 4
static func defaultCommonURIs(from permissions: [HomePermissionItem]) -> [String] {
let uris = permissions.map(\.uri)
let uris = permissions.map(\.uri).filter(HomeMenuCatalog.isCustomizable(uri:))
return uris.count > 4 ? Array(uris.prefix(4)) : uris
}
@ -51,8 +56,9 @@ final class HomeCommonMenuStore {
commonURIs: [String]
) -> (common: [HomeMenuItem], more: [HomeMenuItem]) {
let commonSet = Set(commonURIs)
let common = allMenus.filter { commonSet.contains($0.uri) }
let more = allMenus.filter { !commonSet.contains($0.uri) }
let customizableMenus = allMenus.filter { HomeMenuCatalog.isCustomizable(uri: $0.uri) }
let common = customizableMenus.filter { commonSet.contains($0.uri) }
let more = customizableMenus.filter { !commonSet.contains($0.uri) }
return (common, more)
}

View File

@ -8,6 +8,8 @@ import Foundation
/// catalog permission URI
enum HomeMenuCatalog {
private static let fixedHomeEntryURIs: Set<String> = ["message_center"]
/// Android `Constants.menuList`
static let allItems: [HomeMenuItem] = [
HomeMenuItem(uri: "space_settings", title: "空间设置", iconName: "home_menu_space"),
@ -45,6 +47,7 @@ enum HomeMenuCatalog {
///
static func visibleMenus(from permissions: [HomePermissionItem]) -> [HomeMenuItem] {
permissions.compactMap { permission in
guard isCustomizable(uri: permission.uri) else { return nil }
guard let catalog = allItems.first(where: { $0.uri == permission.uri }) else { return nil }
return HomeMenuItem(
uri: catalog.uri,
@ -59,4 +62,9 @@ enum HomeMenuCatalog {
static func item(for uri: String) -> HomeMenuItem? {
allItems.first { $0.uri == uri }
}
///
static func isCustomizable(uri: String) -> Bool {
!fixedHomeEntryURIs.contains(uri)
}
}

View File

@ -48,6 +48,7 @@ final class AllFunctionsViewModel {
///
func addToCommon(_ menu: HomeMenuItem) {
guard HomeMenuCatalog.isCustomizable(uri: menu.uri) else { return }
guard !commonMenus.contains(where: { $0.uri == menu.uri }) else { return }
commonMenus.append(menu)
moreMenus.removeAll { $0.uri == menu.uri }

View File

@ -25,6 +25,7 @@ final class HomeViewModel {
private(set) var reportTimeText = ""
private(set) var isLocationReporting = false
private(set) var needsPermissionReload = false
private(set) var unreadMessageCount = 0
var onStateChange: (() -> Void)?
var onShowMessage: ((String) -> Void)?
@ -65,6 +66,7 @@ final class HomeViewModel {
var isOnline: Bool { locationStateStore.isOnline }
var countdownDisplayText: String { locationStateStore.countdownDisplayText }
var reminderMinutes: Int { locationStateStore.reminderMinutes }
var hasUnreadMessages: Bool { unreadMessageCount > 0 }
/// 线
func initialize(api: HomeAPI) async {
@ -76,6 +78,28 @@ final class HomeViewModel {
///
func markNeedsPermissionReload() {
needsPermissionReload = true
unreadMessageCount = 0
}
/// `true`
func refreshUnreadMessageStatus(api: any MessageCenterServing) async -> Bool {
do {
let response = try await api.unreadCount()
unreadMessageCount = response.unreadCount
notifyStateChange()
return true
} catch is CancellationError {
return false
} catch {
//
return false
}
}
/// 使
func updateUnreadMessageCount(_ count: Int) {
unreadMessageCount = max(count, 0)
notifyStateChange()
}
///