forked from liza/Questionable
Adjust filter logic
This commit is contained in:
parent
cad6c30b80
commit
95d19455de
@ -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)
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FilteredCategory? FilterCategory(JournalData.Category category, Predicate<string> match)
|
return new FilteredSection(section, filteredCategories.Where(x => x.Genres.Count > 0).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FilteredGenre? FilterGenre(JournalData.Genre genre, Predicate<string> match)
|
return new FilteredCategory(category, filteredGenres.Where(x => x.Quests.Count > 0).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user