Favorites tab for the construction menu (#26347)

* Added fovarite button

* Some fixes in xaml

* added some events for favorite recipes

* set methods for presenter

* fixes for  presenter

* added translates

* reset seach when you select any category

* added some margins

* some fixes from compared

* fixed PR notes about arrays

* deleted controls & margins

* did simpleer with arrays

* review

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
Artjom
2024-06-29 08:10:00 +04:00
committed by GitHub
parent 64af03042a
commit 881c2323fd
4 changed files with 116 additions and 38 deletions

View File

@@ -1,29 +1,33 @@
<DefaultWindow xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.4" Margin="0 0 5 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 0 0 5">
<LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"/>
<OptionButton Name="Category" Access="Public" MinSize="130 0"/>
<OptionButton Name="OptionCategories" Access="Public" MinSize="130 0"/>
</BoxContainer>
<ItemList Name="Recipes" Access="Public" SelectMode="Single" VerticalExpand="True"/>
</BoxContainer>
<Control MinSize="10 0"/>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.6">
<Button Name="FavoriteButton" Visible="false" HorizontalExpand="False"
HorizontalAlignment="Right" Margin="0 0 0 15"/>
<Control>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="0 0 0 5">
<BoxContainer Orientation="Horizontal" Align="Center">
<TextureRect Name="TargetTexture" HorizontalAlignment="Right" Stretch="Keep"/>
<Control MinSize="10 0"/>
<TextureRect Name="TargetTexture" HorizontalAlignment="Right" Stretch="Keep" Margin="0 0 10 0"/>
<BoxContainer Orientation="Vertical">
<RichTextLabel Name="TargetName"/>
<RichTextLabel Name="TargetDesc"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</Control>
<ItemList Name="RecipeStepList" Access="Public" VerticalExpand="True"/>
<ItemList Name="RecipeStepList" Access="Public" VerticalExpand="True" Margin="0 0 0 5"/>
<BoxContainer Orientation="Vertical">
<Button Name="BuildButton" Disabled="True" ToggleMode="True" VerticalExpand="True" SizeFlagsStretchRatio="0.5"/>
<Button Name="BuildButton" Disabled="True" ToggleMode="True"
VerticalExpand="True" SizeFlagsStretchRatio="0.5"/>
<BoxContainer Orientation="Horizontal" VerticalExpand="True" SizeFlagsStretchRatio="0.5">
<Button Name="EraseButton" ToggleMode="True" HorizontalExpand="True" SizeFlagsStretchRatio="0.7"/>
<Button Name="EraseButton" ToggleMode="True"
HorizontalExpand="True" SizeFlagsStretchRatio="0.7"/>
<Button Name="ClearButton" HorizontalExpand="True" SizeFlagsStretchRatio="0.3"/>
</BoxContainer>
</BoxContainer>

View File

@@ -22,7 +22,7 @@ namespace Content.Client.Construction.UI
// It isn't optimal to expose UI controls like this, but the UI control design is
// questionable so it can't be helped.
string[] Categories { get; set; }
OptionButton Category { get; }
OptionButton OptionCategories { get; }
bool EraseButtonPressed { get; set; }
bool BuildButtonPressed { get; set; }
@@ -32,12 +32,13 @@ namespace Content.Client.Construction.UI
event EventHandler<(string search, string catagory)> PopulateRecipes;
event EventHandler<ItemList.Item?> RecipeSelected;
event EventHandler RecipeFavorited;
event EventHandler<bool> BuildButtonToggled;
event EventHandler<bool> EraseButtonToggled;
event EventHandler ClearAllGhosts;
void ClearRecipeInfo();
void SetRecipeInfo(string name, string description, Texture iconTexture, bool isItem);
void SetRecipeInfo(string name, string description, Texture iconTexture, bool isItem, bool isFavorite);
void ResetPlacement();
#region Window Control
@@ -84,10 +85,12 @@ namespace Content.Client.Construction.UI
Recipes.OnItemSelected += obj => RecipeSelected?.Invoke(this, obj.ItemList[obj.ItemIndex]);
Recipes.OnItemDeselected += _ => RecipeSelected?.Invoke(this, null);
SearchBar.OnTextChanged += _ => PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[Category.SelectedId]));
Category.OnItemSelected += obj =>
SearchBar.OnTextChanged += _ =>
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[OptionCategories.SelectedId]));
OptionCategories.OnItemSelected += obj =>
{
Category.SelectId(obj.Id);
OptionCategories.SelectId(obj.Id);
SearchBar.SetText(string.Empty);
PopulateRecipes?.Invoke(this, (SearchBar.Text, Categories[obj.Id]));
};
@@ -97,12 +100,14 @@ namespace Content.Client.Construction.UI
ClearButton.OnPressed += _ => ClearAllGhosts?.Invoke(this, EventArgs.Empty);
EraseButton.Text = Loc.GetString("construction-menu-eraser-mode");
EraseButton.OnToggled += args => EraseButtonToggled?.Invoke(this, args.Pressed);
FavoriteButton.OnPressed += args => RecipeFavorited?.Invoke(this, EventArgs.Empty);
}
public event EventHandler? ClearAllGhosts;
public event EventHandler<(string search, string catagory)>? PopulateRecipes;
public event EventHandler<ItemList.Item?>? RecipeSelected;
public event EventHandler? RecipeFavorited;
public event EventHandler<bool>? BuildButtonToggled;
public event EventHandler<bool>? EraseButtonToggled;
@@ -112,13 +117,17 @@ namespace Content.Client.Construction.UI
EraseButton.Pressed = false;
}
public void SetRecipeInfo(string name, string description, Texture iconTexture, bool isItem)
public void SetRecipeInfo(
string name, string description, Texture iconTexture, bool isItem, bool isFavorite)
{
BuildButton.Disabled = false;
BuildButton.Text = Loc.GetString(isItem ? "construction-menu-place-ghost" : "construction-menu-craft");
TargetName.SetMessage(name);
TargetDesc.SetMessage(description);
TargetTexture.Texture = iconTexture;
FavoriteButton.Visible = true;
FavoriteButton.Text = Loc.GetString(
isFavorite ? "construction-add-favorite-button" : "construction-remove-from-favorite-button");
}
public void ClearRecipeInfo()
@@ -127,6 +136,7 @@ namespace Content.Client.Construction.UI
TargetName.SetMessage(string.Empty);
TargetDesc.SetMessage(string.Empty);
TargetTexture.Texture = null;
FavoriteButton.Visible = false;
RecipeStepList.Clear();
}
}

