// // KeyData.swift // OTP // // Created by Shadowfacts on 8/23/21. // import Foundation import OTPKit struct KeyData: Codable { private(set) var entries: [Entry] = [] private(set) var folders: [Folder] = [] init(entries: [Entry] = []) { self.entries = entries } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.entries = try container.decode([Entry].self, forKey: .entries) self.folders = try container.decode([Folder].self, forKey: .folders) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(entries, forKey: .entries) try container.encode(folders, forKey: .folders) } mutating func addKey(_ key: TOTPKey) { entries.append(Entry(key: key)) } mutating func addOrUpdateEntries(_ entries: [Entry]) { for e in entries { if let index = self.entries.firstIndex(where: { $0.id == e.id }) { self.entries[index] = e } else { self.entries.append(e) } } } mutating func updateKey(entryID id: UUID, newKey: TOTPKey) { guard let index = entries.firstIndex(where: { $0.id == id }) else { return } entries[index].key = newKey } mutating func removeKey(entryID id: UUID) { entries.removeAll(where: { $0.id == id }) } mutating func clearEntries() { entries.removeAll() } mutating func addFolder() { let count = folders.filter { $0.name.starts(with: "New Folder") }.count if count > 0 { folders.append(Folder(name: "New Folder \(count + 1)")) } else { folders.append(Folder(name: "New Folder")) } } mutating func updateFolder(_ newFolder: KeyData.Folder) { guard let index = folders.firstIndex(where: { $0.id == newFolder.id }) else { return } folders[index] = newFolder } mutating func removeFolder(id: UUID) { folders.removeAll(where: { $0.id == id }) for (index, e) in entries.enumerated() where e.folderID == id { entries[index].folderID = nil } } mutating func moveEntryToFolder(entryID: UUID, folderID: UUID?) { guard let index = entries.firstIndex(where: { $0.id == entryID }), folderID == nil || folders.contains(where: { $0.id == folderID }) else { return } entries[index].folderID = folderID } struct Entry: Identifiable, Hashable, Codable { let id: UUID var key: TOTPKey var folderID: UUID? let image: Data? init(id: UUID = UUID(), key: TOTPKey, folderID: UUID? = nil, image: Data? = nil) { self.id = id self.key = key self.folderID = folderID self.image = image } } struct Folder: Identifiable, Codable { let id: UUID var name: String init(id: UUID = UUID(), name: String) { self.id = id self.name = name } } private enum CodingKeys: CodingKey { case entries case folders } }