Adjust filter logic

This commit is contained in:
Liza 2024-12-27 18:25:59 +01:00
parent cad6c30b80
commit 95d19455de
Signed by: liza
GPG Key ID: 2C41B84815CF6445
3 changed files with 94 additions and 113 deletions

View File

@ -10,44 +10,30 @@ namespace Questionable.Data;
internal sealed class JournalData internal sealed class JournalData
{ {
private readonly IDataManager _dataManager;
private readonly QuestData _questData;
public JournalData(IDataManager dataManager, QuestData questData) public JournalData(IDataManager dataManager, QuestData questData)
{ {
_dataManager = dataManager; var genres = dataManager.GetExcelSheet<JournalGenre>()
_questData = questData;
Reload();
}
public List<Genre> Genres { get; set; }
public List<Category> Categories { get; set; }
public List<Section> Sections { get; set; }
public void Reload()
{
var genres = _dataManager.GetExcelSheet<JournalGenre>()
.Where(x => x.RowId > 0 && x.Icon > 0) .Where(x => x.RowId > 0 && x.Icon > 0)
.Select(x => new Genre(x, _questData.GetAllByJournalGenre(x.RowId))) .Select(x => new Genre(x, questData.GetAllByJournalGenre(x.RowId)))
.ToList(); .ToList();
var limsaStart = _dataManager.GetExcelSheet<QuestRedo>().GetRow(1); var limsaStart = dataManager.GetExcelSheet<QuestRedo>().GetRow(1);
var gridaniaStart = _dataManager.GetExcelSheet<QuestRedo>().GetRow(2); var gridaniaStart = dataManager.GetExcelSheet<QuestRedo>().GetRow(2);
var uldahStart = _dataManager.GetExcelSheet<QuestRedo>().GetRow(3); var uldahStart = dataManager.GetExcelSheet<QuestRedo>().GetRow(3);
var genreLimsa = new Genre(uint.MaxValue - 3, "Starting in Limsa Lominsa", 1, var genreLimsa = new Genre(uint.MaxValue - 3, "Starting in Limsa Lominsa", 1,
new uint[] { 108, 109 }.Concat(limsaStart.QuestRedoParam.Select(x => x.Quest.RowId)) new uint[] { 108, 109 }.Concat(limsaStart.QuestRedoParam.Select(x => x.Quest.RowId))
.Where(x => x != 0) .Where(x => x != 0)
.Select(x => _questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF)))) .Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
.ToList()); .ToList());
var genreGridania = new Genre(uint.MaxValue - 2, "Starting in Gridania", 1, var genreGridania = new Genre(uint.MaxValue - 2, "Starting in Gridania", 1,
new uint[] { 85, 123, 124 }.Concat(gridaniaStart.QuestRedoParam.Select(x => x.Quest.RowId)) new uint[] { 85, 123, 124 }.Concat(gridaniaStart.QuestRedoParam.Select(x => x.Quest.RowId))
.Where(x => x != 0) .Where(x => x != 0)
.Select(x => _questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF)))) .Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
.ToList()); .ToList());
var genreUldah = new Genre(uint.MaxValue - 1, "Starting in Ul'dah", 1, var genreUldah = new Genre(uint.MaxValue - 1, "Starting in Ul'dah", 1,
new uint[] { 568, 569, 570 }.Concat(uldahStart.QuestRedoParam.Select(x => x.Quest.RowId)) new uint[] { 568, 569, 570 }.Concat(uldahStart.QuestRedoParam.Select(x => x.Quest.RowId))
.Where(x => x != 0) .Where(x => x != 0)
.Select(x => _questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF)))) .Select(x => questData.GetQuestInfo(new QuestId((ushort)(x & 0xFFFF))))
.ToList()); .ToList());
genres.InsertRange(0, [genreLimsa, genreGridania, genreUldah]); genres.InsertRange(0, [genreLimsa, genreGridania, genreUldah]);
genres.Single(x => x.Id == 1) genres.Single(x => x.Id == 1)
@ -56,15 +42,19 @@ internal sealed class JournalData
genreLimsa.Quests.Contains(x) || genreGridania.Quests.Contains(x) || genreUldah.Quests.Contains(x)); genreLimsa.Quests.Contains(x) || genreGridania.Quests.Contains(x) || genreUldah.Quests.Contains(x));
Genres = genres.ToList(); Genres = genres.ToList();
Categories = _dataManager.GetExcelSheet<JournalCategory>() Categories = dataManager.GetExcelSheet<JournalCategory>()
.Where(x => x.RowId > 0) .Where(x => x.RowId > 0)
.Select(x => new Category(x, Genres.Where(y => y.CategoryId == x.RowId).ToList())) .Select(x => new Category(x, Genres.Where(y => y.CategoryId == x.RowId).ToList()))
.ToList(); .ToList();
Sections = _dataManager.GetExcelSheet<JournalSection>() Sections = dataManager.GetExcelSheet<JournalSection>()
.Select(x => new Section(x, Categories.Where(y => y.SectionId == x.RowId).ToList())) .Select(x => new Section(x, Categories.Where(y => y.SectionId == x.RowId).ToList()))
.ToList(); .ToList();
} }
public List<Genre> Genres { get; }
public List<Category> Categories { get; }
public List<Section> Sections { get; }
internal sealed class Genre internal sealed class Genre
{ {
public Genre(JournalGenre journalGenre, List<IQuestInfo> quests) public Genre(JournalGenre journalGenre, List<IQuestInfo> quests)

View File

@ -31,14 +31,12 @@ internal sealed class QuestJournalComponent
private readonly IDalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _pluginInterface;
private readonly QuestJournalUtils _questJournalUtils; private readonly QuestJournalUtils _questJournalUtils;
private readonly QuestValidator _questValidator; private readonly QuestValidator _questValidator;
private readonly IPluginLog _log;
private List<FilteredSection> _filteredSections = []; private List<FilteredSection> _filteredSections = [];
private string _searchText = string.Empty;
public QuestJournalComponent(JournalData journalData, QuestRegistry questRegistry, QuestFunctions questFunctions, public QuestJournalComponent(JournalData journalData, QuestRegistry questRegistry, QuestFunctions questFunctions,
UiUtils uiUtils, QuestTooltipComponent questTooltipComponent, IDalamudPluginInterface pluginInterface, UiUtils uiUtils, QuestTooltipComponent questTooltipComponent, IDalamudPluginInterface pluginInterface,
QuestJournalUtils questJournalUtils, QuestValidator questValidator, IPluginLog log) QuestJournalUtils questJournalUtils, QuestValidator questValidator)
{ {
_journalData = journalData; _journalData = journalData;
_questRegistry = questRegistry; _questRegistry = questRegistry;
@ -48,9 +46,10 @@ internal sealed class QuestJournalComponent
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
_questJournalUtils = questJournalUtils; _questJournalUtils = questJournalUtils;
_questValidator = questValidator; _questValidator = questValidator;
_log = log;
} }
internal FilterConfiguration Filter { get; } = new();
public void DrawQuests() public void DrawQuests()
{ {
using var tab = ImRaii.TabItem("Quests"); using var tab = ImRaii.TabItem("Quests");
@ -74,7 +73,7 @@ internal sealed class QuestJournalComponent
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
if (ImGui.InputTextWithHint(string.Empty, "Search quests and categories", ref _searchText, 256)) if (ImGui.InputTextWithHint(string.Empty, "Search quests and categories", ref Filter.SearchText, 256))
UpdateFilter(); UpdateFilter();
if (_filteredSections.Count > 0) if (_filteredSections.Count > 0)
@ -92,7 +91,7 @@ internal sealed class QuestJournalComponent
DrawSection(section); DrawSection(section);
} }
else else
ImGui.Text("No quest or category matches your search text."); ImGui.Text("No quest or category matches your search.");
} }
private void DrawSection(FilteredSection filter) private void DrawSection(FilteredSection filter)
@ -239,104 +238,63 @@ internal sealed class QuestJournalComponent
public void UpdateFilter() public void UpdateFilter()
{ {
_journalData.Reload();
Predicate<string> match = string.IsNullOrWhiteSpace(_searchText) ? x => true : x => x.Contains(_searchText, StringComparison.CurrentCultureIgnoreCase);
_filteredSections = _journalData.Sections _filteredSections = _journalData.Sections
.Select(section => FilterSection(section, match)) .Select(x => FilterSection(x, Filter))
.Where(x => x != null) .Where(x => x.Categories.Count > 0)
.Cast<FilteredSection>()
.ToList(); .ToList();
for (int i = 0; i < _filteredSections.Count; i++)
{
var section = _filteredSections[i];
for (int s = 0; s < section.Categories.Count; s++)
{
var category = section.Categories[s];
for (int c = 0; c < category.Genres.Count; c++)
{
var genre = category.Genres[c];
for (int g = 0; g < genre.Quests.Count; g++)
{
var quest = genre.Quests[g];
//All Quest Filter conditions checked here, cause we just love IEnumerable
if (QuestJournalUtils.AvailableOnly && !_questFunctions.IsReadyToAcceptQuest(quest.QuestId) ||
QuestJournalUtils.HideNoPaths && !_questRegistry.TryGetQuest(quest.QuestId, out _))
{
genre.Quests.Remove(quest);
g--;
}
}
}
}
}
RefreshCounts(); RefreshCounts();
} }
private static FilteredSection? FilterSection(JournalData.Section section, Predicate<string> match) private FilteredSection FilterSection(JournalData.Section section, FilterConfiguration filter)
{ {
if (match(section.Name)) IEnumerable<FilteredCategory> filteredCategories;
if (IsCategorySectionGenreMatch(filter, section.Name))
{ {
return new FilteredSection(section, filteredCategories = section.Categories
section.Categories .Select(x => FilterCategory(x, filter.WithoutName()));
.Select(x => FilterCategory(x, _ => true))
.Cast<FilteredCategory>()
.ToList());
} }
else else
{ {
List<FilteredCategory> filteredCategories = section.Categories filteredCategories = section.Categories
.Select(category => FilterCategory(category, match)) .Select(category => FilterCategory(category, filter));
.Where(x => x != null)
.Cast<FilteredCategory>()
.ToList();
if (filteredCategories.Count > 0)
return new FilteredSection(section, filteredCategories);
return null;
} }
return new FilteredSection(section, filteredCategories.Where(x => x.Genres.Count > 0).ToList());
} }
private static FilteredCategory? FilterCategory(JournalData.Category category, Predicate<string> match) private FilteredCategory FilterCategory(JournalData.Category category, FilterConfiguration filter)
{ {
if (match(category.Name)) IEnumerable<FilteredGenre> filteredGenres;
if (IsCategorySectionGenreMatch(filter, category.Name))
{ {
return new FilteredCategory(category, filteredGenres = category.Genres
category.Genres .Select(x => FilterGenre(x, filter.WithoutName()));
.Select(x => FilterGenre(x, _ => true)!)
.ToList());
} }
else else
{ {
List<FilteredGenre> filteredGenres = category.Genres filteredGenres = category.Genres
.Select(genre => FilterGenre(genre, match)) .Select(genre => FilterGenre(genre, filter));
.Where(x => x != null)
.Cast<FilteredGenre>()
.ToList();
if (filteredGenres.Count > 0)
return new FilteredCategory(category, filteredGenres);
return null;
} }
return new FilteredCategory(category, filteredGenres.Where(x => x.Quests.Count > 0).ToList());
} }
private static FilteredGenre? FilterGenre(JournalData.Genre genre, Predicate<string> match) private FilteredGenre FilterGenre(JournalData.Genre genre, FilterConfiguration filter)
{ {
if (match(genre.Name)) IEnumerable<IQuestInfo> filteredQuests;
return new FilteredGenre(genre, genre.Quests); if (IsCategorySectionGenreMatch(filter, genre.Name))
{
filteredQuests = genre.Quests
.Where(x => IsQuestMatch(filter.WithoutName(), x));
}
else else
{ {
List<IQuestInfo> filteredQuests = genre.Quests filteredQuests = genre.Quests
.Where(x => match(x.Name)) .Where(x => IsQuestMatch(filter, x));
.ToList();
if (filteredQuests.Count > 0)
return new FilteredGenre(genre, filteredQuests);
} }
return null; return new FilteredGenre(genre, filteredQuests.ToList());
} }
internal void RefreshCounts() internal void RefreshCounts()
@ -396,6 +354,28 @@ internal sealed class QuestJournalComponent
_sectionCounts[sectionCount.Key] = sectionCount.Value with { Completed = 0 }; _sectionCounts[sectionCount.Key] = sectionCount.Value with { Completed = 0 };
} }
private static bool IsCategorySectionGenreMatch(FilterConfiguration filter, string name)
{
return string.IsNullOrEmpty(filter.SearchText) ||
name.Contains(filter.SearchText, StringComparison.CurrentCultureIgnoreCase);
}
private bool IsQuestMatch(FilterConfiguration filter, IQuestInfo questInfo)
{
if (!string.IsNullOrEmpty(filter.SearchText) &&
!questInfo.Name.Contains(filter.SearchText, StringComparison.CurrentCultureIgnoreCase))
return false;
if (filter.AvailableOnly && !_questFunctions.IsReadyToAcceptQuest(questInfo.QuestId))
return false;
if (filter.HideNoPaths &&
(!_questRegistry.TryGetQuest(questInfo.QuestId, out var quest) || quest.Root.Disabled))
return false;
return true;
}
private sealed record FilteredSection(JournalData.Section Section, List<FilteredCategory> Categories); private sealed record FilteredSection(JournalData.Section Section, List<FilteredCategory> Categories);
private sealed record FilteredCategory(JournalData.Category Category, List<FilteredGenre> Genres); private sealed record FilteredCategory(JournalData.Category Category, List<FilteredGenre> Genres);
@ -409,4 +389,19 @@ internal sealed class QuestJournalComponent
{ {
} }
} }
internal sealed class FilterConfiguration
{
public string SearchText = string.Empty;
public bool AvailableOnly;
public bool HideNoPaths;
public bool AdvancedFiltersActive => AvailableOnly || HideNoPaths;
public FilterConfiguration WithoutName() => new()
{
AvailableOnly = AvailableOnly,
HideNoPaths = HideNoPaths
};
}
} }

