diff options
| author | Dustin Mierau <dustin@mierau.me> | 2025-10-25 16:46:52 -0700 |
|---|---|---|
| committer | Dustin Mierau <dustin@mierau.me> | 2025-10-25 16:46:52 -0700 |
| commit | 3b3b965842c47939ca54d0d1cbdf469346847f14 (patch) | |
| tree | 22b5ee17d5fa8196a2d6b1bd95d7749c71cd69bc /Hotline/Models | |
| parent | 53686e30592fee566585e391738adee8b2ef2137 (diff) | |
Move chat input string to view model so its not lost when switching between tabs. Add chat search/filtering with suppport for live filtering.
Diffstat (limited to 'Hotline/Models')
| -rw-r--r-- | Hotline/Models/Hotline.swift | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/Hotline/Models/Hotline.swift b/Hotline/Models/Hotline.swift index 3783ba0..3d1f309 100644 --- a/Hotline/Models/Hotline.swift +++ b/Hotline/Models/Hotline.swift @@ -163,6 +163,7 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileDownloadClientDelega var users: [User] = [] var accounts: [HotlineAccount] = [] var chat: [ChatMessage] = [] + var chatInput: String = "" var messageBoard: [String] = [] var messageBoardLoaded: Bool = false var files: [FileInfo] = [] @@ -1464,6 +1465,69 @@ class Hotline: Equatable, HotlineClientDelegate, HotlineFileDownloadClientDelega self.lastPersistedMessageType = nil } + @MainActor func searchChat(query: String) -> [ChatMessage] { + guard !query.isEmpty else { + return [] + } + + // Create a map of all messages by ID to deduplicate (current chat includes restored history) + var messageMap: [UUID: ChatMessage] = [:] + + // Add current in-memory messages (includes both restored history and new messages) + for message in self.chat { + messageMap[message.id] = message + } + + // Filter messages based on query + let filteredMessages = messageMap.values.filter { message in + // Never include agreement messages + if message.type == .agreement { + return false + } + + // Always include disconnect messages to show session boundaries + let isDisconnect = message.type == .signOut + + // Search in text and username + let matchesText = message.text.localizedCaseInsensitiveContains(query) + let matchesUsername = message.username?.localizedCaseInsensitiveContains(query) == true + let matchesQuery = matchesText || matchesUsername + + return isDisconnect || matchesQuery + } + + // Sort by date to maintain chronological order + let sortedMessages = filteredMessages.sorted { $0.date < $1.date } + + // Remove consecutive disconnect messages to avoid visual clutter + var deduplicated: [ChatMessage] = [] + var lastWasDisconnect = false + + for message in sortedMessages { + let isDisconnect = message.type == .signOut + + if isDisconnect && lastWasDisconnect { + // Skip consecutive disconnect messages + continue + } + + deduplicated.append(message) + lastWasDisconnect = isDisconnect + } + + // Remove leading disconnect message + if deduplicated.first?.type == .signOut { + deduplicated.removeFirst() + } + + // Remove trailing disconnect message + if deduplicated.last?.type == .signOut { + deduplicated.removeLast() + } + + return deduplicated + } + func updateServerTitle() { self.serverTitle = self.serverName ?? self.server?.name ?? server?.address ?? "Server" } |