Transfer view, change data flow, actors

This commit is contained in:
Christoph Hagen
2023-07-02 17:29:39 +02:00
parent 8b4c4800c9
commit 396571fd30
24 changed files with 1285 additions and 302 deletions

View File

@ -3,7 +3,7 @@ import Combine
import BinaryCodable
import SwiftUI
final class TemperatureStorage: ObservableObject {
final class PersistentStorage: ObservableObject {
static var documentDirectory: URL {
try! FileManager.default.url(
@ -15,6 +15,9 @@ final class TemperatureStorage: ObservableObject {
@AppStorage("newestDate")
private var newestMeasurementTime: Int = 0
@AppStorage("deviceTime")
private var lastDeviceTimeData: Data?
/**
The date of the latest measurement.
@ -34,22 +37,26 @@ final class TemperatureStorage: ObservableObject {
@Published
var dailyMeasurementCounts: [MeasurementDailyCount] = []
/// The formatter for the temperature measurement file names
private let fileNameFormatter: DateFormatter
private let storageFolder: URL
private let overviewFileUrl: URL
/// The storage of daily temperature measurements
private let temperatureStorageFolderUrl: URL
/// The storage of the measurement counts per day
private let dailyCountsFileUrl: URL
private let fm: FileManager
/// The interval in which the measurements should be kept in `recentMeasurements`
private let lastValueInterval: TimeInterval
init(lastMeasurements: [TemperatureMeasurement] = [], lastValueInterval: TimeInterval = 3600) {
self.recentMeasurements = lastMeasurements
let documentDirectory = TemperatureStorage.documentDirectory
self.storageFolder = documentDirectory.appendingPathComponent("measurements")
self.overviewFileUrl = documentDirectory.appendingPathComponent("overview.bin")
let documentDirectory = PersistentStorage.documentDirectory
self.temperatureStorageFolderUrl = documentDirectory.appendingPathComponent("measurements")
self.dailyCountsFileUrl = documentDirectory.appendingPathComponent("overview.bin")
self.fm = .default
self.fileNameFormatter = DateFormatter()
self.fileNameFormatter.dateFormat = "yyyyMMdd.bin"
@ -63,15 +70,15 @@ final class TemperatureStorage: ObservableObject {
}
ensureExistenceOfFolder()
recalculateDailyCounts()
//recalculateDailyCounts()
}
private func ensureExistenceOfFolder() {
guard !fm.fileExists(atPath: storageFolder.path) else {
guard !fm.fileExists(atPath: temperatureStorageFolderUrl.path) else {
return
}
do {
try fm.createDirectory(at: storageFolder, withIntermediateDirectories: true)
try fm.createDirectory(at: temperatureStorageFolderUrl, withIntermediateDirectories: true)
} catch {
log.error("Failed to create folder: \(error)")
}
@ -86,16 +93,17 @@ final class TemperatureStorage: ObservableObject {
}
private func fileUrl(for dateIndex: Int) -> URL {
storageFolder.appendingPathComponent(fileName(for: dateIndex))
temperatureStorageFolderUrl.appendingPathComponent(fileName(for: dateIndex))
}
private func fileUrl(for fileName: String) -> URL {
storageFolder.appendingPathComponent(fileName)
temperatureStorageFolderUrl.appendingPathComponent(fileName)
}
private func loadLastMeasurements() {
let startDate = Date().addingTimeInterval(-lastValueInterval)
let todayIndex = Date().dateIndex
let now = Date.now
let startDate = now.addingTimeInterval(-lastValueInterval)
let todayIndex = now.dateIndex
let todayValues = loadMeasurements(for: todayIndex)
.filter { $0.date >= startDate }
let dateIndexOfStart = startDate.dateIndex
@ -220,7 +228,7 @@ final class TemperatureStorage: ObservableObject {
private func loadDailyCounts() {
do {
let data = try Data(contentsOf: overviewFileUrl)
let data = try Data(contentsOf: dailyCountsFileUrl)
dailyMeasurementCounts = try BinaryDecoder.decode(from: data)
} catch {
log.error("Failed to load overview: \(error)")
@ -230,7 +238,7 @@ final class TemperatureStorage: ObservableObject {
private func saveDailyCounts() {
do {
let data = try BinaryEncoder.encode(dailyMeasurementCounts)
try data.write(to: overviewFileUrl)
try data.write(to: dailyCountsFileUrl)
} catch {
log.error("Failed to write overview: \(error)")
}
@ -248,7 +256,7 @@ final class TemperatureStorage: ObservableObject {
func recalculateDailyCounts() {
do {
let files = try fm.contentsOfDirectory(atPath: storageFolder.path)
let files = try fm.contentsOfDirectory(atPath: temperatureStorageFolderUrl.path)
let newValues: [Int: Int] = files
.reduce(into: [:]) { counts, fileName in
let dateString = fileName.replacingOccurrences(of: ".bin", with: "")
@ -269,6 +277,37 @@ final class TemperatureStorage: ObservableObject {
log.error("Failed to load daily counts: \(error)")
}
}
// MARK: Device time
var lastDeviceTime: DeviceTime? {
get {
guard let data = lastDeviceTimeData else {
return nil
}
do {
let result: DeviceTime = try BinaryDecoder.decode(from: data)
return result
} catch {
log.error("Failed to decode device time: \(error)")
lastDeviceTimeData = nil
return nil
}
}
set {
guard let newValue else {
lastDeviceTimeData = nil
return
}
do {
let data = try BinaryEncoder.encode(newValue)
lastDeviceTimeData = data
} catch {
log.error("Failed to encode device time: \(error)")
lastDeviceTimeData = nil
}
}
}
}
private extension Array where Element == TemperatureMeasurement {
@ -294,9 +333,9 @@ private extension Array where Element == TemperatureMeasurement {
}
}
extension TemperatureStorage {
extension PersistentStorage {
static var mock: TemperatureStorage {
static var mock: PersistentStorage {
.init(lastMeasurements: TemperatureMeasurement.mockData)
}
}