2022-08-04 22:30:09 +00:00
|
|
|
import Repeat
|
2021-11-28 14:37:55 +00:00
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
struct SearchTextField: View {
|
|
|
|
@Environment(\.navigationStyle) private var navigationStyle
|
|
|
|
|
2022-01-20 22:13:10 +00:00
|
|
|
@EnvironmentObject<NavigationModel> private var navigation
|
2021-11-28 14:37:55 +00:00
|
|
|
@EnvironmentObject<RecentsModel> private var recents
|
|
|
|
@EnvironmentObject<SearchModel> private var state
|
|
|
|
|
2022-08-04 22:30:09 +00:00
|
|
|
@Binding var queryText: String
|
2021-12-04 19:35:41 +00:00
|
|
|
@Binding var favoriteItem: FavoriteItem?
|
|
|
|
|
2022-08-04 22:30:09 +00:00
|
|
|
private var queryDebouncer = Debouncer(.milliseconds(800))
|
|
|
|
|
|
|
|
init(
|
|
|
|
queryText: Binding<String>,
|
|
|
|
favoriteItem: Binding<FavoriteItem?>? = nil
|
|
|
|
) {
|
|
|
|
_queryText = queryText
|
2021-12-04 19:35:41 +00:00
|
|
|
_favoriteItem = favoriteItem ?? .constant(nil)
|
|
|
|
}
|
|
|
|
|
2021-11-28 14:37:55 +00:00
|
|
|
var body: some View {
|
|
|
|
ZStack {
|
|
|
|
#if os(macOS)
|
|
|
|
fieldBorder
|
|
|
|
#endif
|
|
|
|
|
|
|
|
HStack(spacing: 0) {
|
|
|
|
#if os(macOS)
|
|
|
|
Image(systemName: "magnifyingglass")
|
|
|
|
.resizable()
|
|
|
|
.aspectRatio(contentMode: .fill)
|
|
|
|
.frame(width: 12, height: 12)
|
|
|
|
.padding(.horizontal, 8)
|
|
|
|
.opacity(0.8)
|
|
|
|
#endif
|
2022-08-04 22:30:09 +00:00
|
|
|
TextField("Search...", text: $queryText) {
|
2022-03-26 14:22:29 +00:00
|
|
|
state.changeQuery { query in
|
|
|
|
query.query = state.queryText
|
|
|
|
navigation.hideKeyboard()
|
|
|
|
}
|
2022-01-20 22:13:10 +00:00
|
|
|
recents.addQuery(state.queryText, navigation: navigation)
|
2021-11-28 14:37:55 +00:00
|
|
|
}
|
2022-08-04 22:30:09 +00:00
|
|
|
.disableAutocorrection(true)
|
|
|
|
.onChange(of: state.suggestionSelection) { newValue in
|
|
|
|
self.queryText = newValue
|
|
|
|
}
|
|
|
|
.onChange(of: queryText) { newValue in
|
|
|
|
queryDebouncer.callback = {
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
state.queryText = newValue
|
|
|
|
}
|
2021-11-28 14:37:55 +00:00
|
|
|
}
|
2022-08-04 22:30:09 +00:00
|
|
|
queryDebouncer.call()
|
2021-11-28 14:37:55 +00:00
|
|
|
}
|
|
|
|
#if os(macOS)
|
2021-12-06 18:13:20 +00:00
|
|
|
.frame(maxWidth: 190)
|
2021-11-28 14:37:55 +00:00
|
|
|
.textFieldStyle(.plain)
|
|
|
|
#else
|
|
|
|
.textFieldStyle(.roundedBorder)
|
|
|
|
.padding(.leading)
|
|
|
|
.padding(.trailing, 15)
|
|
|
|
#endif
|
2021-12-04 19:35:41 +00:00
|
|
|
|
2021-11-28 14:37:55 +00:00
|
|
|
if !self.state.queryText.isEmpty {
|
2021-12-04 19:35:41 +00:00
|
|
|
#if os(iOS)
|
|
|
|
FavoriteButton(item: favoriteItem)
|
|
|
|
.id(favoriteItem?.id)
|
|
|
|
.labelStyle(.iconOnly)
|
|
|
|
.padding(.trailing)
|
|
|
|
#endif
|
2021-11-28 14:37:55 +00:00
|
|
|
clearButton
|
2021-12-06 18:13:20 +00:00
|
|
|
} else {
|
|
|
|
#if os(macOS)
|
|
|
|
clearButton
|
|
|
|
.opacity(0)
|
|
|
|
#endif
|
2021-11-28 14:37:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.padding(.top, navigationStyle == .tab ? 10 : 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
private var fieldBorder: some View {
|
|
|
|
RoundedRectangle(cornerRadius: 5, style: .continuous)
|
|
|
|
.fill(Color.background)
|
|
|
|
.frame(width: 250, height: 32)
|
|
|
|
.overlay(
|
|
|
|
RoundedRectangle(cornerRadius: 5, style: .continuous)
|
2022-08-04 22:30:09 +00:00
|
|
|
.stroke(Color.gray.opacity(0.4), lineWidth: 1)
|
2021-11-28 14:37:55 +00:00
|
|
|
.frame(width: 250, height: 31)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
private var clearButton: some View {
|
|
|
|
Button(action: {
|
2022-08-04 22:30:09 +00:00
|
|
|
queryText = ""
|
2021-11-28 14:37:55 +00:00
|
|
|
self.state.queryText = ""
|
|
|
|
}) {
|
|
|
|
Image(systemName: "xmark.circle.fill")
|
|
|
|
.resizable()
|
|
|
|
.aspectRatio(contentMode: .fit)
|
|
|
|
#if os(macOS)
|
|
|
|
.frame(width: 14, height: 14)
|
|
|
|
#else
|
|
|
|
.frame(width: 18, height: 18)
|
|
|
|
#endif
|
|
|
|
.padding(.trailing, 3)
|
|
|
|
}
|
|
|
|
.buttonStyle(PlainButtonStyle())
|
|
|
|
.padding(.trailing, 10)
|
|
|
|
.opacity(0.7)
|
|
|
|
}
|
|
|
|
}
|