summaryrefslogtreecommitdiff
path: root/Sora
diff options
context:
space:
mode:
Diffstat (limited to 'Sora')
-rw-r--r--Sora/Data/Booru/BooruManager.swift95
-rw-r--r--Sora/Views/MainView.swift17
-rw-r--r--Sora/Views/Post/Grid/PostGridView.swift22
-rw-r--r--Sora/Views/Settings/Section/SettingsSearchView.swift13
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()
}