private static async void ProcessSongRequest(int index, bool fromHistory = false) { if ((RequestQueue.Songs.Count > 0 && !fromHistory) || (RequestHistory.Songs.Count > 0 && fromHistory)) { SongRequest request = null; if (!fromHistory) { SetRequestStatus(index, RequestStatus.Played); request = DequeueRequest(index); } else { request = RequestHistory.Songs.ElementAt(index); } if (request == null) { Plugin.Log("Can't process a null request! Aborting!"); return; } else { Plugin.Log($"Processing song request {request.song["songName"].Value}"); } string songName = request.song["songName"].Value; string songIndex = $"{request.song["id"].Value} ({request.song["songName"].Value} - {request.song["levelAuthor"].Value})"; songIndex = normalize.RemoveDirectorySymbols(ref songIndex); // Remove invalid characters. string currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "Beat Saber_Data\\CustomLevels", songIndex); string songHash = request.song["hash"].Value.ToUpper(); // Check to see if level exists, download if not. // Replace with level check. //CustomLevel[] levels = SongLoader.CustomLevels.Where(l => l.levelID.StartsWith(songHash)).ToArray(); //if (levels.Length == 0) var rat = SongCore.Collections.levelIDsForHash(songHash); bool mapexists = (rat.Count > 0) && (rat[0] != ""); if (!SongCore.Loader.CustomLevels.ContainsKey(currentSongDirectory) && !mapexists) { EmptyDirectory(".requestcache", false); //SongMap map; //if (MapDatabase.MapLibrary.TryGetValue(songIndex, out map)) //{ // if (map.path != "") // { // songIndex = map.song["version"].Value; // songName = map.song["songName"].Value; // currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "CustomSongs", songIndex); // songHash = map.song["hashMd5"].Value.ToUpper(); // Directory.CreateDirectory(currentSongDirectory); // // HACK to allow playing alternate songs not in custom song directory // CopyFilesRecursively(new DirectoryInfo(map.path),new DirectoryInfo( currentSongDirectory)); // goto here; // } //} //Plugin.Log("Downloading"); if (Directory.Exists(currentSongDirectory)) { EmptyDirectory(currentSongDirectory, true); Plugin.Log($"Deleting {currentSongDirectory}"); } string localPath = Path.Combine(Environment.CurrentDirectory, ".requestcache", $"{request.song["id"].Value}.zip"); //string dl = $"https://beatsaver.com {request.song["downloadURL"].Value}"; //Instance.QueueChatMessage($"Download url: {dl}, {request.song}"); // Insert code to replace local path with ZIP path here //SongMap map; //if (MapDatabase.MapLibrary.TryGetValue(songIndex, out map)) //{ // if (map.path != "") // { // songIndex = map.song["version"].Value; // songName = map.song["songName"].Value; // currentSongDirectory = Path.Combine(Environment.CurrentDirectory, "CustomSongs", songIndex); // songHash = map.song["hashMd5"].Value.ToUpper(); // Directory.CreateDirectory(currentSongDirectory); // // HACK to allow playing alternate songs not in custom song directory // CopyFilesRecursively(new DirectoryInfo(map.path),new DirectoryInfo( currentSongDirectory)); // goto here; // } //} #if UNRELEASED // Direct download hack var ext = Path.GetExtension(request.song["coverURL"].Value); var k = request.song["coverURL"].Value.Replace(ext, ".zip"); var songZip = await Plugin.WebClient.DownloadSong($"https://beatsaver.com{k}", System.Threading.CancellationToken.None); #else var songZip = await Plugin.WebClient.DownloadSong($"https://beatsaver.com{request.song["downloadURL"].Value}", System.Threading.CancellationToken.None); #endif Stream zipStream = new MemoryStream(songZip); try { // open zip archive from memory stream ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Read); archive.ExtractToDirectory(currentSongDirectory); archive.Dispose(); } catch (Exception e) { Plugin.Log($"Unable to extract ZIP! Exception: {e}"); return; } zipStream.Close(); here: await Task.Run(async() => { while (!SongCore.Loader.AreSongsLoaded && SongCore.Loader.AreSongsLoading) { await Task.Delay(25); } }); Loader.Instance.RefreshSongs(); await Task.Run(async() => { while (!SongCore.Loader.AreSongsLoaded && SongCore.Loader.AreSongsLoading) { await Task.Delay(25); } }); EmptyDirectory(".requestcache", true); //levels = SongLoader.CustomLevels.Where(l => l.levelID.StartsWith(songHash)).ToArray(); } else { //Instance.QueueChatMessage($"Directory exists: {currentSongDirectory}"); Plugin.Log($"Song {songName} already exists!"); } // Dismiss the song request viewcontroller now //_songRequestMenu.Dismiss(); _flowCoordinator.Dismiss(); if (true) { //Plugin.Log($"Scrolling to level {levels[0].levelID}"); bool success = false; Dispatcher.RunCoroutine(SongListUtils.ScrollToLevel(request.song["hash"].Value.ToUpper(), (s) => success = s, false)); // Redownload the song if we failed to scroll to it } else { Plugin.Log("Failed to find new level!"); } if (!request.song.IsNull && RequestBotConfig.Instance.SendNextSongBeingPlayedtoChat) { new DynamicText().AddUser(ref request.requestor).AddSong(request.song).QueueMessage(NextSonglink.ToString()); // Display next song message } #if UNRELEASED if (!request.song.IsNull) // Experimental! { //ChatHandler.Send("marker "+ new DynamicText().AddUser(ref request.requestor).AddSong(request.song).Parse("%version% songName%"), true); } #endif } }
private async void SetDataFromLevelAsync(SongRequest request, LevelListTableCell _tableCell, int row) { var favouritesBadge = _tableCell.GetField <RawImage, LevelListTableCell>("_favoritesBadgeImage"); favouritesBadge.enabled = false; bool highlight = (request.requestInfo.Length > 0) && (request.requestInfo[0] == '!'); string msg = highlight ? "MSG" : ""; var hasMessage = (request.requestInfo.Length > 0) && (request.requestInfo[0] == '!'); var isChallenge = request.requestInfo.IndexOf("!challenge", StringComparison.OrdinalIgnoreCase) >= 0; var beatmapCharacteristicImages = _tableCell.GetField <UnityEngine.UI.Image[], LevelListTableCell>("_beatmapCharacteristicImages"); // NEW VERSION foreach (var i in beatmapCharacteristicImages) { i.enabled = false; } // causing a nullex? //_tableCell.SetField("_beatmapCharacteristicAlphas", new float[5] { 1f, 1f, 1f, 1f, 1f }); // set message icon if request has a message // NEW VERSION if (hasMessage) { beatmapCharacteristicImages.Last().sprite = Base64Sprites.InfoIcon; beatmapCharacteristicImages.Last().enabled = true; } // set challenge icon if song is a challenge if (isChallenge) { var el = beatmapCharacteristicImages.ElementAt(beatmapCharacteristicImages.Length - 2); el.sprite = Base64Sprites.VersusChallengeIcon; el.enabled = true; } string pp = ""; int ppvalue = request.song["pp"].AsInt; if (ppvalue > 0) { pp = $" {ppvalue} PP"; } var dt = new RequestBot.DynamicText().AddSong(request.song).AddUser(ref request.requestor); // Get basic fields dt.Add("Status", request.status.ToString()); dt.Add("Info", (request.requestInfo != "") ? " / " + request.requestInfo : ""); dt.Add("RequestTime", request.requestTime.ToLocalTime().ToString("hh:mm")); var songName = _tableCell.GetField <TextMeshProUGUI, LevelListTableCell>("_songNameText"); //songName.text = $"{request.song["songName"].Value} <size=50%>{RequestBot.GetRating(ref request.song)} <color=#3fff3f>{pp}</color></size> <color=#ff00ff>{msg}</color>"; songName.text = $"{request.song["songName"].Value} <size=50%>{RequestBot.GetRating(ref request.song)} <color=#3fff3f>{pp}</color></size>"; // NEW VERSION var author = _tableCell.GetField <TextMeshProUGUI, LevelListTableCell>("_authorText"); author.text = dt.Parse(RequestBot.QueueListRow2); var image = _tableCell.GetField <RawImage, LevelListTableCell>("_coverRawImage"); var imageSet = false; if (SongCore.Loader.AreSongsLoaded) { CustomPreviewBeatmapLevel level = CustomLevelForRow(row); if (level != null) { //Plugin.Log("custom level found"); // set image from song's cover image var tex = await level.GetCoverImageTexture2DAsync(System.Threading.CancellationToken.None); image.texture = tex; imageSet = true; } } if (!imageSet) { string url = request.song["coverURL"].Value; if (!_cachedTextures.TryGetValue(url, out var tex)) { var b = await Plugin.WebClient.DownloadImage($"https://beatsaver.com{url}", System.Threading.CancellationToken.None); tex = new Texture2D(2, 2); tex.LoadImage(b); try { _cachedTextures.Add(url, tex); } catch (Exception) { } } image.texture = tex; } UIHelper.AddHintText(_tableCell.transform as RectTransform, dt.Parse(RequestBot.SongHintText)); }
private async void SetDataFromLevelAsync(SongRequest request, LevelListTableCell _tableCell, int row) { var favouritesBadge = _tableCell.GetField <Image, LevelListTableCell>("_favoritesBadgeImage"); favouritesBadge.enabled = false; var highlight = (request.requestInfo.Length > 0) && (request.requestInfo[0] == '!'); var msg = highlight ? "MSG" : ""; var hasMessage = (request.requestInfo.Length > 0) && (request.requestInfo[0] == '!'); var isChallenge = request.requestInfo.IndexOf("!challenge", StringComparison.OrdinalIgnoreCase) >= 0; var pp = ""; var ppvalue = request.song["pp"].AsInt; if (ppvalue > 0) { pp = $" {ppvalue} PP"; } var dt = new RequestBot.DynamicText().AddSong(request.song).AddUser(ref request.requestor); // Get basic fields dt.Add("Status", request.status.ToString()); dt.Add("Info", (request.requestInfo != "") ? " / " + request.requestInfo : ""); dt.Add("RequestTime", request.requestTime.ToLocalTime().ToString("hh:mm")); var songDurationText = _tableCell.GetField <TextMeshProUGUI, LevelListTableCell>("_songDurationText"); songDurationText.text = request.song["songlength"].Value; var songBpm = _tableCell.GetField <TextMeshProUGUI, LevelListTableCell>("_songBpmText"); if (!request.requestor.IsModerator && !request.requestor.IsVip) { (songBpm.transform as RectTransform).anchoredPosition = new Vector2(-2.5f, -1.8f); } (songBpm.transform as RectTransform).sizeDelta += new Vector2(15f, 0f); var k = new List <string>(); if (hasMessage) { k.Add("MSG"); } if (isChallenge) { k.Add("VS"); } k.Add(request.song["id"]); songBpm.text = string.Join(" - ", k); var songBmpIcon = _tableCell.GetComponentsInChildren <Image>().LastOrDefault(c => string.Equals(c.name, "BpmIcon", StringComparison.OrdinalIgnoreCase)); if (songBmpIcon != null) { songBmpIcon.color = request.requestor.IsModerator ? Color.green : request.requestor.IsVip ? Color.magenta : Color.white; if (!request.requestor.IsModerator && !request.requestor.IsVip) { Destroy(songBmpIcon); } } var songName = _tableCell.GetField <TextMeshProUGUI, LevelListTableCell>("_songNameText"); songName.richText = true; songName.text = $"{request.song["songName"].Value} <size=50%>{RequestBot.GetRating(ref request.song)} <color=#3fff3f>{pp}</color></size>"; var author = _tableCell.GetField <TextMeshProUGUI, LevelListTableCell>("_songAuthorText"); author.richText = true; author.text = dt.Parse(RequestBot.QueueListRow2); var image = _tableCell.GetField <Image, LevelListTableCell>("_coverImage"); var imageSet = false; if (SongCore.Loader.AreSongsLoaded) { var level = CustomLevelForRow(row); if (level != null) { // set image from song's cover image var sprite = await level.GetCoverImageAsync(System.Threading.CancellationToken.None); image.sprite = sprite; imageSet = true; } } if (!imageSet) { var url = request.song["coverURL"].Value; if (!_cachedTextures.TryGetValue(url, out var tex)) { var b = await Plugin.WebClient.DownloadImage($"{url}", System.Threading.CancellationToken.None); tex = new Texture2D(2, 2); tex.LoadImage(b); try { _cachedTextures.Add(url, tex); } catch (Exception) { // ignored } } image.sprite = Base64Sprites.Texture2DToSprite(tex); } UIHelper.AddHintText(_tableCell.transform as RectTransform, dt.Parse(RequestBot.SongHintText)); }
protected override void DidActivate(bool firstActivation, ActivationType type) { if (firstActivation) { if (!SongCore.Loader.AreSongsLoaded) { SongCore.Loader.SongsLoadedEvent += SongLoader_SongsLoadedEvent; } // get table cell instance _requestListTableCellInstance = Resources.FindObjectsOfTypeAll <LevelListTableCell>().First((LevelListTableCell x) => x.name == "LevelListTableCell"); // initialize Yes/No modal YesNoModal.instance.Setup(); _songPreviewPlayer = Resources.FindObjectsOfTypeAll <SongPreviewPlayer>().FirstOrDefault(); RectTransform container = new GameObject("RequestBotContainer", typeof(RectTransform)).transform as RectTransform; container.SetParent(rectTransform, false); container.sizeDelta = new Vector2(60f, 0f); #region TableView Setup and Initialization var go = new GameObject("SongRequestTableView", typeof(RectTransform)); go.SetActive(false); _songListTableView = go.AddComponent <TableView>(); _songListTableView.gameObject.AddComponent <RectMask2D>(); _songListTableView.transform.SetParent(container, false); _songListTableView.SetField("_preallocatedCells", new TableView.CellsGroup[0]); _songListTableView.SetField("_isInitialized", false); var viewport = new GameObject("Viewport").AddComponent <RectTransform>(); viewport.SetParent(go.GetComponent <RectTransform>(), false); (viewport.transform as RectTransform).sizeDelta = new Vector2(0, 0); (viewport.transform as RectTransform).anchorMin = new Vector2(0, 0); (viewport.transform as RectTransform).anchorMax = new Vector2(1, 1); go.GetComponent <ScrollRect>().viewport = viewport; _songListTableView.InvokeMethod <object, TableView>("Init"); _songListTableView.dataSource = this; go.SetActive(true); (_songListTableView.transform as RectTransform).anchorMin = new Vector2(0f, 0f); (_songListTableView.transform as RectTransform).anchorMax = new Vector2(1f, 1f); (_songListTableView.transform as RectTransform).sizeDelta = new Vector2(0f, 60f); (_songListTableView.transform as RectTransform).anchoredPosition = new Vector2(0f, -3f); _songListTableView.didSelectCellWithIdxEvent += DidSelectRow; rectTransform.anchorMin = new Vector2(0.5f, 0f); rectTransform.anchorMax = new Vector2(0.5f, 1f); rectTransform.sizeDelta = new Vector2(74f, 0f); rectTransform.pivot = new Vector2(0.4f, 0.5f); var _songListTableViewScroller = _songListTableView.GetField <TableViewScroller, TableView>("_scroller"); _pageUpButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().Last(x => (x.name == "PageUpButton")), container, false); (_pageUpButton.transform as RectTransform).anchoredPosition = new Vector2(0f, 35f); _pageUpButton.interactable = true; _pageUpButton.onClick.AddListener(delegate() { _songListTableViewScroller.PageScrollUp(); }); _pageDownButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().First(x => (x.name == "PageDownButton")), container, false); (_pageDownButton.transform as RectTransform).anchoredPosition = new Vector2(0f, -41f); _pageDownButton.interactable = true; _pageDownButton.onClick.AddListener(delegate() { _songListTableViewScroller.PageScrollDown(); }); #endregion CenterKeys = new KEYBOARD(container, "", false, -15, 15); #if UNRELEASED // BUG: Need additional modes disabling one shot buttons // BUG: Need to make sure the buttons are usable on older headsets _CurrentSongName = BeatSaberUI.CreateText(container, "", new Vector2(-35, 37f)); _CurrentSongName.fontSize = 3f; _CurrentSongName.color = Color.cyan; _CurrentSongName.alignment = TextAlignmentOptions.Left; _CurrentSongName.enableWordWrapping = false; _CurrentSongName.text = ""; _CurrentSongName2 = BeatSaberUI.CreateText(container, "", new Vector2(-35, 34f)); _CurrentSongName2.fontSize = 3f; _CurrentSongName2.color = Color.cyan; _CurrentSongName2.alignment = TextAlignmentOptions.Left; _CurrentSongName2.enableWordWrapping = false; _CurrentSongName2.text = ""; //CenterKeys.AddKeys(SONGLISTKEY); if (!RequestBot.AddKeyboard(CenterKeys, "mainpanel.kbd")) { CenterKeys.AddKeys(SONGLISTKEY); } ColorDeckButtons(CenterKeys, Color.white, Color.magenta); #endif RequestBot.AddKeyboard(CenterKeys, "CenterPanel.kbd"); CenterKeys.DefaultActions(); #region History button // History button _historyButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().First(o => (o.name == "OkButton")), container, false); _historyButton.ToggleWordWrapping(false); (_historyButton.transform as RectTransform).anchoredPosition = new Vector2(90f, 30f); _historyButton.SetButtonText("History"); _historyButton.onClick.RemoveAllListeners(); _historyButton.onClick.AddListener(delegate() { isShowingHistory = !isShowingHistory; RequestBot.SetTitle(isShowingHistory ? "Song Request History" : "Song Request Queue"); UpdateRequestUI(true); SetUIInteractivity(); _lastSelection = -1; }); _historyHintText = UIHelper.AddHintText(_historyButton.transform as RectTransform, ""); #endregion #region Blacklist button // Blacklist button _blacklistButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().First(o => (o.name == "OkButton")), container, false); _blacklistButton.ToggleWordWrapping(false); (_blacklistButton.transform as RectTransform).anchoredPosition = new Vector2(90f, 10f); _blacklistButton.SetButtonText("Blacklist"); //_blacklistButton.GetComponentInChildren<Image>().color = Color.red; _blacklistButton.onClick.RemoveAllListeners(); _blacklistButton.onClick.AddListener(delegate() { if (NumberOfCells() > 0) { void _onConfirm() { RequestBot.Blacklist(_selectedRow, isShowingHistory, true); if (_selectedRow > 0) { _selectedRow--; } confirmDialogActive = false; } // get song var song = SongInfoForRow(_selectedRow).song; // indicate dialog is active confirmDialogActive = true; // show dialog YesNoModal.instance.ShowDialog("Blacklist Song Warning", $"Blacklisting {song["songName"].Value} by {song["authorName"].Value}\r\nDo you want to continue?", _onConfirm, () => { confirmDialogActive = false; }); } }); UIHelper.AddHintText(_blacklistButton.transform as RectTransform, "Block the selected request from being queued in the future."); #endregion #region Skip button // Skip button _skipButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().First(o => (o.name == "OkButton")), container, false); _skipButton.ToggleWordWrapping(false); (_skipButton.transform as RectTransform).anchoredPosition = new Vector2(90f, 0f); _skipButton.SetButtonText("Skip"); //_skipButton.GetComponentInChildren<Image>().color = Color.yellow; _skipButton.onClick.RemoveAllListeners(); _skipButton.onClick.AddListener(delegate() { if (NumberOfCells() > 0) { void _onConfirm() { // get selected song currentsong = SongInfoForRow(_selectedRow); // skip it RequestBot.Skip(_selectedRow); // select previous song if not first song if (_selectedRow > 0) { _selectedRow--; } // indicate dialog is no longer active confirmDialogActive = false; } // get song var song = SongInfoForRow(_selectedRow).song; // indicate dialog is active confirmDialogActive = true; // show dialog YesNoModal.instance.ShowDialog("Skip Song Warning", $"Skipping {song["songName"].Value} by {song["authorName"].Value}\r\nDo you want to continue?", _onConfirm, () => { confirmDialogActive = false; }); } }); UIHelper.AddHintText(_skipButton.transform as RectTransform, "Remove the selected request from the queue."); #endregion #region Play button // Play button _playButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().First(o => (o.name == "OkButton")), container, false); _playButton.ToggleWordWrapping(false); (_playButton.transform as RectTransform).anchoredPosition = new Vector2(90f, -10f); _playButton.SetButtonText("Play"); _playButton.GetComponentInChildren <Image>().color = Color.green; _playButton.onClick.RemoveAllListeners(); _playButton.onClick.AddListener(delegate() { if (NumberOfCells() > 0) { currentsong = SongInfoForRow(_selectedRow); RequestBot.played.Add(currentsong.song); RequestBot.WriteJSON(RequestBot.playedfilename, ref RequestBot.played); SetUIInteractivity(false); RequestBot.Process(_selectedRow, isShowingHistory); _selectedRow = -1; } }); UIHelper.AddHintText(_playButton.transform as RectTransform, "Download and scroll to the currently selected request."); #endregion #region Queue button // Queue button _queueButton = Instantiate(Resources.FindObjectsOfTypeAll <Button>().First(o => (o.name == "OkButton")), container, false); _queueButton.ToggleWordWrapping(false); _queueButton.SetButtonTextSize(3.5f); (_queueButton.transform as RectTransform).anchoredPosition = new Vector2(90f, -30f); _queueButton.SetButtonText(RequestBotConfig.Instance.RequestQueueOpen ? "Queue Open" : "Queue Closed"); _queueButton.GetComponentInChildren <Image>().color = RequestBotConfig.Instance.RequestQueueOpen ? Color.green : Color.red;; _queueButton.interactable = true; _queueButton.onClick.RemoveAllListeners(); _queueButton.onClick.AddListener(delegate() { RequestBotConfig.Instance.RequestQueueOpen = !RequestBotConfig.Instance.RequestQueueOpen; RequestBotConfig.Instance.Save(); RequestBot.WriteQueueStatusToFile(RequestBotConfig.Instance.RequestQueueOpen ? "Queue is open." : "Queue is closed."); RequestBot.Instance.QueueChatMessage(RequestBotConfig.Instance.RequestQueueOpen ? "Queue is open." : "Queue is closed."); UpdateRequestUI(); }); UIHelper.AddHintText(_queueButton.transform as RectTransform, "Open/Close the queue."); #endregion // Set default RequestFlowCoordinator title RequestBot.SetTitle(isShowingHistory ? "Song Request History" : "Song Request Queue"); } base.DidActivate(firstActivation, type); UpdateRequestUI(); SetUIInteractivity(true); }
protected override void DidActivate(bool firstActivation, bool addedToHierarchy, bool screenSystemEnabling) { if (firstActivation) { if (!SongCore.Loader.AreSongsLoaded) { SongCore.Loader.SongsLoadedEvent += SongLoader_SongsLoadedEvent; } Plugin.Log("DidActivate 001"); // get table cell instance _requestListTableCellInstance = Resources.FindObjectsOfTypeAll <LevelListTableCell>().First((LevelListTableCell x) => x.name == "LevelListTableCell"); // initialize Yes/No modal YesNoModal.instance.Setup(); Plugin.Log("DidActivate 002"); _songPreviewPlayer = Resources.FindObjectsOfTypeAll <SongPreviewPlayer>().FirstOrDefault(); RectTransform container = new GameObject("RequestBotContainer", typeof(RectTransform)).transform as RectTransform; container.SetParent(rectTransform, false); #region TableView Setup and Initialization var go = new GameObject("SongRequestTableView", typeof(RectTransform)); go.SetActive(false); go.AddComponent <ScrollRect>(); go.AddComponent <Touchable>(); go.AddComponent <EventSystemListener>(); ScrollView scrollView = go.AddComponent <ScrollView>(); _songListTableView = go.AddComponent <TableView>(); go.AddComponent <RectMask2D>(); _songListTableView.transform.SetParent(container, false); _songListTableView.SetField("_preallocatedCells", new TableView.CellsGroup[0]); _songListTableView.SetField("_isInitialized", false); _songListTableView.SetField("_scrollView", scrollView); var viewport = new GameObject("Viewport").AddComponent <RectTransform>(); viewport.SetParent(go.GetComponent <RectTransform>(), false); go.GetComponent <ScrollRect>().viewport = viewport; (viewport.transform as RectTransform).sizeDelta = new Vector2(70f, 70f); RectTransform content = new GameObject("Content").AddComponent <RectTransform>(); content.SetParent(viewport, false); scrollView.SetField("_contentRectTransform", content); scrollView.SetField("_viewport", viewport); _songListTableView.SetDataSource(this, false); _songListTableView.LazyInit(); go.SetActive(true); (_songListTableView.transform as RectTransform).sizeDelta = new Vector2(70f, 70f); (_songListTableView.transform as RectTransform).anchoredPosition = new Vector2(3f, 0f); _songListTableView.didSelectCellWithIdxEvent += DidSelectRow; _pageUpButton = UIHelper.CreateUIButton("SRMPageUpButton", container, "PracticeButton", new Vector2(0f, 38.5f), new Vector2(15f, 7f), () => { scrollView.PageUpButtonPressed(); }, "˄"); Destroy(_pageUpButton.GetComponentsInChildren <ImageView>().FirstOrDefault(x => x.name == "Underline")); _pageDownButton = UIHelper.CreateUIButton("SRMPageDownButton", container, "PracticeButton", new Vector2(0f, -38.5f), new Vector2(15f, 7f), () => { scrollView.PageDownButtonPressed(); }, "˅"); Destroy(_pageDownButton.GetComponentsInChildren <ImageView>().FirstOrDefault(x => x.name == "Underline")); #endregion CenterKeys = new KEYBOARD(container, "", false, -15, 15); #if UNRELEASED // BUG: Need additional modes disabling one shot buttons // BUG: Need to make sure the buttons are usable on older headsets Plugin.Log("DidActivate 005"); _CurrentSongName = BeatSaberUI.CreateText(container, "", new Vector2(-35, 37f)); _CurrentSongName.fontSize = 3f; _CurrentSongName.color = Color.cyan; _CurrentSongName.alignment = TextAlignmentOptions.Left; _CurrentSongName.enableWordWrapping = false; _CurrentSongName.text = ""; _CurrentSongName2 = BeatSaberUI.CreateText(container, "", new Vector2(-35, 34f)); _CurrentSongName2.fontSize = 3f; _CurrentSongName2.color = Color.cyan; _CurrentSongName2.alignment = TextAlignmentOptions.Left; _CurrentSongName2.enableWordWrapping = false; _CurrentSongName2.text = ""; //CenterKeys.AddKeys(SONGLISTKEY); if (!RequestBot.AddKeyboard(CenterKeys, "mainpanel.kbd")) { CenterKeys.AddKeys(SONGLISTKEY); } ColorDeckButtons(CenterKeys, Color.white, Color.magenta); #endif RequestBot.AddKeyboard(CenterKeys, "CenterPanel.kbd"); CenterKeys.DefaultActions(); #region History button // History button _historyButton = UIHelper.CreateUIButton("SRMHistory", container, "PracticeButton", new Vector2(53f, 30f), new Vector2(25f, 15f), () => { isShowingHistory = !isShowingHistory; RequestBot.SetTitle(isShowingHistory ? "Song Request History" : "Song Request Queue"); if (NumberOfCells() > 0) { _songListTableView.ScrollToCellWithIdx(0, TableView.ScrollPositionType.Beginning, false); _songListTableView.SelectCellWithIdx(0); _selectedRow = 0; } else { _selectedRow = -1; } UpdateRequestUI(true); SetUIInteractivity(); _lastSelection = -1; }, "History"); _historyButton.ToggleWordWrapping(false); _historyHintText = UIHelper.AddHintText(_historyButton.transform as RectTransform, ""); #endregion #region Blacklist button // Blacklist button _blacklistButton = UIHelper.CreateUIButton("SRMBlacklist", container, "PracticeButton", new Vector2(53f, 10f), new Vector2(25f, 15f), () => { if (NumberOfCells() > 0) { void _onConfirm() { RequestBot.Blacklist(_selectedRow, isShowingHistory, true); if (_selectedRow > 0) { _selectedRow--; } confirmDialogActive = false; } // get song var song = SongInfoForRow(_selectedRow).song; // indicate dialog is active confirmDialogActive = true; // show dialog YesNoModal.instance.ShowDialog("Blacklist Song Warning", $"Blacklisting {song["songName"].Value} by {song["authorName"].Value}\r\nDo you want to continue?", _onConfirm, () => { confirmDialogActive = false; }); } }, "Blacklist"); _blacklistButton.ToggleWordWrapping(false); UIHelper.AddHintText(_blacklistButton.transform as RectTransform, "Block the selected request from being queued in the future."); #endregion #region Skip button // Skip button _skipButton = UIHelper.CreateUIButton("SRMSkip", container, "PracticeButton", new Vector2(53f, 0f), new Vector2(25f, 15f), () => { if (NumberOfCells() > 0) { // get song var song = SongInfoForRow(_selectedRow).song; void _onConfirm() { // get selected song currentsong = SongInfoForRow(_selectedRow); // skip it RequestBot.Skip(_selectedRow); // select previous song if not first song if (_selectedRow > 0) { _selectedRow--; } // indicate dialog is no longer active confirmDialogActive = false; } // indicate dialog is active confirmDialogActive = true; // show dialog YesNoModal.instance.ShowDialog("Skip Song Warning", $"Skipping {song["songName"].Value} by {song["authorName"].Value}\r\nDo you want to continue?", _onConfirm, () => { confirmDialogActive = false; }); } }, "Skip"); _skipButton.ToggleWordWrapping(false); UIHelper.AddHintText(_skipButton.transform as RectTransform, "Remove the selected request from the queue."); #endregion #region Play button // Play button _playButton = UIHelper.CreateUIButton("SRMPlay", container, "ActionButton", new Vector2(53f, -10f), new Vector2(25f, 15f), () => { if (NumberOfCells() > 0) { currentsong = SongInfoForRow(_selectedRow); RequestBot.played.Add(currentsong.song); RequestBot.WriteJSON(RequestBot.playedfilename, ref RequestBot.played); SetUIInteractivity(false); RequestBot.Process(_selectedRow, isShowingHistory); _selectedRow = -1; } }, "Play"); ((RectTransform)_playButton.transform).localScale = Vector3.one; _playButton.GetComponent <NoTransitionsButton>().enabled = true; _playButton.ToggleWordWrapping(false); _playButton.interactable = ((isShowingHistory && RequestHistory.Songs.Count > 0) || (!isShowingHistory && RequestQueue.Songs.Count > 0)); UIHelper.AddHintText(_playButton.transform as RectTransform, "Download and scroll to the currently selected request."); #endregion #region Queue button // Queue button _queueButton = UIHelper.CreateUIButton("SRMQueue", container, "PracticeButton", new Vector2(53f, -30f), new Vector2(25f, 15f), () => { RequestBotConfig.Instance.RequestQueueOpen = !RequestBotConfig.Instance.RequestQueueOpen; RequestBotConfig.Instance.Save(); RequestBot.WriteQueueStatusToFile(RequestBotConfig.Instance.RequestQueueOpen ? "Queue is open." : "Queue is closed."); RequestBot.Instance.QueueChatMessage(RequestBotConfig.Instance.RequestQueueOpen ? "Queue is open." : "Queue is closed."); UpdateRequestUI(); }, RequestBotConfig.Instance.RequestQueueOpen ? "Queue Open" : "Queue Closed"); _queueButton.ToggleWordWrapping(true); _queueButton.SetButtonUnderlineColor(RequestBotConfig.Instance.RequestQueueOpen ? Color.green : Color.red); _queueButton.SetButtonTextSize(3.5f); UIHelper.AddHintText(_queueButton.transform as RectTransform, "Open/Close the queue."); #endregion #region Websocket Connect Button // Websocket Connect button _websocketConnectButton = UIHelper.CreateUIButton("WSConnect", container, "PracticeButton", new Vector2(53f, -20f), new Vector2(25f, 15f), () => { ChatHandler.WebsocketHandlerConnect(); }, "Connect WS"); _websocketConnectButton.ToggleWordWrapping(true); _websocketConnectButton.SetButtonUnderlineColor(Color.red); _websocketConnectButton.SetButtonTextSize(3.5f); UIHelper.AddHintText(_websocketConnectButton.transform as RectTransform, "Connects the Websocket"); #endregion // Set default RequestFlowCoordinator title RequestBot.SetTitle(isShowingHistory ? "Song Request History" : "Song Request Queue"); } base.DidActivate(firstActivation, addedToHierarchy, screenSystemEnabling); if (addedToHierarchy) { _selectedRow = -1; _songListTableView.ClearSelection(); } UpdateRequestUI(); SetUIInteractivity(true); }