diff options
| author | Fuwn <[email protected]> | 2026-02-18 12:33:44 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-18 12:33:50 -0800 |
| commit | 0587c64598267ecace6259241198425cdc284f3a (patch) | |
| tree | ba90872e872e90ae98096c1da81ceb5a66d5c476 /Sora/Views/SearchSuggestionsView.swift | |
| parent | refactor: share folder menu hierarchy across views (diff) | |
| download | sora-testing-0587c64598267ecace6259241198425cdc284f3a.tar.xz sora-testing-0587c64598267ecace6259241198425cdc284f3a.zip | |
perf: reduce suggestion and image handling hot-path overhead
Diffstat (limited to 'Sora/Views/SearchSuggestionsView.swift')
| -rw-r--r-- | Sora/Views/SearchSuggestionsView.swift | 68 |
1 files changed, 43 insertions, 25 deletions
diff --git a/Sora/Views/SearchSuggestionsView.swift b/Sora/Views/SearchSuggestionsView.swift index 03af4c6..e9593ec 100644 --- a/Sora/Views/SearchSuggestionsView.swift +++ b/Sora/Views/SearchSuggestionsView.swift @@ -9,13 +9,21 @@ struct SearchSuggestionsView: View { var items: [Either<BooruTag, BooruSearchQuery>] @Binding var searchText: String @Binding var suppressNextSearchSubmit: Bool + @State private var cachedTags: [CachedTag] = [] private var lastSearchTag: String { String(searchText.split(separator: " ").last ?? "").lowercased() } - private var cachedTags: [CachedTag] { - items.map { item in + private var itemsCacheKey: Int { + items.reduce(into: Hasher()) { hasher, item in + hasher.combine(item) + } + .finalize() + } + + private func refreshCachedTags() { + cachedTags = items.map { item in switch item { case .left(let tag): return CachedTag(original: item, names: [tag.name.lowercased()]) @@ -53,36 +61,46 @@ struct SearchSuggestionsView: View { } var body: some View { - ForEach(filteredItems, id: \.self) { item in - switch item { - case .left(let tag): - Button { - let previousTags = searchText.split(separator: " ").dropLast() - - suppressNextSearchSubmit = true - searchText = (previousTags.map(String.init) + [tag.name]).joined(separator: " ") - } label: { - Text(tag.name) - } - - case .right(let query): - Button { - if let matchingTag = query.tags.first(where: { $0.lowercased().contains(lastSearchTag) }) - { + Group { + ForEach(filteredItems, id: \.self) { item in + switch item { + case .left(let tag): + Button { let previousTags = searchText.split(separator: " ").dropLast() suppressNextSearchSubmit = true - searchText = (previousTags.map(String.init) + [matchingTag]).joined(separator: " ") + searchText = (previousTags.map(String.init) + [tag.name]).joined(separator: " ") + } label: { + Text(tag.name) } - } label: { - if let matchingTag = query.tags.first(where: { $0.lowercased().contains(lastSearchTag) }) - { - Text(matchingTag) - } else { - Text(query.tags.first ?? "") + + case .right(let query): + let matchingTag = query.tags.first { tag in + tag.lowercased().contains(lastSearchTag) + } + + Button { + if let matchingTag { + let previousTags = searchText.split(separator: " ").dropLast() + + suppressNextSearchSubmit = true + searchText = (previousTags.map(String.init) + [matchingTag]).joined(separator: " ") + } + } label: { + if let matchingTag { + Text(matchingTag) + } else { + Text(query.tags.first ?? "") + } } } } } + .onAppear { + refreshCachedTags() + } + .onChange(of: itemsCacheKey) { + refreshCachedTags() + } } } |