import SwiftUI class SettingsManager: ObservableObject { @AppStorage("detailViewType") var detailViewQuality: BooruPostFileType = .original @AppStorage("thumbnailQuality") var thumbnailQuality: BooruPostFileType = .preview @AppStorage("searchSuggestionsMode") var searchSuggestionsMode: SettingsSearchSuggestionsMode = .disabled @AppStorage("thumbnailGridColumns") var thumbnailGridColumns = 2 @AppStorage("bookmarks") private var bookmarksData = Data() @AppStorage("preferredBooru") var preferredBooru: BooruProvider = .safebooru @AppStorage("enableShareShortcut") var enableShareShortcut = false @AppStorage("displayRatings") private var displayRatingsData = SettingsManager.defaultRatingsData() @AppStorage("blurRatings") private var blurRatingsData = SettingsManager.initializeRatingsData( enabledRatings: [.explicit] ) @AppStorage("displayDetailsInformationBar") var displayDetailsInformationBar = true @AppStorage("searchHistory") private var searchHistoryData = Data() #if os(macOS) @AppStorage("saveTagsToFile") var saveTagsToFile = false #endif var bookmarks: [SettingsBookmark] { get { if let bookmarks = try? JSONDecoder().decode([SettingsBookmark].self, from: bookmarksData) { return bookmarks } return [] } set { if let data = try? JSONEncoder().encode(newValue) { bookmarksData = data } } } var displayRatings: [BooruRating] { get { Self.decodeRatings(from: displayRatingsData) } set { if let data = Self.encodeRatings(newValue) { displayRatingsData = data } } } var blurRatings: [BooruRating] { get { Self.decodeRatings(from: blurRatingsData) } set { if let data = Self.encodeRatings(newValue) { blurRatingsData = data } } } var searchHistory: [BooruSearchQuery] { get { if let history = try? JSONDecoder().decode([BooruSearchQuery].self, from: searchHistoryData) { return history } return [] } set { if let data = try? JSONEncoder().encode(newValue) { searchHistoryData = data } } } func appendToSearchHistory(_ query: BooruSearchQuery) { self.searchHistory.append(query) } func removeFromSearchHistory(_ query: BooruSearchQuery) { if let index = self.searchHistory.firstIndex(of: query) { self.searchHistory.remove(at: index) } } private static func defaultRatingsData() -> Data { initializeRatingsData(enabledRatings: BooruRating.allCases) } private static func initializeRatingsData(enabledRatings: [BooruRating]) -> Data { var ratings: [BooruRating] = [] for rating in enabledRatings { ratings.append(rating) } do { return try JSONEncoder().encode(ratings) } catch { debugPrint("Settings.initializeRatingsData: \(error)") return Data() } } private static func decodeRatings(from data: Data) -> [BooruRating] { if let ratings = try? JSONDecoder().decode([BooruRating].self, from: data) { return ratings } return BooruRating.allCases } private static func encodeRatings(_ ratings: [BooruRating]) -> Data? { try? JSONEncoder().encode(ratings) } func resetToDefaults() { detailViewQuality = .original thumbnailQuality = .preview searchSuggestionsMode = .disabled thumbnailGridColumns = 2 preferredBooru = .safebooru enableShareShortcut = false displayRatingsData = Self.defaultRatingsData() blurRatingsData = Self.initializeRatingsData(enabledRatings: [.explicit]) displayDetailsInformationBar = true #if os(macOS) saveTagsToFile = false #endif } func addBookmark(provider: BooruProvider, tags: [String]) { var currentBookmarks = bookmarks currentBookmarks.append(SettingsBookmark(provider: provider, tags: tags.map { $0.lowercased() })) bookmarks = currentBookmarks } func removeBookmark(at index: IndexSet) { var currentBookmarks = bookmarks currentBookmarks.remove(atOffsets: index) bookmarks = currentBookmarks } func removeBookmark(withTags tags: [String]) { var currentBookmarks = bookmarks currentBookmarks.removeAll { bookmark in bookmark.tags.contains(where: tags.contains) } bookmarks = currentBookmarks } func removeBookmark(withID: UUID) { var currentBookmarks = bookmarks currentBookmarks.removeAll { bookmark in bookmark.id == withID } bookmarks = currentBookmarks } }