Версия 3.2.0: контракт v2, оформление «Лес» #2

Merged
wt merged 5 commits from develop into main 2026-10-31 19:17:48 +00:00
4 changed files with 12 additions and 10 deletions
Showing only changes of commit 94177dbb0b - Show all commits

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ extension EnvironmentValues {
struct CurrencyContextProvider<Content: View>: View {
@Query private var accounts: [FinanceAccount]
@Query private var rates: [ExchangeRate]
@Query(filter: #Predicate<SyncRecord> { $0.entity == "setting" && $0.recordID == "baseCurrency" })
@Query(filter: #Predicate<SyncRecord> { $0.entityName == "setting" && $0.recordID == "baseCurrency" })
private var baseSetting: [SyncRecord]
@AppStorage("currencyCode") private var currencyCode = SupportedCurrency.RUB.rawValue
@ViewBuilder let content: Content
+2 -2
View File
@@ -489,7 +489,7 @@ struct WatchSettingsView: View {
@StateObject private var account = ServerAccountStore.shared
@AppStorage("currencyCode") private var currencyCode = SupportedCurrency.RUB.rawValue
@AppStorage("appTheme") private var appTheme = AppTheme.system.rawValue
@Query(filter: #Predicate<SyncRecord> { $0.entity == "setting" && $0.recordID == "baseCurrency" })
@Query(filter: #Predicate<SyncRecord> { $0.entityName == "setting" && $0.recordID == "baseCurrency" })
private var baseSetting: [SyncRecord]
private var currencyCodes: [String] {
@@ -508,7 +508,7 @@ struct WatchSettingsView: View {
record.payload = payload
record.syncUpdatedAt = .now
} else {
modelContext.insert(SyncRecord(entity: "setting", recordID: SyncRecord.baseCurrencyKey, payload: payload, syncUpdatedAt: .now))
modelContext.insert(SyncRecord(entityName: "setting", recordID: SyncRecord.baseCurrencyKey, payload: payload, syncUpdatedAt: .now))
}
})
}
+5 -3
View File
@@ -70,13 +70,15 @@ final class ExchangeRate {
/// `attachment`, `setting`. Payload хранится целиком, поэтому все поля сохраняются.
@Model
final class SyncRecord {
var entity: String = ""
/// Не `entity`: так называется встроенное свойство CoreData, и предикат
/// по нему ломает SQL-запрос SwiftData.
var entityName: String = ""
var recordID: String = ""
var payload: Data = Data()
var syncUpdatedAt: Date = Date.now
init(entity: String, recordID: String, payload: Data, syncUpdatedAt: Date) {
self.entity = entity
init(entityName: String, recordID: String, payload: Data, syncUpdatedAt: Date) {
self.entityName = entityName
self.recordID = recordID
self.payload = payload
self.syncUpdatedAt = syncUpdatedAt
+4 -4
View File
@@ -498,9 +498,9 @@ final class ServerAccountStore: ObservableObject {
private func pushSettings(context: ModelContext, after threshold: Date, through cutoff: Date, cursor: Int64) async throws {
let lowerBound = threshold, upperBound = cutoff
let items = try context.fetch(FetchDescriptor<SyncRecord>(predicate: #Predicate { item in
item.entity == "setting" && item.syncUpdatedAt >= lowerBound && item.syncUpdatedAt <= upperBound
item.entityName == "setting" && item.syncUpdatedAt >= lowerBound && item.syncUpdatedAt <= upperBound
}))
try await sendPush(items.map { SyncChange(entity:$0.entity, id:$0.recordID, deleted:false, updatedAt:$0.syncUpdatedAt, payload:$0.payload) }, cursor:cursor)
try await sendPush(items.map { SyncChange(entity:$0.entityName, id:$0.recordID, deleted:false, updatedAt:$0.syncUpdatedAt, payload:$0.payload) }, cursor:cursor)
}
private func pushTombstones(through cutoff: Date, cursor: Int64) async throws {
@@ -660,12 +660,12 @@ final class ServerAccountStore: ObservableObject {
/// Регулярные операции часы не исполняют (§4).
private func applyRecord(_ change: SyncChange, context: ModelContext) throws {
let entity = change.entity, recordID = change.id
let existing = try context.fetch(FetchDescriptor<SyncRecord>(predicate:#Predicate { $0.entity == entity && $0.recordID == recordID })).first
let existing = try context.fetch(FetchDescriptor<SyncRecord>(predicate:#Predicate { $0.entityName == entity && $0.recordID == recordID })).first
if let existing, existing.syncUpdatedAt > change.updatedAt { return }
if change.deleted { if let existing { context.delete(existing) }; return }
guard let data = change.payload else { return }
if let existing { existing.payload = data; existing.syncUpdatedAt = change.updatedAt }
else { context.insert(SyncRecord(entity:entity, recordID:recordID, payload:data, syncUpdatedAt:change.updatedAt)) }
else { context.insert(SyncRecord(entityName:entity, recordID:recordID, payload:data, syncUpdatedAt:change.updatedAt)) }
}
private func transaction(id: UUID, context: ModelContext) throws -> FinanceTransaction? {