blob: 03af4c64337314baed52660be0c09c342f497bc1 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
import SwiftUI
struct SearchSuggestionsView: View {
private struct CachedTag {
let original: Either<BooruTag, BooruSearchQuery>
let names: [String]
}
var items: [Either<BooruTag, BooruSearchQuery>]
@Binding var searchText: String
@Binding var suppressNextSearchSubmit: Bool
private var lastSearchTag: String {
String(searchText.split(separator: " ").last ?? "").lowercased()
}
private var cachedTags: [CachedTag] {
items.map { item in
switch item {
case .left(let tag):
return CachedTag(original: item, names: [tag.name.lowercased()])
case .right(let query):
return CachedTag(original: item, names: query.tags.map { $0.lowercased() })
}
}
}
private var filteredItems: [Either<BooruTag, BooruSearchQuery>] {
let matchCandidateTag = lastSearchTag
let matchingTagsLimit = 50
guard !matchCandidateTag.isEmpty else { return [] }
var seenTags = Set<String>()
var matchingTags: [Either<BooruTag, BooruSearchQuery>] = []
matchingTags.reserveCapacity(matchingTagsLimit)
for tag in cachedTags {
if matchingTags.count >= matchingTagsLimit { break }
for name in tag.names {
if name.contains(matchCandidateTag), seenTags.insert(name).inserted {
matchingTags.append(tag.original)
break
}
}
}
return matchingTags
}
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) })
{
let previousTags = searchText.split(separator: " ").dropLast()
suppressNextSearchSubmit = true
searchText = (previousTags.map(String.init) + [matchingTag]).joined(separator: " ")
}
} label: {
if let matchingTag = query.tags.first(where: { $0.lowercased().contains(lastSearchTag) })
{
Text(matchingTag)
} else {
Text(query.tags.first ?? "")
}
}
}
}
}
}
|