Add favorite option to items.

This commit is contained in:
Ottermandias 2023-10-06 01:23:26 +02:00
parent 00883943cd
commit ea4fb49c0f
11 changed files with 211 additions and 31 deletions

View file

@ -22,6 +22,7 @@ public sealed class ObjectUnlocked : EventWrapper<Action<ObjectUnlocked.Type, ui
public enum Priority
{
/// <seealso cref="Gui.Tabs.UnlocksTab.UnlockTable.OnObjectUnlock"/>
/// <remarks> Currently used as a hack to make the unlock table dirty in it. If anything else starts using this, rework. </remarks>
UnlockTable = 0,
}

View file

@ -18,6 +18,9 @@ public enum ColorId
AutomationActorAvailable,
AutomationActorUnavailable,
HeaderButtons,
FavoriteStarOn,
FavoriteStarHovered,
FavoriteStarOff,
}
public static class Colors
@ -40,6 +43,9 @@ public static class Colors
ColorId.AutomationActorAvailable => (0xFFFFFFFF, "Automation Actor Available", "A character associated with the given automated design set is currently visible." ),
ColorId.AutomationActorUnavailable => (0xFF808080, "Automation Actor Unavailable", "No character associated with the given automated design set is currently visible." ),
ColorId.HeaderButtons => (0xFFFFF0C0, "Header Buttons", "The text and border color of buttons in the header, like the Incognito toggle." ),
ColorId.FavoriteStarOn => (0xFF40D0D0, "Favored Item", "The color of the star for favored items and of the border in the unlock overview tab." ),
ColorId.FavoriteStarHovered => (0xFFD040D0, "Favorite Star Hovered", "The color of the star for favored items when it is hovered." ),
ColorId.FavoriteStarOff => (0x20808080, "Favorite Star Outline", "The color of the star for items that are not favored when it is not hovered." ),
_ => (0x00000000, string.Empty, string.Empty ),
// @formatter:on
};

View file

@ -10,6 +10,7 @@ using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.Services;
using Glamourer.Structs;
using Glamourer.Unlocks;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
@ -37,7 +38,8 @@ public class EquipmentDrawer
private float _requiredComboWidthUnscaled;
private float _requiredComboWidth;
public EquipmentDrawer(IDataManager gameData, ItemManager items, CodeService codes, TextureService textures, Configuration config,
public EquipmentDrawer(FavoriteManager favorites, IDataManager gameData, ItemManager items, CodeService codes, TextureService textures,
Configuration config,
GPoseService gPose)
{
_items = items;
@ -48,7 +50,7 @@ public class EquipmentDrawer
_stainData = items.Stains;
_stainCombo = new FilterComboColors(DefaultWidth - 20,
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))), Glamourer.Log);
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log)).ToArray();
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log, favorites)).ToArray();
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
foreach (var type in Enum.GetValues<FullEquipType>())
{

View file

@ -2,6 +2,7 @@
using System.Linq;
using Dalamud.Plugin.Services;
using Glamourer.Services;
using Glamourer.Unlocks;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
@ -16,13 +17,15 @@ namespace Glamourer.Gui.Equipment;
public sealed class ItemCombo : FilterComboCache<EquipItem>
{
public readonly string Label;
private ItemId _currentItem;
private float _innerWidth;
private readonly FavoriteManager _favorites;
public readonly string Label;
private ItemId _currentItem;
private float _innerWidth;
public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot, Logger log)
: base(() => GetItems(items, slot), log)
public ItemCombo(IDataManager gameData, ItemManager items, EquipSlot slot, Logger log, FavoriteManager favorites)
: base(() => GetItems(favorites, items, slot), log)
{
_favorites = favorites;
Label = GetLabel(gameData, slot);
_currentItem = ItemManager.NothingId(slot);
SearchByParts = true;
@ -59,7 +62,15 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
{
var obj = Items[globalIdx];
var name = ToString(obj);
var ret = ImGui.Selectable(name, selected);
if (UiHelpers.DrawFavoriteStar(_favorites, obj) && CurrentSelectionIdx == globalIdx)
{
CurrentSelectionIdx = -1;
_currentItem = obj.ItemId;
CurrentSelection = default;
}
ImGui.SameLine();
var ret = ImGui.Selectable(name, selected);
ImGui.SameLine();
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF808080);
ImGuiUtil.RightAlign($"({obj.ModelString})");
@ -92,7 +103,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
};
}
private static IReadOnlyList<EquipItem> GetItems(ItemManager items, EquipSlot slot)
private static IReadOnlyList<EquipItem> GetItems(FavoriteManager favorites, ItemManager items, EquipSlot slot)
{
var nothing = ItemManager.NothingItem(slot);
if (!items.ItemService.AwaitedService.TryGetValue(slot.ToEquipType(), out var list))
@ -104,6 +115,6 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
var enumerable = list.AsEnumerable();
if (slot.IsEquipment())
enumerable = enumerable.Append(ItemManager.SmallClothesItem(slot));
return enumerable.OrderBy(i => i.Name).Prepend(nothing).ToList();
return enumerable.OrderByDescending(favorites.Contains).ThenBy(i => i.Name).Prepend(nothing).ToList();
}
}