View File

@@ -36,7 +36,10 @@ namespace Content.Client.Construction.UI
private ConstructionSystem? _constructionSystem;
private ConstructionPrototype? _selected;
private List<ConstructionPrototype> _favoritedRecipes = [];
private string _selectedCategory = string.Empty;
private string _favoriteCatName = "construction-category-favorites";
private string _forAllCategoryName = "construction-category-all";
private bool CraftingAvailable
{
get => _uiManager.GetActiveUIWidget<GameTopMenuBar>().CraftingButton.Visible;
@@ -65,7 +68,7 @@ namespace Content.Client.Construction.UI
else
_constructionView.OpenCentered();
if(_selected != null)
if (_selected != null)
PopulateInfo(_selected);
}
else
@@ -105,9 +108,10 @@ namespace Content.Client.Construction.UI
_constructionView.EraseButtonPressed = b;
};
_constructionView.RecipeFavorited += (_, _) => OnViewFavoriteRecipe();
PopulateCategories();
OnViewPopulateRecipes(_constructionView, (string.Empty, string.Empty));
}
public void OnHudCraftingButtonToggled(ButtonToggledEventArgs args)
@@ -154,6 +158,13 @@ namespace Content.Client.Construction.UI
recipesList.Clear();
var recipes = new List<ConstructionPrototype>();
var isEmptyCategory = string.IsNullOrEmpty(category) || category == _forAllCategoryName;
if (isEmptyCategory)
_selectedCategory = string.Empty;
else
_selectedCategory = category;
foreach (var recipe in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>())
{
if (recipe.Hide)
@@ -170,11 +181,20 @@ namespace Content.Client.Construction.UI
continue;
}
if (!string.IsNullOrEmpty(category) && category != "construction-category-all")
if (!isEmptyCategory)
{
if (category == _favoriteCatName)
{
if (!_favoritedRecipes.Contains(recipe))
{
if (recipe.Category != category)
continue;
}
}
else if (recipe.Category != category)
{
continue;
}
}
recipes.Add(recipe);
}
@@ -189,13 +209,10 @@ namespace Content.Client.Construction.UI
// There is apparently no way to set which
}
private void PopulateCategories()
private void PopulateCategories(string? selectCategory = null)
{
var uniqueCategories = new HashSet<string>();
// hard-coded to show all recipes
uniqueCategories.Add("construction-category-all");
foreach (var prototype in _prototypeManager.EnumeratePrototypes<ConstructionPrototype>())
{
var category = prototype.Category;
@@ -204,25 +221,49 @@ namespace Content.Client.Construction.UI
uniqueCategories.Add(category);
}
_constructionView.Category.Clear();
var isFavorites = _favoritedRecipes.Count > 0;
var categoriesArray = new string[isFavorites ? uniqueCategories.Count + 2 : uniqueCategories.Count + 1];
var array = uniqueCategories.OrderBy(Loc.GetString).ToArray();
Array.Sort(array);
// hard-coded to show all recipes
var idx = 0;
categoriesArray[idx++] = _forAllCategoryName;
for (var i = 0; i < array.Length; i++)
// hard-coded to show favorites if it need
if (isFavorites)
{
var category = array[i];
_constructionView.Category.AddItem(Loc.GetString(category), i);
categoriesArray[idx++] = _favoriteCatName;
}
_constructionView.Categories = array;
var sortedProtoCategories = uniqueCategories.OrderBy(Loc.GetString);
foreach (var cat in sortedProtoCategories)
{
categoriesArray[idx++] = cat;
}
_constructionView.OptionCategories.Clear();
for (var i = 0; i < categoriesArray.Length; i++)
{
_constructionView.OptionCategories.AddItem(Loc.GetString(categoriesArray[i]), i);
if (!string.IsNullOrEmpty(selectCategory) && selectCategory == categoriesArray[i])
_constructionView.OptionCategories.SelectId(i);
}
_constructionView.Categories = categoriesArray;
}
private void PopulateInfo(ConstructionPrototype prototype)
{
var spriteSys = _systemManager.GetEntitySystem<SpriteSystem>();
_constructionView.ClearRecipeInfo();
_constructionView.SetRecipeInfo(prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon), prototype.Type != ConstructionType.Item);
_constructionView.SetRecipeInfo(
prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon),
prototype.Type != ConstructionType.Item,
!_favoritedRecipes.Contains(prototype));
var stepList = _constructionView.RecipeStepList;
GenerateStepList(prototype, stepList);
@@ -240,7 +281,7 @@ namespace Content.Client.Construction.UI
var text = entry.Arguments != null
? Loc.GetString(entry.Localization, entry.Arguments) : Loc.GetString(entry.Localization);
if (entry.EntryNumber is {} number)
if (entry.EntryNumber is { } number)
{
text = Loc.GetString("construction-presenter-step-wrapper",
("step-number", number), ("text", text));
@@ -332,6 +373,26 @@ namespace Content.Client.Construction.UI
if (args.System is ConstructionSystem) SystemBindingChanged(null);
}
private void OnViewFavoriteRecipe()
{
if (_selected is not ConstructionPrototype recipe)
return;
if (!_favoritedRecipes.Remove(_selected))
_favoritedRecipes.Add(_selected);
if (_selectedCategory == _favoriteCatName)
{
if (_favoritedRecipes.Count > 0)
OnViewPopulateRecipes(_constructionView, (string.Empty, _favoriteCatName));
else
OnViewPopulateRecipes(_constructionView, (string.Empty, string.Empty));
}
PopulateInfo(_selected);
PopulateCategories(_selectedCategory);
}
private void SystemBindingChanged(ConstructionSystem? newSystem)
{
if (newSystem is null)

View File

@@ -10,3 +10,6 @@ construction-category-tiles = Tiles
construction-category-utilities = Utilities
construction-category-misc = Misc
construction-category-clothing = Clothing
construction-category-favorites = Favorites
construction-add-favorite-button = Add to favorites
construction-remove-from-favorite-button = Remove from favorites