You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

411 lines
15 KiB

  1. using BSIPA_ModList.UI.ViewControllers;
  2. using CustomUI.BeatSaber;
  3. using CustomUI.MenuButton;
  4. using IPA.Loader;
  5. using IPA.Updating.BeatMods;
  6. using IPA.Utilities;
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.Diagnostics;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using TMPro;
  15. using UnityEngine;
  16. using UnityEngine.UI;
  17. using VRUI;
  18. namespace BSIPA_ModList.UI
  19. {
  20. internal class ModInfoViewController : VRUIViewController
  21. {
  22. internal Sprite Icon;
  23. internal string Name;
  24. internal string Version;
  25. internal string Author;
  26. internal string Description;
  27. internal PluginLoader.PluginMetadata UpdateInfo;
  28. private static RectTransform rowTransformOriginal;
  29. private ModInfoView view;
  30. private RectTransform rowTransform;
  31. private Button linkHomeButton;
  32. private Button linkSourceButton;
  33. private Button linkDonateButton;
  34. private ModListFlowCoordinator flowController;
  35. private bool showEnableDisable = false;
  36. private TextMeshProUGUI restartMessage;
  37. private Button enableDisableButton;
  38. private new bool enabled = false;
  39. public void Init(Sprite icon, string name, string version, string author, string description, PluginLoader.PluginMetadata updateInfo, PluginManifest.LinksObject links = null, bool showEnDis = false, ModListFlowCoordinator mlfc = null)
  40. {
  41. showEnableDisable = showEnDis;
  42. Icon = icon;
  43. Name = name;
  44. Version = version;
  45. Author = author;
  46. Description = description;
  47. UpdateInfo = updateInfo;
  48. enabled = !PluginManager.IsDisabled(updateInfo);
  49. flowController = mlfc;
  50. if (rowTransformOriginal == null)
  51. rowTransformOriginal = MenuButtonUI.Instance.GetPrivateField<RectTransform>("menuButtonsOriginal");
  52. // i also have no clue why this is necessary
  53. rectTransform.anchorMin = new Vector2(0f, 0f);
  54. rectTransform.anchorMax = new Vector2(0.5f, 1f);
  55. var go = new GameObject("Info View", typeof(RectTransform));
  56. go.SetActive(false);
  57. go.AddComponent<RectMask2D>();
  58. view = go.AddComponent<ModInfoView>();
  59. var rt = view.transform as RectTransform;
  60. rt.SetParent(transform);
  61. rt.anchorMin = new Vector2(0f, 0f);
  62. rt.anchorMax = new Vector2(1f, 1f);
  63. rt.anchoredPosition = new Vector2(0f, 0);
  64. view.Init(this);
  65. go.SetActive(true);
  66. if (showEnDis)
  67. {
  68. restartMessage = BeatSaberUI.CreateText(rectTransform, "A restart is required to apply", new Vector2(11f, 33.5f));
  69. restartMessage.fontSize = 4f;
  70. restartMessage.gameObject.SetActive(false);
  71. enableDisableButton = BeatSaberUI.CreateUIButton(rectTransform, "CreditsButton", new Vector2(33, 32), new Vector2(25, 10), ToggleEnable);
  72. enableDisableButton.GetComponentInChildren<StartMiddleEndButtonBackgroundController>().SetMiddleSprite();
  73. UpdateButtonText();
  74. }
  75. SetupLinks(links);
  76. }
  77. private Action setAction = () => { };
  78. private void ToggleEnable()
  79. {
  80. var info = enabled ? PluginManager.InfoFromMetadata(UpdateInfo) : null;
  81. bool needsRestart;
  82. if (enabled)
  83. needsRestart = PluginManager.DisablePlugin(info);
  84. else
  85. needsRestart = PluginManager.EnablePlugin(UpdateInfo);
  86. UpdateButtonText(!enabled, needsRestart);
  87. if (!needsRestart)
  88. flowController.exitActions.Add(setAction);
  89. }
  90. private void UpdateButtonText(bool? _enabled = null, bool _needsRestart = false)
  91. {
  92. enabled = _enabled ?? enabled;
  93. if (enabled)
  94. enableDisableButton.SetButtonText("Disable");
  95. else
  96. enableDisableButton.SetButtonText("Enable");
  97. restartMessage.gameObject.SetActive(_needsRestart);
  98. }
  99. public void Reload(string name, string version, string author, string description)
  100. {
  101. Name = name;
  102. Version = version;
  103. Author = author;
  104. Description = description;
  105. view.Refresh();
  106. }
  107. private void SetupLinks(PluginManifest.LinksObject links = null, Uri moreInfoLink = null)
  108. {
  109. bool addedLink = false;
  110. if (links != null || moreInfoLink != null)
  111. {
  112. Logger.log.Debug($"Adding links");
  113. rowTransform = Instantiate(rowTransformOriginal, rectTransform);
  114. rowTransform.anchorMin = new Vector2(0f, 0f);
  115. rowTransform.anchorMax = new Vector2(1f, .15f);
  116. rowTransform.anchoredPosition = new Vector2(-3.5f, 4f);
  117. rowTransform.sizeDelta = Vector2.zero;
  118. Destroy(rowTransform.GetComponent<StartMiddleEndButtonsGroup>());
  119. foreach (Transform child in rowTransform)
  120. {
  121. child.name = string.Empty;
  122. Destroy(child.gameObject);
  123. }
  124. if (links?.ProjectHome != null)
  125. {
  126. linkHomeButton = BeatSaberUI.CreateUIButton(rowTransform, "CreditsButton", buttonText: "Home", anchoredPosition: Vector2.zero, sizeDelta: new Vector2(20, 10),
  127. onClick: () => Process.Start(links.ProjectHome.ToString()));
  128. addedLink = true;
  129. }
  130. if (links?.ProjectSource != null)
  131. {
  132. linkSourceButton = BeatSaberUI.CreateUIButton(rowTransform, "CreditsButton", buttonText: "Source", anchoredPosition: Vector2.zero, sizeDelta: new Vector2(20, 10),
  133. onClick: () => Process.Start(links.ProjectSource.ToString()));
  134. addedLink = true;
  135. }
  136. if (links?.Donate != null)
  137. {
  138. linkDonateButton = BeatSaberUI.CreateUIButton(rowTransform, "CreditsButton", buttonText: "Donate", anchoredPosition: Vector2.zero, sizeDelta: new Vector2(20, 10),
  139. onClick: () => Process.Start(links.Donate.ToString()));
  140. addedLink = true;
  141. }
  142. if (moreInfoLink != null)
  143. {
  144. linkDonateButton = BeatSaberUI.CreateUIButton(rowTransform, "CreditsButton", buttonText: "More Info", anchoredPosition: Vector2.zero, sizeDelta: new Vector2(20, 10),
  145. onClick: () => Process.Start(moreInfoLink.ToString()));
  146. addedLink = true;
  147. }
  148. foreach (var cmp in rowTransform.GetComponentsInChildren<StartMiddleEndButtonBackgroundController>())
  149. cmp.SetMiddleSprite();
  150. }
  151. if (UpdateInfo != null && !addedLink)
  152. StartCoroutine(GetMoreInfoLink());
  153. }
  154. private IEnumerator GetMoreInfoLink()
  155. {
  156. Logger.log.Debug($"Getting more info link");
  157. Ref<ApiEndpoint.Mod> mod = new Ref<ApiEndpoint.Mod>(null);
  158. if (UpdateInfo.Id == null) yield break;
  159. yield return Updater.GetModInfo(UpdateInfo.Id, UpdateInfo.Version.ToString(), mod);
  160. try { mod.Verify(); }
  161. catch (Exception e)
  162. {
  163. Logger.log.Warn($"Error getting more info link for mod {UpdateInfo.Id}");
  164. Logger.log.Warn(e);
  165. yield break;
  166. }
  167. SetupLinks(null, mod.Value.Link);
  168. }
  169. #if DEBUG
  170. public void Update()
  171. {
  172. #if ADJUST_INFO_BUTTON_UI_LINKS
  173. RectTransform rt = rowTransform;
  174. if (rt == null) return;
  175. var cpos = rt.anchoredPosition;
  176. if (Input.GetKey(KeyCode.LeftArrow))
  177. {
  178. rt.anchoredPosition = new Vector2(cpos.x - .1f, cpos.y);
  179. }
  180. else if (Input.GetKey(KeyCode.RightArrow))
  181. {
  182. rt.anchoredPosition = new Vector2(cpos.x + .1f, cpos.y);
  183. }
  184. else if (Input.GetKey(KeyCode.UpArrow))
  185. {
  186. rt.anchoredPosition = new Vector2(cpos.x, cpos.y + .1f);
  187. }
  188. else if (Input.GetKey(KeyCode.DownArrow))
  189. {
  190. rt.anchoredPosition = new Vector2(cpos.x, cpos.y - .1f);
  191. }
  192. else
  193. return;
  194. Logger.log.Debug($"Position now at {rt.anchoredPosition}");
  195. #endif
  196. }
  197. #endif
  198. }
  199. internal class ModInfoView : MonoBehaviour
  200. {
  201. private MarkdownView mdv;
  202. private TextMeshProUGUI titleText;
  203. private TextMeshProUGUI authorText;
  204. private Image icon;
  205. private ModInfoViewController controller;
  206. private const string TitleFormat = "{0} <size=60%>{1}";
  207. public void Init(ModInfoViewController controller)
  208. {
  209. this.controller = controller;
  210. var rectTransform = transform as RectTransform;
  211. rectTransform.sizeDelta = new Vector2(60f, 10f);
  212. titleText = BeatSaberUI.CreateText(rectTransform, string.Format(TitleFormat, controller.Name, controller.Version), new Vector2(11f, 27.5f));
  213. titleText.fontSize = 6f;
  214. authorText = BeatSaberUI.CreateText(rectTransform, controller.Author, new Vector2(11f, 22f));
  215. authorText.fontSize = 4.5f;
  216. var mdvgo = new GameObject("MarkDown Desc");
  217. mdvgo.SetActive(false);
  218. mdv = mdvgo.AddComponent<MarkdownView>();
  219. mdv.rectTransform.SetParent(rectTransform);
  220. mdv.rectTransform.anchorMin = new Vector2(.5f, .5f);
  221. mdv.rectTransform.anchorMax = new Vector2(.5f, .5f);
  222. mdv.rectTransform.anchoredPosition = new Vector2(-4f, -3.6f);
  223. mdv.rectTransform.sizeDelta = new Vector2(65f, 40f);
  224. mdvgo.SetActive(true);
  225. mdv.Markdown = controller.Description;
  226. icon = new GameObject("Mod Info View Icon", typeof(RectTransform)).AddComponent<Image>();
  227. icon.gameObject.SetActive(false);
  228. icon.rectTransform.SetParent(rectTransform, false);
  229. icon.rectTransform.anchorMin = new Vector2(0.5f, 0.44f);
  230. icon.rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
  231. icon.rectTransform.sizeDelta = new Vector2(60f, 10f);
  232. icon.rectTransform.anchoredPosition = new Vector2(-27.8f, 27.3f);
  233. icon.sprite = controller.Icon;
  234. icon.preserveAspect = true;
  235. icon.useSpriteMesh = true;
  236. icon.material = CustomUI.Utilities.UIUtilities.NoGlowMaterial;
  237. icon.gameObject.SetActive(true);
  238. }
  239. public void Refresh()
  240. {
  241. titleText.text = string.Format(TitleFormat, controller.Name, controller.Version);
  242. authorText.text = controller.Author;
  243. mdv.Markdown = controller.Description;
  244. icon.sprite = controller.Icon;
  245. }
  246. #if DEBUG
  247. #if ADJUST_INFO_TEXT_UI_KEYS
  248. private int currentItem = 0;
  249. #endif
  250. public void Update()
  251. {
  252. #if ADJUST_INFO_TEXT_UI_KEYS
  253. RectTransform rt;
  254. switch (currentItem)
  255. {
  256. default:
  257. currentItem = 0;
  258. goto case 0; // idk why this is needed tbh
  259. case 0:
  260. rt = titleText.rectTransform;
  261. break;
  262. case 1:
  263. rt = authorText.rectTransform;
  264. break;
  265. case 2:
  266. rt = descText.rectTransform;
  267. break;
  268. }
  269. if (Input.GetKeyDown(KeyCode.N))
  270. currentItem++;
  271. var cpos = rt.anchoredPosition;
  272. if (Input.GetKey(KeyCode.LeftArrow))
  273. {
  274. rt.anchoredPosition = new Vector2(cpos.x - .1f, cpos.y);
  275. }
  276. else if (Input.GetKey(KeyCode.RightArrow))
  277. {
  278. rt.anchoredPosition = new Vector2(cpos.x + .1f, cpos.y);
  279. }
  280. else if (Input.GetKey(KeyCode.UpArrow))
  281. {
  282. rt.anchoredPosition = new Vector2(cpos.x, cpos.y + .1f);
  283. }
  284. else if (Input.GetKey(KeyCode.DownArrow))
  285. {
  286. rt.anchoredPosition = new Vector2(cpos.x, cpos.y - .1f);
  287. }
  288. else
  289. return;
  290. Logger.log.Debug($"Position now at {rt.anchoredPosition}");
  291. #endif
  292. #if ADJUST_INFO_ICON_UI_KEYS
  293. var rt = icon.rectTransform;
  294. if (Input.GetKey(KeyCode.Z))
  295. { // adjust anchormin
  296. var cpos = rt.anchorMin;
  297. if (Input.GetKey(KeyCode.LeftArrow))
  298. {
  299. rt.anchorMin = new Vector2(cpos.x - .001f, cpos.y);
  300. }
  301. else if (Input.GetKey(KeyCode.RightArrow))
  302. {
  303. rt.anchorMin = new Vector2(cpos.x + .001f, cpos.y);
  304. }
  305. else if (Input.GetKey(KeyCode.UpArrow))
  306. {
  307. rt.anchorMin = new Vector2(cpos.x, cpos.y + .001f);
  308. }
  309. else if (Input.GetKey(KeyCode.DownArrow))
  310. {
  311. rt.anchorMin = new Vector2(cpos.x, cpos.y - .001f);
  312. }
  313. else
  314. return;
  315. Logger.log.Debug($"Anchor min now at {rt.anchorMin}");
  316. }
  317. else if(Input.GetKey(KeyCode.X))
  318. { // adjust anchorMax
  319. var cpos = rt.anchorMax;
  320. if (Input.GetKey(KeyCode.LeftArrow))
  321. {
  322. rt.anchorMax = new Vector2(cpos.x - .001f, cpos.y);
  323. }
  324. else if (Input.GetKey(KeyCode.RightArrow))
  325. {
  326. rt.anchorMax = new Vector2(cpos.x + .001f, cpos.y);
  327. }
  328. else if (Input.GetKey(KeyCode.UpArrow))
  329. {
  330. rt.anchorMax = new Vector2(cpos.x, cpos.y + .001f);
  331. }
  332. else if (Input.GetKey(KeyCode.DownArrow))
  333. {
  334. rt.anchorMax = new Vector2(cpos.x, cpos.y - .001f);
  335. }
  336. else
  337. return;
  338. Logger.log.Debug($"Anchor max now at {rt.anchorMax}");
  339. }
  340. else
  341. {
  342. var cpos = rt.anchoredPosition;
  343. if (Input.GetKey(KeyCode.LeftArrow))
  344. {
  345. rt.anchoredPosition = new Vector2(cpos.x - .1f, cpos.y);
  346. }
  347. else if (Input.GetKey(KeyCode.RightArrow))
  348. {
  349. rt.anchoredPosition = new Vector2(cpos.x + .1f, cpos.y);
  350. }
  351. else if (Input.GetKey(KeyCode.UpArrow))
  352. {
  353. rt.anchoredPosition = new Vector2(cpos.x, cpos.y + .1f);
  354. }
  355. else if (Input.GetKey(KeyCode.DownArrow))
  356. {
  357. rt.anchoredPosition = new Vector2(cpos.x, cpos.y - .1f);
  358. }
  359. else
  360. return;
  361. Logger.log.Debug($"Position now at {rt.anchoredPosition}");
  362. }
  363. #endif
  364. }
  365. #endif
  366. }
  367. }