MyInfoEntity: also fix unreadMessages count here to be fast, and use it for appState.unreadChannelMessages

This commit is contained in:
Mike Robbins 2025-10-13 14:44:28 -04:00
parent 431f1d6f03
commit 0fa913551b
6 changed files with 21 additions and 12 deletions

View file

@ -32,8 +32,8 @@ extension AccessoryManager {
}
}
// Set initial unread message badge states
appState.unreadChannelMessages = fetchedNodeInfo[0].myInfo?.unreadMessages ?? 0
appState.unreadDirectMessages = fetchedNodeInfo[0].user?.unreadMessages(in: context, skipLastMessageCheck: true) ?? 0 // skipLastMessageCheck=true because we don't update lastMessage on our own connected node
appState.unreadChannelMessages = fetchedNodeInfo[0].myInfo?.unreadMessages(context: context) ?? 0
appState.unreadDirectMessages = fetchedNodeInfo[0].user?.unreadMessages(context: context, skipLastMessageCheck: true) ?? 0 // skipLastMessageCheck=true because we don't update lastMessage on our own connected node
}
if fetchedNodeInfo.count == 1 && fetchedNodeInfo[0].rangeTestConfig?.enabled == true {
wantRangeTestPackets = true

View file

@ -30,7 +30,7 @@ extension ChannelEntity {
return (try? context.fetch(fetchRequest))?.first
}
var unreadMessages: Int {
func unreadMessages(context: NSManagedObjectContext) -> Int {
let context = PersistenceController.shared.container.viewContext
let fetchRequest = MessageEntity.fetchRequest()
// sort is irrelvant.
@ -38,6 +38,9 @@ extension ChannelEntity {
return (try? context.count(for: fetchRequest)) ?? 0
}
// Backwards-compatible property (uses viewContext)
var unreadMessages: Int { unreadMessages(context: PersistenceController.shared.container.viewContext) }
var protoBuf: Channel {
var channel = Channel()
channel.index = self.index

View file

@ -6,6 +6,7 @@
//
import Foundation
import CoreData
extension MyInfoEntity {
@ -18,11 +19,17 @@ extension MyInfoEntity {
return (try? context.fetch(fetchRequest)) ?? [MessageEntity]()
}
var unreadMessages: Int {
let unreadMessages = messageList.filter { ($0 as AnyObject).read == false && ($0 as AnyObject).isEmoji == false }
return unreadMessages.count
func unreadMessages(context: NSManagedObjectContext) -> Int {
// Returns the count of unread *channel* messages
let fetchRequest = MessageEntity.fetchRequest()
// sort is irrelvant.
fetchRequest.predicate = NSPredicate(format: "toUser == nil AND isEmoji == false AND read == false")
return (try? context.count(for: fetchRequest)) ?? 0
}
// Backwards-compatible property (uses viewContext)
var unreadMessages: Int { unreadMessages(context: PersistenceController.shared.container.viewContext) }
var hasAdmin: Bool {
let adminChannel = channels?.filter { ($0 as AnyObject).name?.lowercased() == "admin" }
return adminChannel?.count ?? 0 > 0

View file

@ -43,12 +43,11 @@ extension UserEntity {
return (try? context.fetch(fetchRequest)) ?? [MessageEntity]()
}
func unreadMessages(in ctx: NSManagedObjectContext?, skipLastMessageCheck: Bool = false) -> Int {
func unreadMessages(context: NSManagedObjectContext, skipLastMessageCheck: Bool = false) -> Int {
// Most contacts will have no DMs history, so we can return early.
// (For our own node, set skipLastMessageCheck=true, because we don't update lastMessage on our own connected node.)
guard self.lastMessage != nil || skipLastMessageCheck else { return 0; }
let context = ctx ?? PersistenceController.shared.container.viewContext // default to viewContext
let fetchRequest = MessageEntity.fetchRequest()
// sort is irrelvant.
fetchRequest.predicate = NSPredicate(format: "((toUser == %@) OR (fromUser == %@)) AND toUser != nil AND fromUser != nil AND isEmoji == false AND admin = false AND portNum != 10 AND read == false", self, self)
@ -56,7 +55,7 @@ extension UserEntity {
}
// Backwards-compatible property (uses viewContext)
var unreadMessages: Int { unreadMessages(in: nil) }
var unreadMessages: Int { unreadMessages(context: PersistenceController.shared.container.viewContext) }
/// SVG Images for Vendors who are signed project backers
var hardwareImage: String? {

View file

@ -1040,7 +1040,7 @@ func textMessageAppPacket(
if newMessage.fromUser != nil && newMessage.toUser != nil {
// Set Unread Message Indicators
if packet.to == connectedNode {
let unreadCount = newMessage.toUser?.unreadMessages(in: context, skipLastMessageCheck: true) ?? 0 // skipLastMessageCheck=true because we don't update lastMessage on our own connected node
let unreadCount = newMessage.toUser?.unreadMessages(context: context, skipLastMessageCheck: true) ?? 0 // skipLastMessageCheck=true because we don't update lastMessage on our own connected node
Task { @MainActor in
appState?.unreadDirectMessages = unreadCount
}
@ -1071,7 +1071,7 @@ func textMessageAppPacket(
do {
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest)
if !fetchedMyInfo.isEmpty {
appState?.unreadChannelMessages = fetchedMyInfo[0].unreadMessages
appState?.unreadChannelMessages = fetchedMyInfo[0].unreadMessages(context: context)
for channel in (fetchedMyInfo[0].channels?.array ?? []) as? [ChannelEntity] ?? [] {
if channel.index == newMessage.channel {
context.refresh(channel, mergeChanges: true)

View file

@ -43,7 +43,7 @@ struct UserMessageList: View {
if let connectedPeripheralNum = accessoryManager.activeDeviceNum,
let connectedNode = getNodeInfo(id: connectedPeripheralNum, context: context),
let connectedUser = connectedNode.user {
appState.unreadDirectMessages = connectedUser.unreadMessages(in: context, skipLastMessageCheck: true) // skipLastMessageCheck=true because we don't update lastMessage on our own connected node
appState.unreadDirectMessages = connectedUser.unreadMessages(context: context, skipLastMessageCheck: true) // skipLastMessageCheck=true because we don't update lastMessage on our own connected node
}
context.refresh(user, mergeChanges: true)