|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
1 | 3 | using System.IO; |
2 | | -using UnityEngine; |
3 | | -using UnityEngine.UI; |
4 | | -using Object = UnityEngine.Object; |
| 4 | +using HarmonyLib; |
| 5 | +using MelonLoader; |
5 | 6 | using S1API.Internal.Abstraction; |
6 | 7 | using S1API.Internal.Patches; |
7 | 8 | using S1API.Internal.Utils; |
8 | | -using System; |
9 | | -using MelonLoader; |
| 9 | +using UnityEngine; |
| 10 | +using UnityEngine.UI; |
| 11 | +using Object = UnityEngine.Object; |
10 | 12 | #if IL2CPPMELON |
11 | 13 | using Il2CppScheduleOne.UI; |
12 | 14 | using Il2CppScheduleOne.UI.Phone; |
@@ -325,16 +327,14 @@ internal void SpawnIcon(HomeScreen homeScreenInstance) |
325 | 327 | return; |
326 | 328 | } |
327 | 329 |
|
328 | | - // Find the LAST icon (the one most recently added) |
329 | | - Transform? lastIcon = appIcons.transform.childCount > 0 ? appIcons.transform.GetChild(appIcons.transform.childCount - 1) : null; |
330 | | - if (lastIcon == null) |
| 330 | + GameObject? iconObj = CreateAppIcon(homeScreenInstance, appIcons.transform); |
| 331 | + if (iconObj == null) |
331 | 332 | { |
332 | | - Logger.Error("No icons found in AppIcons."); |
| 333 | + Logger.Error($"Failed to create an icon for {AppName}."); |
333 | 334 | return; |
334 | 335 | } |
335 | 336 |
|
336 | | - GameObject iconObj = lastIcon.gameObject; |
337 | | - iconObj.name = AppName; // Rename it now |
| 337 | + iconObj.name = AppName; |
338 | 338 |
|
339 | 339 | // Cache icon image for future updates |
340 | 340 | Transform imageTransform = iconObj.transform.Find("Mask/Image"); |
@@ -375,6 +375,55 @@ internal void SpawnIcon(HomeScreen homeScreenInstance) |
375 | 375 | } |
376 | 376 | } |
377 | 377 |
|
| 378 | + /// <summary> |
| 379 | + /// Creates and registers an independent home-screen icon using the native icon prefab. |
| 380 | + /// </summary> |
| 381 | + private static GameObject? CreateAppIcon(HomeScreen homeScreenInstance, Transform parent) |
| 382 | + { |
| 383 | +#if IL2CPPMELON |
| 384 | + GameObject? iconPrefab = homeScreenInstance.appIconPrefab; |
| 385 | +#else |
| 386 | + GameObject? iconPrefab = AccessTools.Field( |
| 387 | + typeof(HomeScreen), |
| 388 | + "appIconPrefab")?.GetValue(homeScreenInstance) as GameObject; |
| 389 | +#endif |
| 390 | + if (iconPrefab == null) |
| 391 | + { |
| 392 | + Logger.Error("HomeScreen appIconPrefab was unavailable."); |
| 393 | + return null; |
| 394 | + } |
| 395 | + |
| 396 | + GameObject iconObject = Object.Instantiate(iconPrefab, parent); |
| 397 | + Button? button = iconObject.GetComponent<Button>(); |
| 398 | + UISelectable? selectable = iconObject.GetComponent<UISelectable>(); |
| 399 | + if (button == null || selectable == null) |
| 400 | + { |
| 401 | + Logger.Error("Native phone app icon prefab is missing Button or UISelectable."); |
| 402 | + Object.Destroy(iconObject); |
| 403 | + return null; |
| 404 | + } |
| 405 | + |
| 406 | +#if IL2CPPMELON |
| 407 | + var nativeButtons = homeScreenInstance.appIcons; |
| 408 | + var uiPanel = homeScreenInstance.uiPanel; |
| 409 | +#else |
| 410 | + var appIconsField = AccessTools.Field(typeof(HomeScreen), "appIcons"); |
| 411 | + var uiPanelField = AccessTools.Field(typeof(HomeScreen), "uiPanel"); |
| 412 | + var nativeButtons = appIconsField?.GetValue(homeScreenInstance) as List<Button>; |
| 413 | + var uiPanel = uiPanelField?.GetValue(homeScreenInstance) as UIPanel; |
| 414 | +#endif |
| 415 | + if (nativeButtons == null || uiPanel == null) |
| 416 | + { |
| 417 | + Logger.Error("HomeScreen icon registration fields were unavailable."); |
| 418 | + Object.Destroy(iconObject); |
| 419 | + return null; |
| 420 | + } |
| 421 | + |
| 422 | + nativeButtons.Add(button); |
| 423 | + uiPanel.AddSelectable(selectable); |
| 424 | + return iconObject; |
| 425 | + } |
| 426 | + |
378 | 427 | /// <summary> |
379 | 428 | /// Opens this phone application, managing proper app state transitions. |
380 | 429 | /// </summary> |
|
0 commit comments