View file

@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface.Utility;
using Glamourer.Customization;
using Glamourer.Interop;
@ -24,6 +25,7 @@ public class UnlockOverview
private readonly TextureService _textures;
private readonly CodeService _codes;
private readonly JobService _jobs;
private readonly FavoriteManager _favorites;
private static readonly Vector4 UnavailableTint = new(0.3f, 0.3f, 0.3f, 1.0f);
@ -70,7 +72,7 @@ public class UnlockOverview
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureService textures, CodeService codes,
JobService jobs)
JobService jobs, FavoriteManager favorites)
{
_items = items;
_customizations = customizations;
@ -80,6 +82,7 @@ public class UnlockOverview
_textures = textures;
_codes = codes;
_jobs = jobs;
_favorites = favorites;
}
public void Draw()
@ -166,10 +169,12 @@ public class UnlockOverview
var (icon, size) = (iconHandle.ImGuiHandle, new Vector2(iconHandle.Width, iconHandle.Height));
ImGui.Image(icon, iconSize, Vector2.Zero, Vector2.One, unlocked || _codes.EnabledShirts ? Vector4.One : UnavailableTint);
if (_favorites.Contains(item))
ImGui.GetWindowDrawList().AddRect(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), ColorId.FavoriteStarOn.Value(),
2 * ImGuiHelpers.GlobalScale, ImDrawFlags.RoundCornersAll, 4 * ImGuiHelpers.GlobalScale);
if (ImGui.IsItemClicked())
{
// TODO link
}
Glamourer.Messager.Chat.Print(new SeStringBuilder().AddItemLink(item.ItemId.Id, false).BuiltString);
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _tooltip.Player(out var state))
_tooltip.ApplyItem(state, item);

View file

@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Events;
@ -24,19 +25,20 @@ public class UnlockTable : Table<EquipItem>, IDisposable
private readonly ObjectUnlocked _event;
public UnlockTable(ItemManager items, TextureService textures, ItemUnlockManager itemUnlocks,
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event, JobService jobs)
PenumbraChangedItemTooltip tooltip, ObjectUnlocked @event, JobService jobs, FavoriteManager favorites)
: base("ItemUnlockTable", new ItemList(items),
new NameColumn(textures, tooltip) { Label = "Item Name..." },
new SlotColumn() { Label = "Equip Slot" },
new TypeColumn() { Label = "Item Type..." },
new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" },
new ItemIdColumn() { Label = "Item Id..." },
new ModelDataColumn(items) { Label = "Model Data..." },
new JobColumn(jobs) { Label = "Jobs" },
new LevelColumn() { Label = "Level..." },
new DyableColumn() { Label = "Dye" },
new CrestColumn() { Label = "Crest" },
new TradableColumn() { Label = "Trade" }
new FavoriteColumn(favorites, @event) { Label = "F" },
new NameColumn(textures, tooltip) { Label = "Item Name..." },
new SlotColumn() { Label = "Equip Slot" },
new TypeColumn() { Label = "Item Type..." },
new UnlockDateColumn(itemUnlocks) { Label = "Unlocked" },
new ItemIdColumn() { Label = "Item Id..." },
new ModelDataColumn(items) { Label = "Model Data..." },
new JobColumn(jobs) { Label = "Jobs" },
new LevelColumn() { Label = "Level..." },
new DyableColumn() { Label = "Dye" },
new CrestColumn() { Label = "Crest" },
new TradableColumn() { Label = "Trade" }
)
{
_event = @event;
@ -48,6 +50,37 @@ public class UnlockTable : Table<EquipItem>, IDisposable
public void Dispose()
=> _event.Unsubscribe(OnObjectUnlock);
private sealed class FavoriteColumn : YesNoColumn
{
public override float Width
=> ImGui.GetFrameHeightWithSpacing();
private readonly FavoriteManager _favorites;
private readonly ObjectUnlocked _hackEvent; // used to trigger the table dirty.
public FavoriteColumn(FavoriteManager favorites, ObjectUnlocked hackEvent)
{
_favorites = favorites;
_hackEvent = hackEvent;
}
protected override bool GetValue(EquipItem item)
=> _favorites.Contains(item);
public override void DrawColumn(EquipItem item, int idx)
{
ImGui.AlignTextToFramePadding();
if (UiHelpers.DrawFavoriteStar(_favorites, item))
_hackEvent.Invoke(ObjectUnlocked.Type.Customization, 0, DateTimeOffset.Now);
}
public override bool FilterFunc(EquipItem item)
=> FilterValue.HasFlag(_favorites.Contains(item) ? YesNoFlag.Yes : YesNoFlag.No);
public override int Compare(EquipItem lhs, EquipItem rhs)
=> _favorites.Contains(rhs).CompareTo(_favorites.Contains(lhs));
}
private sealed class NameColumn : ColumnString<EquipItem>
{
private readonly TextureService _textures;
@ -75,9 +108,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
if (ImGui.Selectable(item.Name))
{
// TODO link
}
Glamourer.Messager.Chat.Print(new SeStringBuilder().AddItemLink(item.ItemId.Id, false).BuiltString);
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && _tooltip.Player(out var state))
_tooltip.ApplyItem(state, item);

View file

@ -1,9 +1,11 @@
using System;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Glamourer.Customization;
using Glamourer.Services;
using Glamourer.Structs;
using Glamourer.Unlocks;
using ImGuiNET;
using Lumina.Misc;
using OtterGui;
@ -119,4 +121,26 @@ public static class UiHelpers
(true, false) => (true, false),
(false, true) => (false, true),
};
}
public static bool DrawFavoriteStar(FavoriteManager favorites, EquipItem item)
{
var favorite = favorites.Contains(item);
var hovering = ImGui.IsMouseHoveringRect(ImGui.GetCursorScreenPos(),
ImGui.GetCursorScreenPos() + new Vector2(ImGui.GetTextLineHeight()));
using var font = ImRaii.PushFont(UiBuilder.IconFont);
using var c = ImRaii.PushColor(ImGuiCol.Text,
hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value());
ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString());
if (ImGui.IsItemClicked())
{
if (favorite)
favorites.Remove(item);
else
favorites.TryAdd(item);
return true;
}
return false;
}
}

