Skip to content

Commit

Permalink
Add bag editing features (#66)
Browse files Browse the repository at this point in the history
* Stub out bag tab

* Get tabs for each pouch

* Implement inventory management basics

* Add button to delete items

* Remove .idea

* Ignore .idea

* Use expression body, static method

* Adjust buttons

* Adjust grid, fix headers

* Show proper names for pouches

* Fix count max

* Improve perf, add flags, restrict items to proper pouches

* Remove commented code, stub item-sprite CSS

* Remove redundant assignments

* Add sorting options
  • Loading branch information
codemonkey85 authored Nov 21, 2024
1 parent 30d0792 commit ed9780c
Show file tree
Hide file tree
Showing 4 changed files with 313 additions and 1 deletion.
173 changes: 173 additions & 0 deletions Pkmds.Web/Components/MainTabPages/BagTab.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
@inherits BasePkmdsComponent

@if (AppState.SaveFile is { } saveFile && Inventory is not null)
{
<MudTabs Outlined
Rounded
Border>
@foreach (var pouch in Inventory)
{
<MudTabPanel Text="@GetPouchName(pouch)">
<MudStack>
<MudStack Row>
<MudButton OnClick="@SaveChanges"
Color="@Color.Primary"
Variant="@Variant.Filled"
StartIcon="@Icons.Material.Filled.Save">
Save
</MudButton>
<MudButton OnClick="@(() => SortByName(pouch))"
Color="@Color.Default"
Variant="@Variant.Filled"
StartIcon="@Icons.Material.Filled.SortByAlpha">
Sort By Name
</MudButton>
<MudButton OnClick="@(() => SortByCount(pouch))"
Color="@Color.Default"
Variant="@Variant.Filled"
StartIcon="@Icons.Material.Filled.Sort">
Sort By Count
</MudButton>
<MudButton OnClick="@(() => SortByIndex(pouch))"
Color="@Color.Default"
Variant="@Variant.Filled"
StartIcon="@Icons.Material.Filled.Sort">
Sort By Index
</MudButton>
</MudStack>
<MudDataGrid T="InventoryItem"
Items="@pouch.Items"
ReadOnly="@false"
EditMode="@DataGridEditMode.Cell"
SortMode="@SortMode.None"
Dense
Hover
Striped
FixedHeader
EditTrigger="@DataGridEditTrigger.OnRowClick"
Height="calc(100vh - 240px)"
Virtualize>
<Columns>
<PropertyColumn Property="@(item => item.Index)"
Title="Item">
<EditTemplate>
<MudStack Row
Spacing="1"
AlignItems="@AlignItems.Center">
<MudAutocomplete T="@ComboItem"
Variant="@Variant.Outlined"
Value="@GetItem(context)"
ValueChanged="@(newItem => SetItem(context, newItem))"
SearchFunc="@((string searchString, CancellationToken _) => SearchItemNames(pouch, searchString))"
ToStringFunc="@(item => { return ItemList[context.Item.Index]; })">
<ItemTemplate Context="item">
<MudStack Row>
@if (item.Value != 0)
{
<object class="item-sprite"
type="image/png"
data="@SpriteHelper.GetItemSpriteFilename(item.Value, saveFile.Context)"
title="@item.Text">
<img class="pkm-sprite"
src="@SpriteHelper.ItemFallbackImageFileName"
title="@item.Text">
</object>
}
<MudText>
@item.Text
</MudText>
</MudStack>
</ItemTemplate>
</MudAutocomplete>
@if (context.Item.Index != 0)
{
var itemText = AppService.GetItemComboItem(context.Item.Index)?.Text;
<object class="item-sprite"
type="image/png"
data="@SpriteHelper.GetItemSpriteFilename(context.Item.Index, saveFile.Context)"
title="@itemText">
<img class="pkm-sprite"
src="@SpriteHelper.ItemFallbackImageFileName"
title="@itemText">
</object>
}
</MudStack>
</EditTemplate>
</PropertyColumn>
<PropertyColumn Property="@(item => item.Count)"
Title="Count">
<EditTemplate>
<MudNumericField T="@int"
Variant="@Variant.Outlined"
Max="@pouch.MaxCount"
@bind-Value="@context.Item.Count" />
</EditTemplate>
</PropertyColumn>
@if (HasFreeSpace)
{
<TemplateColumn Title="Free">
<EditTemplate>
@if (context.Item is IItemFreeSpace freeSpaceItem)
{
<MudCheckBox Label="Free Space"
Value="@freeSpaceItem.IsFreeSpace"
ValueChanged="@((bool value) => freeSpaceItem.IsFreeSpace = value)" />
}
</EditTemplate>
</TemplateColumn>
}
@if (HasFreeSpaceIndex)
{
<TemplateColumn Title="Free">
<EditTemplate>
@if (context.Item is IItemFreeSpaceIndex freeSpaceIndexItem)
{
<MudNumericField T="@uint"
Variant="@Variant.Outlined"
@bind-Value="@freeSpaceIndexItem.FreeSpaceIndex" />
}
</EditTemplate>
</TemplateColumn>
}
@if (HasFavorite)
{
<TemplateColumn Title="Favorite">
<EditTemplate>
@if (context.Item is IItemFavorite favoriteItem)
{
<MudCheckBox Label="Favorite"
Value="@favoriteItem.IsFavorite"
ValueChanged="@((bool value) => favoriteItem.IsFavorite = value)" />
}
</EditTemplate>
</TemplateColumn>
}
@if (HasNew)
{
<TemplateColumn Title="New">
<EditTemplate>
@if (context.Item is IItemNewFlag newFlagItem)
{
<MudCheckBox Label="New"
Value="@newFlagItem.IsNew"
ValueChanged="@((bool value) => newFlagItem.IsNew = value)" />
}
</EditTemplate>
</TemplateColumn>
}
<TemplateColumn>
<EditTemplate>
<MudIconButton OnClick="@(() => DeleteItem(context, pouch))"
ButtonType="@ButtonType.Button"
Color="@Color.Error"
Variant="@Variant.Filled"
Icon="@Icons.Material.Filled.Delete" />
</EditTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudStack>
</MudTabPanel>
}
</MudTabs>
}
128 changes: 128 additions & 0 deletions Pkmds.Web/Components/MainTabPages/BagTab.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
namespace Pkmds.Web.Components.MainTabPages;

public partial class BagTab
{
[Parameter, EditorRequired]
public IReadOnlyList<InventoryPouch>? Inventory { get; set; }

private string[] ItemList { get; set; } = [];

private bool HasFreeSpace { get; set; }

private bool HasFreeSpaceIndex { get; set; }

private bool HasFavorite { get; set; }

private bool HasNew { get; set; }

private bool IsSortedByName { get; set; } = true; // Set as true so first sort is ascending

private bool IsSortedByCount { get; set; } = true; // Set as true so first sort is ascending

private bool IsSortedByIndex { get; set; } = true; // Set as true so first sort is ascending

protected override void OnParametersSet()
{
base.OnParametersSet();

if (Inventory is null || AppState is not { SaveFile: { } saveFile })
{
return;
}

ItemList = [.. GameInfo.Strings.GetItemStrings(saveFile.Context, saveFile.Version)];

for (var i = 0; i < ItemList.Length; i++)
{
if (string.IsNullOrEmpty(ItemList[i]))
{
ItemList[i] = $"(Item #{i:000})";
}
}

var item0 = Inventory[0].Items[0];

HasFreeSpace = item0 is IItemFreeSpace;
HasFreeSpaceIndex = item0 is IItemFreeSpaceIndex;
HasFavorite = item0 is IItemFavorite;
HasNew = item0 is IItemNewFlag;
}

private void SaveChanges()
{
if (AppState?.SaveFile is null || Inventory is null)
{
return;
}

foreach (var pouch in Inventory)
{
pouch.ClearCount0();
}

AppState.SaveFile.Inventory = Inventory;
}

private ComboItem GetItem(CellContext<InventoryItem> context) =>
AppService.GetItemComboItem(context.Item.Index);

private static void SetItem(CellContext<InventoryItem> context, ComboItem item) =>
context.Item.Index = item.Value;

private void DeleteItem(CellContext<InventoryItem> context, InventoryPouch pouch)
{
if (Inventory is null)
{
return;
}

context.Item.Clear();
pouch.ClearCount0();
}

private static string GetPouchName(InventoryPouch pouch) => pouch.Type switch
{
InventoryType.None => "None",
InventoryType.Items => "Items",
InventoryType.KeyItems => "Key Items",
InventoryType.TMHMs => "TMs/HMs",
InventoryType.Medicine => "Medicine",
InventoryType.Berries => "Berries",
InventoryType.Balls => "Balls",
InventoryType.BattleItems => "Battle Items",
InventoryType.MailItems => "Mail Items",
InventoryType.PCItems => "PC Items",
InventoryType.FreeSpace => "Free Space",
InventoryType.ZCrystals => "Z-Crystals",
InventoryType.Candy => "Candy",
InventoryType.Treasure => "Treasure",
InventoryType.Ingredients => "Ingredients",
_ => pouch.Type.ToString()
};

private string[] GetStringsForPouch(ReadOnlySpan<ushort> items, bool sort = true)
{
string[] res = new string[items.Length + 1];
for (int i = 0; i < res.Length - 1; i++)
res[i] = ItemList[items[i]];
res[items.Length] = ItemList[0];
if (sort)
Array.Sort(res);
return res;
}

private void SortByName(InventoryPouch pouch) => pouch.SortByName(ItemList, reverse: IsSortedByName = !IsSortedByName);

private void SortByCount(InventoryPouch pouch) => pouch.SortByCount(reverse: IsSortedByCount = !IsSortedByCount);

private void SortByIndex(InventoryPouch pouch) => pouch.SortByIndex(reverse: IsSortedByIndex = !IsSortedByIndex);

private Task<IEnumerable<ComboItem>> SearchItemNames(InventoryPouch pouch, string searchString)
{
var itemsToSearch = GetStringsForPouch(pouch.GetAllItems());

return Task.FromResult(ItemList
.Select((name, index) => new ComboItem(name, index))
.Where(x => itemsToSearch.Contains(x.Text) && x.Text.Contains(searchString, StringComparison.OrdinalIgnoreCase)));
}
}
10 changes: 9 additions & 1 deletion Pkmds.Web/Components/SaveFileComponent.razor
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ else
</MudTabPanel>

<MudTabPanel Text="Trainer">
<TrainerInfoTab />
<div class="mt-3">
<TrainerInfoTab />
</div>
</MudTabPanel>

<MudTabPanel Text="Bag">
<div class="mt-3">
<BagTab Inventory="@AppState.SaveFile.Inventory" />
</div>
</MudTabPanel>

</MudTabs>
Expand Down
3 changes: 3 additions & 0 deletions Pkmds.Web/wwwroot/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ pkm-sprite {
align-self: center;
}

item-sprite {
}

.slot-fill :hover {
transform-origin: center;
animation: bounce 500ms linear infinite;
Expand Down

0 comments on commit ed9780c

Please sign in to comment.