View File

@ -7,6 +7,7 @@ using Questionable.Functions;
using Questionable.Model; using Questionable.Model;
using Questionable.Model.Questing; using Questionable.Model.Questing;
using System; using System;
using Dalamud.Interface.Colors;
namespace Questionable.Windows.JournalComponents; namespace Questionable.Windows.JournalComponents;
@ -16,9 +17,6 @@ internal sealed class QuestJournalUtils
private readonly QuestFunctions _questFunctions; private readonly QuestFunctions _questFunctions;
private readonly ICommandManager _commandManager; private readonly ICommandManager _commandManager;
public static bool AvailableOnly;
public static bool HideNoPaths;
public QuestJournalUtils(QuestController questController, QuestFunctions questFunctions, public QuestJournalUtils(QuestController questController, QuestFunctions questFunctions,
ICommandManager commandManager) ICommandManager commandManager)
{ {
@ -50,19 +48,17 @@ internal sealed class QuestJournalUtils
} }
} }
internal static void ShowFilterContextMenu(QuestJournalComponent journalUI) internal static void ShowFilterContextMenu(QuestJournalComponent journalUi)
{ {
if (ImGuiComponents.IconButton(Dalamud.Interface.FontAwesomeIcon.Filter)) if (ImGuiComponents.IconButtonWithText(Dalamud.Interface.FontAwesomeIcon.Filter, "Filter"))
ImGui.OpenPopup($"##QuestFilters"); ImGui.OpenPopup("##QuestFilters");
using var popup = ImRaii.Popup($"##QuestFilters"); using var popup = ImRaii.Popup("##QuestFilters");
if (!popup) if (!popup)
return; return;
if (ImGui.Checkbox("Show only Available Quests", ref AvailableOnly) || if (ImGui.Checkbox("Show only Available Quests", ref journalUi.Filter.AvailableOnly) ||
ImGui.Checkbox("Hide Quests Without Path", ref HideNoPaths)) ImGui.Checkbox("Hide Quests Without Path", ref journalUi.Filter.HideNoPaths))
journalUI.UpdateFilter(); journalUi.UpdateFilter();
} }
} }