diff --git a/include/UI/Modals/GenrePicker.hpp b/include/UI/Modals/GenrePicker.hpp index 6ef6371..901f4c9 100644 --- a/include/UI/Modals/GenrePicker.hpp +++ b/include/UI/Modals/GenrePicker.hpp @@ -14,9 +14,31 @@ #include "bsml/shared/BSML/Components/CustomListTableData.hpp" -DECLARE_CLASS_CODEGEN(BetterSongSearch::UI::Modals, GenrePicker, UnityEngine::MonoBehaviour, +namespace BetterSongSearch::UI::Modals { + enum class GenreCellStatus { + None, + Include, + Exclude + }; + + struct GenreCellState { + std::string tag; + uint64_t mask; + GenreCellStatus status; + uint32_t songCount; + }; +} + + +DECLARE_CLASS_CODEGEN_INTERFACES(BetterSongSearch::UI::Modals, GenrePicker, UnityEngine::MonoBehaviour, classof(HMUI::TableView::IDataSource*), + + DECLARE_OVERRIDE_METHOD_MATCH(HMUI::TableCell*, CellForIdx, &HMUI::TableView::IDataSource::CellForIdx, HMUI::TableView* tableView, int idx); + DECLARE_OVERRIDE_METHOD_MATCH(float, CellSize, &HMUI::TableView::IDataSource::CellSize); + DECLARE_OVERRIDE_METHOD_MATCH(int, NumberOfCells, &HMUI::TableView::IDataSource::NumberOfCells); + DECLARE_INSTANCE_METHOD(void, OnEnable); DECLARE_CTOR(ctor); + DECLARE_DTOR(dtor); DECLARE_INSTANCE_METHOD(void, PostParse); @@ -26,14 +48,13 @@ DECLARE_CLASS_CODEGEN(BetterSongSearch::UI::Modals, GenrePicker, UnityEngine::Mo DECLARE_INSTANCE_METHOD(void, ClearGenre); - + DECLARE_INSTANCE_METHOD(void, RefreshGenreList); DECLARE_INSTANCE_FIELD(bool, initialized); - + // Modals DECLARE_INSTANCE_FIELD(UnityW, genrePickerModal); - public: - std::vector selectedGenres; - std::vector excludedGenres; + private: + std::vector genres; ) diff --git a/include/UI/Modals/GenrePickerCell.hpp b/include/UI/Modals/GenrePickerCell.hpp index d782e5f..1629a83 100644 --- a/include/UI/Modals/GenrePickerCell.hpp +++ b/include/UI/Modals/GenrePickerCell.hpp @@ -11,22 +11,30 @@ #include "bsml/shared/macros.hpp" #include "bsml/shared/BSML.hpp" #include "bsml/shared/BSML/Components/CustomListTableData.hpp" +#include "bsml/shared/BSML/Components/ClickableText.hpp" #include "HMUI/Touchable.hpp" #include "HMUI/TableView.hpp" #include "UnityEngine/UI/HorizontalOrVerticalLayoutGroup.hpp" #include "assets.hpp" +#include "UI/Modals/GenrePicker.hpp" DECLARE_CLASS_CODEGEN(BetterSongSearch::UI::Modals, GenrePickerCell, HMUI::TableCell, DECLARE_OVERRIDE_METHOD_MATCH(void, SelectionDidChange, &HMUI::SelectableCell::SelectionDidChange, HMUI::SelectableCell::TransitionType transitionType); DECLARE_OVERRIDE_METHOD_MATCH(void, HighlightDidChange, &HMUI::SelectableCell::HighlightDidChange, HMUI::SelectableCell::TransitionType transitionType); DECLARE_OVERRIDE_METHOD_MATCH(void, WasPreparedForReuse, &HMUI::TableCell::WasPreparedForReuse); - DECLARE_INSTANCE_FIELD(TMPro::TextMeshProUGUI*, presetNameLabel); - DECLARE_INSTANCE_FIELD(HMUI::ImageView*, bgContainer); + + DECLARE_INSTANCE_FIELD(UnityW, includeButton); + DECLARE_INSTANCE_FIELD(UnityW, excludeButton); + + DECLARE_INSTANCE_METHOD(void, IncludeGenre); + DECLARE_INSTANCE_METHOD(void, ExcludeGenre); + + DECLARE_INSTANCE_METHOD(void, Refresh); public: - PresetsTableCell* PopulateWithPresetName(StringW presetName); - static PresetsTableCell *GetCell(HMUI::TableView *tableView); + BetterSongSearch::UI::Modals::GenrePickerCell* PopulateWithGenre(BetterSongSearch::UI::Modals::GenreCellState* state); + static BetterSongSearch::UI::Modals::GenrePickerCell *GetCell(HMUI::TableView *tableView); - private: - void RefreshBgState(); +private: + BetterSongSearch::UI::Modals::GenreCellState* genre; ) diff --git a/src/UI/Modals/GenrePicker.cpp b/src/UI/Modals/GenrePicker.cpp index a8c0b09..e35eb95 100644 --- a/src/UI/Modals/GenrePicker.cpp +++ b/src/UI/Modals/GenrePicker.cpp @@ -5,12 +5,14 @@ #include "bsml/shared/BSML.hpp" #include "UI/FlowCoordinators/BetterSongSearchFlowCoordinator.hpp" +#include "UI/Modals/GenrePickerCell.hpp" #include "logging.hpp" #include "assets.hpp" #include "FilterOptions.hpp" #include "DataHolder.hpp" + using namespace BetterSongSearch::UI; using namespace BetterSongSearch::Util; #define coro(coroutine) BSML::SharedCoroutineStarter::get_instance()->StartCoroutine(custom_types::Helpers::CoroutineHelper::New(coroutine)) @@ -35,6 +37,47 @@ void Modals::GenrePicker::ctor() { INVOKE_CTOR(); this->initialized = false; + + // Subscribe to events + dataHolder.loadingFinished += {&Modals::GenrePicker::PostParse, this}; +} +void Modals::GenrePicker::dtor() +{ + // Unsub from events + dataHolder.loadingFinished -= {&Modals::GenrePicker::PostParse, this}; +} + +void Modals::GenrePicker::RefreshGenreList() { + if (!this->genrePickerModal) return; + if (!initialized) return; + + auto table = this->genrePickerModal->get_transform()->Find("TableView")->GetComponent(); + if (!table) return; + + if (dataHolder.tags.size() == 0) return; + + // Recalculate preprocessed values + dataHolder.filterOptions.RecalculatePreprocessedValues(); + + std::vector tempGenres; + for (auto& genre : dataHolder.tags) + { + GenreCellStatus state = GenreCellStatus::None; + auto mask = genre.mask; + + auto isExcluded = dataHolder.filterOptions._mapGenreExcludeBitfield & mask; + auto isIncluded = dataHolder.filterOptions._mapGenreBitfield & mask; + + if (isExcluded) state = GenreCellStatus::Exclude; + if (isIncluded) state = GenreCellStatus::Include; + + genres.push_back({genre.tag, mask, state, genre.songCount}); + } + + tempGenres.swap(genres); + + table->SetDataSource(reinterpret_cast(this), false); + table->ReloadData(); } void Modals::GenrePicker::OpenModal() @@ -44,6 +87,8 @@ void Modals::GenrePicker::OpenModal() initialized = true; } + RefreshGenreList(); + INFO("Opening genre picker modal"); this->genrePickerModal->Show(); @@ -53,7 +98,6 @@ void Modals::GenrePicker::OpenModal() if (!fv) return; dataHolder.PreprocessTags(); - } void Modals::GenrePicker::ClearGenre() @@ -73,4 +117,20 @@ void Modals::GenrePicker::ClearGenre() fcInstance->FilterViewController->ForceRefreshUI(); this->genrePickerModal->Hide(); +} + +// Table stuff +HMUI::TableCell *Modals::GenrePicker::CellForIdx(HMUI::TableView *tableView, int idx) +{ + return Modals::GenrePickerCell::GetCell(tableView)->PopulateWithGenre(&genres[idx]); +} + +float Modals::GenrePicker::CellSize() +{ + return 6.05f; +} + +int Modals::GenrePicker::NumberOfCells() +{ + return genres.size(); } \ No newline at end of file diff --git a/src/UI/Modals/GenrePickerCell.cpp b/src/UI/Modals/GenrePickerCell.cpp new file mode 100644 index 0000000..970958a --- /dev/null +++ b/src/UI/Modals/GenrePickerCell.cpp @@ -0,0 +1,83 @@ +#include "UI/Modals/GenrePickerCell.hpp" + + +DEFINE_TYPE(BetterSongSearch::UI::Modals, GenrePickerCell); + +const StringW GenrePickerCellReuseIdentifier = "REUSEGenreTableCell"; + +namespace BetterSongSearch::UI::Modals +{ + void GenrePickerCell::Refresh() + { + if (genre == nullptr) return; + + includeButton->set_fontStyle( + genre->status == GenreCellStatus::Exclude + ? TMPro::FontStyles::Strikethrough + : TMPro::FontStyles::Normal + ); + + includeButton->set_color( + UnityEngine::Color( + genre->status == GenreCellStatus::Exclude ? 1.0f : 0.8f, + genre->status == GenreCellStatus::Include ? 1.0f : 0.7f, + 0.8f, + get_highlighted() ? 1.0f : 0.8f + ) + ); + + excludeButton->get_gameObject()->SetActive(highlighted && genre->status != GenreCellStatus::Exclude); + } + + void GenrePickerCell::SelectionDidChange(HMUI::SelectableCell::TransitionType transitionType) + { + Refresh(); + } + + void GenrePickerCell::HighlightDidChange(HMUI::SelectableCell::TransitionType transitionType) + { + Refresh(); + } + + void GenrePickerCell::WasPreparedForReuse() + { + includeButton->set_text(""); + genre = nullptr; + } + + BetterSongSearch::UI::Modals::GenrePickerCell* GenrePickerCell::PopulateWithGenre(BetterSongSearch::UI::Modals::GenreCellState* state){ + this->genre = state; + includeButton->set_text(state->tag); + Refresh(); + + return this; + } + + BetterSongSearch::UI::Modals::GenrePickerCell *GenrePickerCell::GetCell(HMUI::TableView *tableView) + { + auto tableCell = tableView->DequeueReusableCellForIdentifier(GenrePickerCellReuseIdentifier); + if (!tableCell) + { + tableCell = UnityEngine::GameObject::New_ctor("GenrePickerCell")->AddComponent(); + tableCell->set_interactable(true); + tableCell->set_reuseIdentifier(GenrePickerCellReuseIdentifier); + BSML::parse_and_construct(Assets::GenrePickerCell_bsml, tableCell->get_transform(), tableCell); + + // Weird hack cause HMUI touchable is not there for some reason, thanks RedBrumbler + tableCell->get_gameObject()->AddComponent(); + } + + return tableCell.cast(); + } + + void GenrePickerCell::IncludeGenre() { + if (genre == nullptr) return; + genre->status = genre->status == GenreCellStatus::Include ? GenreCellStatus::None : GenreCellStatus::Include; + Refresh(); + } + void GenrePickerCell::ExcludeGenre() { + if (genre == nullptr) return; + genre->status = GenreCellStatus::Exclude; + Refresh(); + } +} diff --git a/src/Util/Debug.cpp b/src/Util/Debug.cpp index 8f9a298..313278f 100644 --- a/src/Util/Debug.cpp +++ b/src/Util/Debug.cpp @@ -9,28 +9,20 @@ std::string BetterSongSearch::Util::SortToString(int sortMode) { { case 0: return "Newest"; - break; case 1: return "Oldest"; - break; case 2: return "Latest_Ranked"; - break; case 3: return "Most_Stars"; - break; case 4: return "Least_Stars"; - break; case 5: return "Best_rated"; - break; case 6: return "Worst_rated"; - break; default: return "Unknown"; - break; } } @@ -39,25 +31,18 @@ std::string BetterSongSearch::Util::RequirementTypeToString(int requirementType) { case 0: return "Any"; - break; case 1: return "NoodleExtensions"; - break; case 2: return "MappingExtensions"; - break; case 3: return "Chroma"; - break; case 4: return "Cinema"; - break; case 5: return "None"; - break; default: return "Unknown"; - break; } } @@ -66,34 +51,24 @@ std::string BetterSongSearch::Util::CharFilterTypeToString(int charFilterType) { { case 0: return "All"; - break; case 1: return "Custom"; - break; case 2: return "Standard"; - break; case 3: return "OneSaber"; - break; case 4: return "NoArrows"; - break; case 5: return "NinetyDegrees"; - break; case 6: return "ThreeSixtyDegrees"; - break; case 7: return "LightShow"; - break; case 8: return "Lawless"; - break; default: return "Unknown"; - break; } } @@ -102,25 +77,18 @@ std::string BetterSongSearch::Util::DifficultyFilterTypeToString(int diffFilterT { case 0: return "All"; - break; case 1: return "Easy"; - break; case 2: return "Normal"; - break; case 3: return "Hard"; - break; case 4: return "Expert"; - break; case 5: return "ExpertPlus"; - break; default: return "Unknown"; - break; } } @@ -129,22 +97,16 @@ std::string BetterSongSearch::Util::RankedFilterTypeToString(int rankedFilterTyp { case 0: return "ShowAll"; - break; case 1: return "ScoreSaberRanked"; - break; case 2: return "BeatLeaderRanked"; - break; case 3: return "ScoreSaberQualified"; - break; case 4: return "BeatLeaderQualified"; - break; default: return "Unknown"; - break; } } std::string BetterSongSearch::Util::LocalScoreFilterTypeToString(int localScoreFilterType) { @@ -152,16 +114,12 @@ std::string BetterSongSearch::Util::LocalScoreFilterTypeToString(int localScoreF { case 0: return "All"; - break; case 1: return "HidePassed"; - break; case 2: return "OnlyPassed"; - break; default: return "Unknown"; - break; } } @@ -170,16 +128,12 @@ std::string BetterSongSearch::Util::DownloadFilterTypeToString(int downloadFilte { case 0: return "All"; - break; case 1: return "HidePassed"; - break; case 2: return "OnlyPassed"; - break; default: return "Unknown"; - break; } }