private void ApplyFilters() { if (BeatmapDetailsLoader.instance.IsLoading) { Logger.log.Warn("Tried to apply filters while loading beatmap details (this should never happen?)"); return; } if (!Tweaks.SongBrowserTweaks.Initialized) { Logger.log.Debug($"Applying filter, starting with {_beatmapDetails.Count} songs"); } List <BeatmapDetails> filteredLevels = null; bool hasApplied; if (!Tweaks.SongBrowserTweaks.Initialized) { filteredLevels = new List <BeatmapDetails>(_beatmapDetails.Values); hasApplied = FilterList.ApplyFilter(ref filteredLevels); Logger.log.Debug($"Filter completed, {filteredLevels.Count} songs left"); } else { foreach (var filter in FilterList.ActiveFilters) { filter.ApplyStagingValues(); } hasApplied = FilterList.AnyApplied; } RefreshUI(); if (hasApplied) { if (Tweaks.SongBrowserTweaks.ModLoaded && Tweaks.SongBrowserTweaks.Initialized) { _filterMainViewController.ShowInfoText("Filter applied"); } else { _filterMainViewController.ShowInfoText($"{filteredLevels.Count} out of {_beatmapDetails.Count} songs found"); // SongBrowser will create its own BeatmapLevelPack when it gets our filtered levels via: // ProcessSongList() -> CustomFilterHandler() -> ApplyFiltersForSongBrowser() -> ApplyFilters() // filters are applied once this flow coordinator is dismissed FilterApplied?.Invoke(_beatmapDetails.Where(x => filteredLevels.Contains(x.Value)).Select(x => x.Key).ToArray()); } } else { // default values were applied (no filtering or undo filtering) FiltersUnapplied?.Invoke(); } }
/// <summary> /// Adapt this mod to SongBrowser version 5.4.0 and onwards. /// </summary> /// <returns>A boolean indicating whether the tweaks were done correctly.</returns> private static bool _Init() { // acquire all the UI elements we need to change before modifying LevelCollectionViewController levelCollectionViewController; Button xButton; Button filterByButton; Button[] existingFilterButtons; var levelSelectionNavigationController = SongListUI.instance.LevelSelectionNavigationController; try { levelCollectionViewController = levelSelectionNavigationController.GetPrivateField <LevelCollectionViewController>("_levelCollectionViewController"); _songBrowserUI = Resources.FindObjectsOfTypeAll <SongBrowserUI>().First(); _searchButton = levelCollectionViewController.GetComponentsInChildren <Button>(true).First(x => x.name == "FilterSearchButton"); existingFilterButtons = levelCollectionViewController.GetComponentsInChildren <Button>(true).Where(x => x.name.StartsWith("Filter") && x.name.EndsWith("Button")).ToArray(); // these buttons are found using their respective x positions (will need to be changed if button position changes) xButton = levelCollectionViewController.GetComponentsInChildren <Button>(true).First(x => x.name == "CustomUIButton" && (x.transform as RectTransform).anchoredPosition.x == -32.5f); filterByButton = levelCollectionViewController.GetComponentsInChildren <Button>(true).First(x => x.name == "CustomUIButton" && (x.transform as RectTransform).anchoredPosition.x == 30.5); _clearFiltersButton = levelCollectionViewController.GetComponentsInChildren <Button>(true).First(x => x.name == "CustomUIButton" && (x.transform as RectTransform).anchoredPosition.x == 54.5f); } catch (InvalidOperationException) { Logger.log.Debug("Unable to find the buttons created by SongBrowser"); return(false); } // SongBrowser filter buttons if (!PluginConfig.DisableSearch) { _searchButton.onClick.RemoveAllListeners(); _searchButton.onClick.AddListener(delegate() { SongListUI.instance.SearchButtonPressed(); _filterButton.gameObject.SetActive(false); _songBrowserUI.InvokeMethod("RefreshOuterUIState", new object[] { UIState.Main }); }); } else { Logger.log.Info("Enhanced search functionality is disabled. SongBrowser's \"Search\" button is not modified"); } if (!PluginConfig.DisableFilters) { foreach (var button in existingFilterButtons) { if (button.name == "FilterSearchButton") { continue; } button.onClick.AddListener(delegate() { // search button should be hidden already via RefreshOuterUIState _filterButton.gameObject.SetActive(false); SongListUI.instance.UnapplyFilters(); }); } // create this mod's filter button _filterButton = BeatSaberUI.CreateUIButton(levelCollectionViewController.rectTransform, "ApplyButton", new Vector2(-18f + (12.75f * existingFilterButtons.Length), 37f), new Vector2(16.75f, 5f), delegate() { SongListUI.instance.FilterButtonPressed(); _filterButton.gameObject.SetActive(false); _songBrowserUI.InvokeMethod("RefreshOuterUIState", new object[] { UIState.Main }); }, "Other Filters"); _filterButton.SetButtonTextSize(2.25f); _filterButton.GetComponentsInChildren <HorizontalLayoutGroup>().First(btn => btn.name == "Content").padding = new RectOffset(4, 4, 2, 2); _filterButton.ToggleWordWrapping(false); _filterButton.gameObject.SetActive(false); // SongBrowser outer UI buttons filterByButton.onClick.AddListener(delegate() { _filterButton.gameObject.SetActive(true); }); _clearFiltersButton.onClick.RemoveAllListeners(); _clearFiltersButton.onClick.AddListener(delegate() { SongListUI.instance.ClearButtonPressed(); // filters are cancelled by ClearButtonPressed -> UnapplyFilters -> FilterFlowCoordinatorFiltersUnapplied // but only if custom filters are applied, otherwise we do it here if ((_songBrowserUI as SongBrowserUI).Model.Settings.filterMode != SongFilterMode.None) { _FiltersUnapplied(); } }); xButton.onClick.AddListener(delegate() { _filterButton.gameObject.SetActive(false); }); // custom filter handler when the same level pack is selected SongBrowserModel.CustomFilterHandler = delegate(IBeatmapLevelPack levelPack) { FilterList.ApplyFilter(levelPack.beatmapLevelCollection.beatmapLevels, out var filteredLevels, false); return(filteredLevels.ToList()); }; // on first load, SongBrowser uses the previously applied settings // if this mod's filters was applied last, we have to disable it, since our filters aren't saved across sessions if ((_songBrowserUI as SongBrowserUI).Model.Settings.filterMode == SongFilterMode.Custom) { (_songBrowserUI as SongBrowserUI).CancelFilter(); (_songBrowserUI as SongBrowserUI).ProcessSongList(); (_songBrowserUI as SongBrowserUI).RefreshSongUI(); } } else { Logger.log.Info("Filter functionality is disabled. SongBrowser's buttons are not modified"); } Initialized = true; Logger.log.Info("Modified SongBrowser's search, filter, and clear filter buttons"); return(true); }