using System.Collections.Generic; using System.IO; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class SongSelectManager : MonoBehaviour { [Header("탭 버튼")] [SerializeField] private Button tabAllBtn; [SerializeField] private Button tabOwnedBtn; [SerializeField] private Color tabActiveColor = Color.white; [SerializeField] private Color tabInactiveColor = new Color(0.6f, 0.6f, 0.6f); [Header("카드 목록")] [SerializeField] private Transform cardContainer; [SerializeField] private GameObject songCardPrefab; [Header("연결")] [SerializeField] private SongDetailPanel detailPanel; [SerializeField] private DownloadManager downloadManager; [Header("상태 오버레이")] [SerializeField] private GameObject loadingOverlay; [SerializeField] private GameObject errorOverlay; [SerializeField] private TMP_Text errorText; private static string CachePath => Path.Combine(Application.persistentDataPath, "songs_cache.json"); private List allSongs = new List(); private bool showingOwned = false; // ── Unity ──────────────────────────────────────────────── private void Start() { tabAllBtn.onClick.AddListener(() => SwitchTab(false)); tabOwnedBtn.onClick.AddListener(() => SwitchTab(true)); detailPanel.gameObject.SetActive(false); SetTabVisual(false); FetchSongs(); } // ── 탭 전환 ────────────────────────────────────────────── private void SwitchTab(bool owned) { showingOwned = owned; SetTabVisual(owned); RefreshCards(); } private void SetTabVisual(bool owned) { tabAllBtn.image.color = owned ? tabInactiveColor : tabActiveColor; tabOwnedBtn.image.color = owned ? tabActiveColor : tabInactiveColor; } // ── 데이터 로드 ─────────────────────────────────────────── private void FetchSongs() { loadingOverlay.SetActive(true); errorOverlay.SetActive(false); downloadManager.FetchSongsList( onSuccess: list => { allSongs = list.songs; SaveCache(list); SongLibrary.Instance.ValidateWithFileSystem(downloadManager, list.songs); loadingOverlay.SetActive(false); RefreshCards(); }, onError: _ => { SongsList cached = LoadCache(); loadingOverlay.SetActive(false); if (cached != null) { allSongs = cached.songs; RefreshCards(); } else { errorOverlay.SetActive(true); errorText.text = "서버 연결 실패\n인터넷 연결을 확인해주세요"; } }); } // ── 카드 갱신 ──────────────────────────────────────────── public void RefreshCards() { foreach (Transform child in cardContainer) Destroy(child.gameObject); List songs = showingOwned ? allSongs.FindAll(s => SongLibrary.Instance.IsSongDownloaded(s.id)) : allSongs; foreach (SongInfo song in songs) { bool downloaded = SongLibrary.Instance.IsSongDownloaded(song.id); GameObject obj = Instantiate(songCardPrefab, cardContainer); SongInfo captured = song; obj.GetComponent().Setup(song, downloaded, () => OnCardClicked(captured)); } } private void OnCardClicked(SongInfo song) { detailPanel.gameObject.SetActive(true); detailPanel.Show(song, downloadManager, this); } // ── 로컬 캐시 (오프라인 폴백) ───────────────────────────── private static void SaveCache(SongsList list) { try { File.WriteAllText(CachePath, JsonUtility.ToJson(list, true)); } catch { } } private static SongsList LoadCache() { if (!File.Exists(CachePath)) return null; try { return JsonUtility.FromJson(File.ReadAllText(CachePath)); } catch { return null; } } }