Atoll/DynamicIsland/components/Shelf/Services/ShelfPersistenceService.swift
2026-01-29 12:26:04 +05:30

96 lines
3.6 KiB
Swift

/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* Originally from boring.notch project
* Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import Foundation
// Access model types
@_exported import struct Foundation.URL
final class ShelfPersistenceService {
static let shared = ShelfPersistenceService()
private let fileURL: URL
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()
private init() {
let fm = FileManager.default
let support = try? fm.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let dir = (support ?? fm.temporaryDirectory).appendingPathComponent("DynamicIsland", isDirectory: true).appendingPathComponent("Shelf", isDirectory: true)
try? fm.createDirectory(at: dir, withIntermediateDirectories: true)
fileURL = dir.appendingPathComponent("items.json")
encoder.outputFormatting = [.prettyPrinted]
decoder.dateDecodingStrategy = .iso8601
encoder.dateEncodingStrategy = .iso8601
}
func load() -> [ShelfItem] {
guard let data = try? Data(contentsOf: fileURL) else { return [] }
// Try to decode as array first (normal case)
if let items = try? decoder.decode([ShelfItem].self, from: data) {
return items
}
// If array decoding fails, try to decode individual items
do {
// Parse as JSON array to get individual item data
guard let jsonArray = try JSONSerialization.jsonObject(with: data) as? [Any] else {
print("⚠️ Shelf persistence file is not a valid JSON array")
return []
}
var validItems: [ShelfItem] = []
var failedCount = 0
for (index, jsonItem) in jsonArray.enumerated() {
do {
let itemData = try JSONSerialization.data(withJSONObject: jsonItem)
let item = try decoder.decode(ShelfItem.self, from: itemData)
validItems.append(item)
} catch {
failedCount += 1
print("⚠️ Failed to decode shelf item at index \(index): \(error.localizedDescription)")
}
}
if failedCount > 0 {
print("📦 Successfully loaded \(validItems.count) shelf items, discarded \(failedCount) corrupted items")
}
return validItems
} catch {
print("❌ Failed to parse shelf persistence file: \(error.localizedDescription)")
return []
}
}
func save(_ items: [ShelfItem]) {
do {
let data = try encoder.encode(items)
try data.write(to: fileURL, options: Data.WritingOptions.atomic)
} catch {
print("Failed to save shelf items: \(error.localizedDescription)")
}
}
}