diff options
Diffstat (limited to 'Sora')
| -rw-r--r-- | Sora/Data/Booru/BooruManager.swift | 95 | ||||
| -rw-r--r-- | Sora/Views/MainView.swift | 17 | ||||
| -rw-r--r-- | Sora/Views/Post/Grid/PostGridView.swift | 22 | ||||
| -rw-r--r-- | Sora/Views/Settings/Section/SettingsSearchView.swift | 13 |
4 files changed, 45 insertions, 102 deletions
diff --git a/Sora/Data/Booru/BooruManager.swift b/Sora/Data/Booru/BooruManager.swift index 966f31f..2c4df79 100644 --- a/Sora/Data/Booru/BooruManager.swift +++ b/Sora/Data/Booru/BooruManager.swift @@ -2,15 +2,13 @@ import Alamofire import SwiftUI @MainActor -class BooruManager: ObservableObject { // swiftlint:disable:this type_body_length +class BooruManager: ObservableObject { // MARK: - Published Properties @Published var posts: [BooruPost] = [] - @Published var allTags: [BooruTag] = [] @Published var isLoading = false @Published var currentPage = 1 @Published var searchText = "" @Published var endOfData = false - @Published var cacheSize: String? @Published var selectedPost: BooruPost? @Published var flavor: BooruProviderFlavor @Published var domain: String @@ -23,10 +21,6 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng // MARK: - Private Properties private var currentTask: Task<Void, Never>? - private let tagsCacheFileURL: URL? = FileManager.default.urls( - for: .cachesDirectory, in: .userDomainMask - ).first? - .appendingPathComponent("\(BooruProvider.safebooru.asFileNameComponent)_tags.json") private let pageCache = NSCache<NSString, BooruPageCacheEntry>() // swiftlint:disable:this legacy_objc_type private let cacheDuration: TimeInterval = 300 private let credentials: BooruProviderCredentials? @@ -62,12 +56,6 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng } // MARK: - Public Methods - func initializeTags() { - loadCachedTags() - fetchAllTags() - updateTagsCacheSize() - } - func fetchPosts(page: Int = 1, limit: Int = 100, tags: [String] = [], replace: Bool = false) async { guard !isLoading else { return } @@ -198,41 +186,21 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng currentTask = Task { isNavigatingHistory = false } } - func fetchAllTags(limit: Int = 10_000) { - guard let url = urlForTags(limit: limit) else { return } - - Task { - do { - let data = try await requestURL(url) + func searchTags(name: String) async -> [BooruTag] { + guard let url = urlForTagsSearch(name: name) else { return [] } - guard !Task.isCancelled else { return } + do { + let data = try await requestURL(url) - allTags = BooruTagXMLParser(data: data).parse().sorted { $0.count > $1.count } + guard !Task.isCancelled else { return [] } - saveTagsToCache() - } catch { - if (error as? URLError)?.code != .cancelled { - debugPrint("BooruManager.fetchAllTags: \(error)") - } + return BooruTagXMLParser(data: data).parse().sorted { $0.count > $1.count } + } catch { + if (error as? URLError)?.code != .cancelled { + debugPrint("BooruManager.searchTags: \(error)") } - } - } - func clearCachedTags() { - try? tagsCacheFileURL.map { url in - try FileManager.default.removeItem(at: url) - updateTagsCacheSize() - } - } - - func updateTagsCacheSize() { - cacheSize = tagsCacheFileURL.flatMap { url in - ByteCountFormatter.string( - fromByteCount: Int64( - (try? FileManager.default.attributesOfItem(atPath: url.path)[.size] as? Int) ?? 0 - ), - countStyle: .file - ) + return [] } } @@ -280,6 +248,22 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng } } + private func urlForTagsSearch(name: String) -> URL? { + switch flavor { + case .moebooru: + return URL(string: "https://\(domain)/tag.xml?name_pattern=\(name)&order=count") + + case .gelbooru: + return URL( + string: + "https://\(domain)/index.php?page=dapi&s=tag&q=index&name_pattern=%\(name)%&orderby=count" + ) + + case .danbooru: + return nil + } + } + nonisolated private func parsePosts( from data: Data, flavor: BooruProviderFlavor, @@ -325,31 +309,6 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng } } - private func saveTagsToCache() { - if let url = tagsCacheFileURL { - do { - let data = try JSONEncoder().encode(allTags) - - try data.write(to: url) - updateTagsCacheSize() - } catch { - debugPrint("BooruManager.saveTagsToCache:", error) - } - } - } - - private func loadCachedTags() { - guard let url = tagsCacheFileURL else { return } - - if let data = try? Data(contentsOf: url), - let tags = try? JSONDecoder().decode([BooruTag].self, from: data) - { - allTags = tags - - updateTagsCacheSize() - } - } - private func requestURL(_ url: URL) async throws -> Data { let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0" let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "1" diff --git a/Sora/Views/MainView.swift b/Sora/Views/MainView.swift index bb31d4e..dd73c49 100644 --- a/Sora/Views/MainView.swift +++ b/Sora/Views/MainView.swift @@ -12,11 +12,6 @@ struct MainView: View { .onChange(of: settings.preferredBooru) { _, newState in updateManager(newState) } - .onChange(of: settings.searchSuggestionsMode) { _, newState in - if newState != .disabled { - refreshTags() - } - } .onChange(of: manager.historyIndex) { _, _ in manager.selectedPost = nil } @@ -114,8 +109,6 @@ struct MainView: View { ) manager.searchText = previousSearchText - refreshTags() - Task(priority: .userInitiated) { if manager.searchText.isEmpty { await manager.fetchPosts() @@ -132,22 +125,12 @@ struct MainView: View { .first { $0.provider == settings.preferredBooru } ) - refreshTags() - Task(priority: .userInitiated) { if manager.posts.isEmpty { await manager.fetchPosts() } } } - - private func refreshTags() { - if settings.searchSuggestionsMode != .disabled { - manager.initializeTags() - } else { - manager.updateTagsCacheSize() - } - } } #Preview { diff --git a/Sora/Views/Post/Grid/PostGridView.swift b/Sora/Views/Post/Grid/PostGridView.swift index 9c7e5b6..97604e5 100644 --- a/Sora/Views/Post/Grid/PostGridView.swift +++ b/Sora/Views/Post/Grid/PostGridView.swift @@ -11,6 +11,8 @@ struct PostGridView: View { // swiftlint:disable:this type_body_length @State private var isSearchablePresented = false @State private var cachedSuggestions: [Either<BooruTag, BooruSearchQuery>] = [] @State private var suppressNextSearchSubmit = false + @State private var searchTask: Task<Void, Never>? + @State private var suggestions: [BooruTag] = [] @Environment(\.isSearching) private var isSearching @@ -131,10 +133,22 @@ struct PostGridView: View { // swiftlint:disable:this type_body_length ) } } - .onAppear { + .onChange(of: manager.searchText) { _, newValue in if settings.searchSuggestionsMode == .tags { - cachedSuggestions = manager.allTags.map { tag in - Either<BooruTag, BooruSearchQuery>.left(tag) + searchTask?.cancel() + + searchTask = Task { + try? await Task.sleep(nanoseconds: 300_000_000) + + guard !Task.isCancelled else { return } + + let searchTag = newValue.split(separator: " ").last.map(String.init) ?? "" + + if !searchTag.isEmpty { + suggestions = await manager.searchTags(name: searchTag) + } else { + suggestions = [] + } } } } @@ -343,7 +357,7 @@ struct PostGridView: View { // swiftlint:disable:this type_body_length private func searchSuggestionsItems() -> [Either<BooruTag, BooruSearchQuery>] { switch settings.searchSuggestionsMode { case .tags: - return cachedSuggestions + return suggestions.map { .left($0) } case .history: return settings.searchHistory.map { .right($0) } diff --git a/Sora/Views/Settings/Section/SettingsSearchView.swift b/Sora/Views/Settings/Section/SettingsSearchView.swift index 062efad..34b123b 100644 --- a/Sora/Views/Settings/Section/SettingsSearchView.swift +++ b/Sora/Views/Settings/Section/SettingsSearchView.swift @@ -3,12 +3,6 @@ import SwiftUI struct SettingsSearchView: View { @EnvironmentObject var settings: SettingsManager - #if os(macOS) - var manager = BooruManager(.yandere) - #else - @EnvironmentObject var manager: BooruManager - #endif - var body: some View { Picker("Suggestion Mode", selection: $settings.searchSuggestionsMode) { ForEach(SettingsSearchSuggestionsMode.allCases, id: \.self) { type in @@ -16,13 +10,6 @@ struct SettingsSearchView: View { } } - Button( - "Clear Cached Tags (\(manager.cacheSize ?? "Unknown size"))" - ) { - manager.clearCachedTags() - } - .trailingFrame() - Button("Clear History") { settings.searchHistory.removeAll() } |