View file

@ -34,6 +34,7 @@ public class BackupService
new(fileNames.AutomationFile),
new(fileNames.UnlockFileCustomize),
new(fileNames.UnlockFileItems),
new(fileNames.FavoriteFile),
};
list.AddRange(fileNames.Designs());

View file

@ -15,6 +15,7 @@ public class FilenameService
public readonly string AutomationFile;
public readonly string UnlockFileCustomize;
public readonly string UnlockFileItems;
public readonly string FavoriteFile;
public FilenameService(DalamudPluginInterface pi)
{
@ -26,6 +27,7 @@ public class FilenameService
UnlockFileCustomize = Path.Combine(ConfigDirectory, "unlocks_customize.json");
UnlockFileItems = Path.Combine(ConfigDirectory, "unlocks_items.json");
DesignDirectory = Path.Combine(ConfigDirectory, "designs");
FavoriteFile = Path.Combine(ConfigDirectory, "favorites.json");
}

View file

@ -56,7 +56,8 @@ public static class ServiceManager
.AddSingleton<CodeService>()
.AddSingleton<ConfigMigrationService>()
.AddSingleton<Configuration>()
.AddSingleton<TextureService>();
.AddSingleton<TextureService>()
.AddSingleton<FavoriteManager>();
private static IServiceCollection AddEvents(this IServiceCollection services)
=> services.AddSingleton<VisorStateChanged>()

View file

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Dalamud.Interface.Internal.Notifications;
using Glamourer.Services;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui.Classes;
using Penumbra.GameData.Structs;
namespace Glamourer.Unlocks;
public class FavoriteManager : ISavable
{
private readonly SaveService _saveService;
private readonly HashSet<ItemId> _favorites = new();
public FavoriteManager(SaveService saveService)
{
_saveService = saveService;
Load();
}
private void Load()
{
var file = _saveService.FileNames.FavoriteFile;
if (!File.Exists(file))
return;
try
{
var text = File.ReadAllText(file);
var array = JsonConvert.DeserializeObject<uint[]>(text) ?? Array.Empty<uint>();
_favorites.UnionWith(array.Select(i => (ItemId)i));
}
catch (Exception ex)
{
Glamourer.Messager.NotificationMessage(ex, "Could not read Favorite file.", NotificationType.Error);
}
}
public string ToFilename(FilenameService fileNames)
=> fileNames.FavoriteFile;
private void Save()
=> _saveService.DelaySave(this);
public void Save(StreamWriter writer)
{
using var j = new JsonTextWriter(writer)
{
Formatting = Formatting.Indented,
};
j.WriteStartArray();
foreach (var item in _favorites)
j.WriteValue(item.Id);
j.WriteEndArray();
}
public bool TryAdd(EquipItem item)
=> TryAdd(item.ItemId);
public bool TryAdd(ItemId item)
{
if (item.Id == 0 || !_favorites.Add(item))
return false;
Save();
return true;
}
public bool Remove(EquipItem item)
=> Remove(item.ItemId);
public bool Remove(ItemId item)
{
if (!_favorites.Remove(item))
return false;
Save();
return true;
}
public IEnumerator<ItemId> GetEnumerator()
=> _favorites.GetEnumerator();
public int Count
=> _favorites.Count;
public bool Contains(EquipItem item)
=> _favorites.Contains(item.ItemId);
public bool Contains(ItemId item)
=> _favorites.Contains(item);
}