diff --git a/Shared/Supporting Files/Extensions/CategoryView+Search.swift b/Shared/Supporting Files/Extensions/CategoryView+Search.swift index fca42b626..e63d5cd11 100644 --- a/Shared/Supporting Files/Extensions/CategoryView+Search.swift +++ b/Shared/Supporting Files/Extensions/CategoryView+Search.swift @@ -15,42 +15,43 @@ import SwiftUI extension CategoryView { - /// Searches the samples using the sample's name and the query. + /// Searches through a list of samples using the sample's name and the query. + /// - Parameters: + /// - samples: The `Array` of samples to search through. + /// - query: The `String` to search with. /// - Returns: The samples whose name partially matches the query. - func searchSamplesNames() -> [Sample] { - // Return all the samples when query is empty. - guard !query.isEmpty else { return samples } - + func searchNames(in samples: [Sample], with query: String) -> [Sample] { // Perform a partial text search using the sample's name and the query. let nameSearchResults = samples.filter { sample in sample.name.localizedCaseInsensitiveContains(query) } - previousSearchResults.formUnion(nameSearchResults.map(\.name)) return nameSearchResults } - /// Searches the samples using the sample's description and the query. + /// Searches through a list of samples using the sample's description and the query. + /// - Parameters: + /// - samples: The `Array` of samples to search through. + /// - query: The `String` to search with. /// - Returns: The samples whose description partially matches the query. - func searchSamplesDescriptions() -> [Sample] { - // Perform a partial text search using the sample's description and - // the query for the samples that are not already found. + func searchDescriptions(in samples: [Sample], with query: String) -> [Sample] { + // Perform a partial text search using the sample's description and the query. let descriptionSearchResults = samples.filter { sample in - sample.description.localizedCaseInsensitiveContains(query) && - !previousSearchResults.contains(sample.name) + sample.description.localizedCaseInsensitiveContains(query) } - previousSearchResults.formUnion(descriptionSearchResults.map(\.name)) return descriptionSearchResults } - /// Searches the samples using the sample's tags and the query. + /// Searches through a list of samples using the sample's tags and the query. + /// - Parameters: + /// - samples: The `Array` of samples to search through. + /// - query: The `String` to search with. /// - Returns: The samples which have a tag that fully matches the query. - func searchSamplesTags() -> [Sample] { - // Perform a full text search using the sample's tags and the query for - // the samples that are not already found. + func searchTags(in samples: [Sample], with query: String) -> [Sample] { + // Perform a full text search using the sample's tags and the query. let tagsSearchResults = samples.filter { sample in sample.tags.contains { tag in tag.localizedCaseInsensitiveCompare(query) == .orderedSame - } && !previousSearchResults.contains(sample.name) + } } return tagsSearchResults } diff --git a/Shared/Supporting Files/Views/CategoryView.swift b/Shared/Supporting Files/Views/CategoryView.swift index 28f7e6c2b..e38bef036 100644 --- a/Shared/Supporting Files/Views/CategoryView.swift +++ b/Shared/Supporting Files/Views/CategoryView.swift @@ -36,9 +36,6 @@ struct CategoryView: View { /// A Boolean value that indicates whether to present the about view. @State private var isAboutViewPresented = false - /// The names of the samples already found in a previous section. - @State var previousSearchResults: Set = [] - var body: some View { Group { if !isSearching { @@ -63,13 +60,10 @@ struct CategoryView: View { } } .onChange(of: query) { _ in - previousSearchResults.removeAll(keepingCapacity: true) - nameSearchResults = searchSamplesNames() - descriptionSearchResults = searchSamplesDescriptions() - tagsSearchResults = searchSamplesTags() + searchSamples(in: samples, with: query) } .onAppear { - nameSearchResults = searchSamplesNames() + searchSamples(in: samples, with: query) } } } @@ -87,4 +81,32 @@ struct CategoryView: View { } } } + + /// Searches through a list of samples to find ones that match the query. + /// - Parameters: + /// - samples: The `Array` of samples to search through. + /// - query: The `String` to search with. + private func searchSamples(in samples: [Sample], with query: String) { + // Show all samples in the name section when query is empty. + guard !query.isEmpty else { + nameSearchResults = samples + return + } + + // The names of the samples already found in a previous section. + var previousSearchResults: Set = [] + + // Update the name section results. + nameSearchResults = searchNames(in: samples, with: query) + previousSearchResults.formUnion(nameSearchResults.map(\.name)) + + // Update the description section results. + descriptionSearchResults = searchDescriptions(in: samples, with: query) + .filter { !previousSearchResults.contains($0.name) } + previousSearchResults.formUnion(descriptionSearchResults.map(\.name)) + + // Update the tags section results. + tagsSearchResults = searchTags(in: samples, with: query) + .filter { !previousSearchResults.contains($0.name) } + } }