diff --git a/CHANGELOG.md b/CHANGELOG.md index d143c114de..798f42c1a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Shrubs, a system for spawning smaller tree-like plants into the world. - Waterfalls - Sailing boat (currently requires spawning in) +- Added a filter search function for crafting menu, use "input:_____" to search for recipe inputs - Added catalan (Catalonia) language translation ### Changed diff --git a/voxygen/src/hud/crafting.rs b/voxygen/src/hud/crafting.rs index 32907a42b0..bd6a325981 100644 --- a/voxygen/src/hud/crafting.rs +++ b/voxygen/src/hud/crafting.rs @@ -217,6 +217,21 @@ pub struct State { selected_recipe: Option, } +enum SearchFilter { + None, + Input, + Nonexistant, +} + +impl SearchFilter { + fn parse_from_str(string: &str) -> Self { + match string { + "input" => Self::Input, + _ => Self::Nonexistant, + } + } +} + impl<'a> Widget for Crafting<'a> { type Event = Vec; type State = State; @@ -407,6 +422,29 @@ impl<'a> Widget for Crafting<'a> { .set(state.ids.category_imgs[i], ui); } + // TODO: Consider UX for filtering searches, maybe a checkbox or a dropdown if + // more filters gets added + let mut _lower_case_search = String::new(); + let (search_filter, search_keys) = { + if let Some(key) = &self.show.crafting_search_key { + _lower_case_search = key.as_str().to_lowercase(); + _lower_case_search + .split_once(':') + .map(|(filter, key)| { + ( + SearchFilter::parse_from_str(filter), + key.split_whitespace().collect(), + ) + }) + .unwrap_or(( + SearchFilter::None, + _lower_case_search.split_whitespace().collect(), + )) + } else { + (SearchFilter::None, vec![]) + } + }; + // First available recipes, then ones with available materials, // then unavailable ones, each sorted by quality and then alphabetically // In the tuple, "name" is the recipe book key, and "recipe.output.0.name()" @@ -415,16 +453,24 @@ impl<'a> Widget for Crafting<'a> { .client .recipe_book() .iter() - .filter(|(_, recipe)| { - let output_name = recipe.output.0.name.to_lowercase(); - if let Some(key) = &self.show.crafting_search_key { - key.as_str() - .to_lowercase() - .split_whitespace() - .all(|substring| output_name.contains(substring)) - } else { - true - } + .filter(|(_, recipe)| match search_filter { + SearchFilter::None => { + let output_name = recipe.output.0.name.to_lowercase(); + search_keys + .iter() + .all(|&substring| output_name.contains(substring)) + }, + SearchFilter::Input => recipe.inputs().any(|(input, _)| { + let input_name = match input { + RecipeInput::Item(def) => def.name.as_str(), + RecipeInput::Tag(tag) => tag.name(), + } + .to_lowercase(); + search_keys + .iter() + .all(|&substring| input_name.contains(substring)) + }), + _ => false, }) .map(|(name, recipe)| { let has_materials = self.client.available_recipes().get(name.as_str()).is_some();