This commit is contained in:
世界
2025-11-26 22:25:51 +08:00
parent 68b4142340
commit 2e2fc223bf
4 changed files with 146 additions and 31 deletions
+57 -12
View File
@@ -1,5 +1,6 @@
import Combine
import Foundation
import Libbox
import Library
import SwiftUI
#if canImport(UIKit)
@@ -20,6 +21,9 @@ public class LogViewModel: ObservableObject {
@Published public var logFileURL: URL?
private let commandClient: CommandClient
private var lastProcessedLogCount = 0
private var lastEffectiveLevel: Int?
private var lastSearchText = ""
public var isEmpty: Bool { commandClient.logList.isEmpty }
public var isConnected: Bool { commandClient.isConnected }
@@ -36,17 +40,42 @@ public class LogViewModel: ObservableObject {
$selectedLogLevel,
debouncedSearchText
)
.map { logList, defaultLogLevel, selectedLogLevel, searchText in
let effectiveLevel = selectedLogLevel ?? defaultLogLevel
return logList.filter { log in
log.level <= effectiveLevel &&
(searchText.isEmpty || log.message.contains(searchText))
}
}
.receive(on: DispatchQueue.main)
.assign(to: &$filteredLogs)
.sink { [weak self] logList, defaultLogLevel, selectedLogLevel, searchText in
guard let self = self else { return }
let effectiveLevel = selectedLogLevel ?? defaultLogLevel
// Check if we can do incremental filtering
let canIncrement = self.lastProcessedLogCount > 0 &&
logList.count > self.lastProcessedLogCount &&
effectiveLevel == self.lastEffectiveLevel &&
searchText == self.lastSearchText
if canIncrement {
// Incremental filtering: only filter new logs
let newLogs = logList[self.lastProcessedLogCount...]
let newFilteredLogs = newLogs.filter { log in
log.level <= effectiveLevel &&
(searchText.isEmpty || log.message.contains(searchText))
}
self.filteredLogs.append(contentsOf: newFilteredLogs)
} else {
// Full refiltering needed
self.filteredLogs = logList.filter { log in
log.level <= effectiveLevel &&
(searchText.isEmpty || log.message.contains(searchText))
}
}
self.lastProcessedLogCount = logList.count
self.lastEffectiveLevel = effectiveLevel
self.lastSearchText = searchText
}
.store(in: &cancellables)
}
private var cancellables = Set<AnyCancellable>()
public func togglePause() {
isPaused.toggle()
}
@@ -59,11 +88,23 @@ public class LogViewModel: ObservableObject {
}
public func clearLogs() {
commandClient.logList.removeAll()
isPaused = false
lastProcessedLogCount = 0
lastEffectiveLevel = nil
lastSearchText = ""
Task.detached {
let client = LibboxNewStandaloneCommandClient()
try? client?.clearLogs()
}
}
#if !os(tvOS)
private static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd-HH:mm:ss"
return formatter
}()
public func getLogsText() -> String {
filteredLogs.map(\.message).joined(separator: "\n")
}
@@ -78,12 +119,16 @@ public class LogViewModel: ObservableObject {
#endif
}
public func cleanupLogFile() {
guard let url = logFileURL else { return }
try? FileManager.default.removeItem(at: url)
}
public func prepareLogFile() {
cleanupLogFile()
do {
let text = getLogsText()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd-HH:mm:ss"
let dateString = dateFormatter.string(from: Date())
let dateString = Self.dateFormatter.string(from: Date())
let tempDirectory = FileManager.default.temporaryDirectory
let fileURL = tempDirectory.appendingPathComponent("logs-\(dateString).txt")
try text.write(to: fileURL, atomically: true, encoding: .utf8)