feat: 接入消息未读数、全部已读与首页红点角标同步。
固定消息中心为首页入口,并在推送到达、已读后刷新桌面角标。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -90,10 +90,10 @@ final class HomeViewModelTests: XCTestCase {
|
||||
let menuStore = HomeCommonMenuStore(defaults: defaults)
|
||||
appStore.permissions.savePermissionItems([
|
||||
HomePermissionItem(id: "1", name: "钱包", uri: "wallet"),
|
||||
HomePermissionItem(id: "2", name: "云盘", uri: "cloud_management"),
|
||||
HomePermissionItem(id: "3", name: "任务", uri: "task_management"),
|
||||
HomePermissionItem(id: "4", name: "设置", uri: "system_settings"),
|
||||
HomePermissionItem(id: "5", name: "消息", uri: "message_center"),
|
||||
HomePermissionItem(id: "2", name: "消息", uri: "message_center"),
|
||||
HomePermissionItem(id: "3", name: "云盘", uri: "cloud_management"),
|
||||
HomePermissionItem(id: "4", name: "任务", uri: "task_management"),
|
||||
HomePermissionItem(id: "5", name: "设置", uri: "system_settings"),
|
||||
])
|
||||
let viewModel = HomeViewModel(appStore: appStore, commonMenuStore: menuStore)
|
||||
|
||||
@ -231,6 +231,50 @@ final class HomeViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(session.requests.count, 1)
|
||||
}
|
||||
|
||||
func testUnreadMessageStatusUsesCountEndpointAndUpdatesBadgeState() async {
|
||||
let api = HomeMessageCenterAPIMock()
|
||||
api.unreadCountResponses = [
|
||||
MessageUnreadCountResponse(unreadCount: 9),
|
||||
MessageUnreadCountResponse(unreadCount: 0),
|
||||
]
|
||||
let viewModel = HomeViewModel(appStore: appStore)
|
||||
|
||||
await viewModel.refreshUnreadMessageStatus(api: api)
|
||||
XCTAssertTrue(viewModel.hasUnreadMessages)
|
||||
XCTAssertEqual(viewModel.unreadMessageCount, 9)
|
||||
|
||||
await viewModel.refreshUnreadMessageStatus(api: api)
|
||||
XCTAssertFalse(viewModel.hasUnreadMessages)
|
||||
XCTAssertEqual(viewModel.unreadMessageCount, 0)
|
||||
XCTAssertEqual(api.unreadCountCallCount, 2)
|
||||
}
|
||||
|
||||
func testScenicHeaderMessageButtonShowsUnreadStateAndHandlesTap() throws {
|
||||
let headerView = HomeScenicHeaderView(frame: CGRect(x: 0, y: 0, width: 390, height: 100))
|
||||
var tapCount = 0
|
||||
headerView.onMessageTap = { tapCount += 1 }
|
||||
|
||||
headerView.apply(scenicName: "测试景区", hasUnreadMessages: true)
|
||||
headerView.layoutIfNeeded()
|
||||
|
||||
let button = try XCTUnwrap(
|
||||
findSubview(in: headerView) { $0.accessibilityIdentifier == "home_message_button" } as? UIButton
|
||||
)
|
||||
let unreadDot = try XCTUnwrap(
|
||||
findSubview(in: headerView) { $0.accessibilityIdentifier == "home_message_unread_dot" }
|
||||
)
|
||||
XCTAssertEqual(button.bounds.size, CGSize(width: 44, height: 44))
|
||||
XCTAssertEqual(button.accessibilityLabel, "消息中心,有未读消息")
|
||||
XCTAssertFalse(unreadDot.isHidden)
|
||||
|
||||
button.sendActions(for: .touchUpInside)
|
||||
XCTAssertEqual(tapCount, 1)
|
||||
|
||||
headerView.apply(scenicName: "测试景区", hasUnreadMessages: false)
|
||||
XCTAssertEqual(button.accessibilityLabel, "消息中心")
|
||||
XCTAssertTrue(unreadDot.isHidden)
|
||||
}
|
||||
|
||||
func testRefreshLocalDisplayStateClearsWhenNameMissing() {
|
||||
appStore.session.currentScenicId = 10
|
||||
appStore.session.currentScenicName = ""
|
||||
@ -283,6 +327,45 @@ final class HomeViewModelTests: XCTestCase {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func findSubview(in view: UIView, matching predicate: (UIView) -> Bool) -> UIView? {
|
||||
if predicate(view) {
|
||||
return view
|
||||
}
|
||||
for subview in view.subviews {
|
||||
if let match = findSubview(in: subview, matching: predicate) {
|
||||
return match
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// 首页未读消息查询替身。
|
||||
@MainActor
|
||||
private final class HomeMessageCenterAPIMock: MessageCenterServing {
|
||||
var unreadCountResponses: [MessageUnreadCountResponse] = []
|
||||
var unreadCountCallCount = 0
|
||||
|
||||
func list(lastId: Int, limit: Int, unread: Int) async throws -> MessageListResponse {
|
||||
MessageListResponse()
|
||||
}
|
||||
|
||||
func unreadCount() async throws -> MessageUnreadCountResponse {
|
||||
unreadCountCallCount += 1
|
||||
guard !unreadCountResponses.isEmpty else { return MessageUnreadCountResponse() }
|
||||
return unreadCountResponses.removeFirst()
|
||||
}
|
||||
|
||||
func markAsRead(messageId: Int) async throws -> MessageUnreadCountResponse {
|
||||
MessageUnreadCountResponse()
|
||||
}
|
||||
|
||||
func markAllAsRead() async throws -> MessageReadAllResponse {
|
||||
MessageReadAllResponse()
|
||||
}
|
||||
|
||||
func delete(messageId: Int) async throws {}
|
||||
}
|
||||
|
||||
private extension UIColor {
|
||||
|
||||
Reference in New Issue
Block a user