#nullable enable using Gpm.Ui; using System; using System.Collections.Generic; using System.Linq; using TMPro; using UnityEngine; using UVC.Extention; using UVC.Locale; using UVC.UI.Modal; namespace UVC.UI.List { public class PrefabGrid : MonoBehaviour { [Tooltip("데이터를 표시할 InfiniteScroll 컴포넌트입니다.")] [SerializeField] protected InfiniteScroll? scrollList = null; [Tooltip("검색어 입력을 위한 TMP_InputField 컴포넌트입니다.")] [SerializeField] protected TMP_InputField? inputField = null; [SerializeField] protected TextMeshProUGUI searchResultText; // InfiniteScroll에 표시될 원본 데이터 리스트입니다. protected List? data; protected List? filteredData; private Vector2 originalScrollPosition; /// /// SingletonScene 초기화 과정에서 호출됩니다. /// 필요한 컴포넌트를 찾고, 이벤트 리스너를 등록합니다. /// protected void Start() { // scrollList가 인스펙터에서 할당되지 않았을 경우, 자식에서 찾아봅니다. if (scrollList == null) { scrollList = GetComponentInChildren(); } if (scrollList == null) { Debug.LogError("InfiniteScroll component is not assigned or found in Children."); return; } if (scrollList != null) { var rect = scrollList.GetComponent(); originalScrollPosition = scrollList.GetComponent().anchoredPosition; } // inputField가 인스펙터에서 할당되지 않았을 경우, 자식에서 찾아봅니다. if (inputField == null) { inputField = GetComponentInChildren(); } if (inputField != null) { // 사용자가 검색어를 입력하고 Enter 키를 누르거나 입력을 완료했을 때 OnInputFieldChanged 메서드가 호출되도록 이벤트를 등록합니다. //inputField.onEndEdit.AddListener(OnInputFieldChanged); inputField.onSubmit.AddListener(OnInputFieldChanged); } } protected void OnDestroy() { if (inputField != null) { // Init에서 등록한 리스너를 제거합니다. //inputField.onEndEdit.RemoveListener(OnInputFieldChanged); inputField.onSubmit.RemoveListener(OnInputFieldChanged); } } /// /// FactoryObjectManager에서 데이터를 가져와 스크롤 리스트를 설정합니다. /// 데이터를 카테고리별로 그룹화하고, 각 카테고리와 해당 항목들을 리스트에 추가합니다. /// public virtual void SetupData(List objectsData) { if (scrollList == null) { Debug.LogError("InfiniteScroll component is not assigned."); return; } if (inputField != null) inputField.text = string.Empty; if (searchResultText != null) searchResultText.gameObject.SetActive(false); scrollList.ClearData(); // 스크롤 리스트의 기존 데이터를 모두 비웁니다. if (data == null) data = new List(); data?.Clear(); data?.AddRange(objectsData); // 3. 완성된 데이터 리스트를 InfiniteScroll에 한 번에 삽입하여 UI를 업데이트합니다. scrollList.InsertData(data!.ToArray()); } /// /// 검색 입력 필드의 내용이 변경되고 제출(Enter)되었을 때 호출됩니다. /// 입력된 텍스트를 기반으로 scrollList의 내용을 필터링합니다. /// /// 사용자가 입력한 검색어 protected virtual void OnInputFieldChanged(string text) { Debug.Log($"Searching1 for: {text}"); if (scrollList == null || inputField == null) return; // 검색어가 비어있으면 필터링을 수행하지 않습니다. if (string.IsNullOrEmpty(text)) return; // 검색어가 너무 짧으면 사용자에게 알림을 표시하고 입력을 초기화합니다. if (text.Length < 3) { inputField.text = string.Empty; // 입력 필드 초기화 inputField.ActivateInputField(); // 입력 필드에 다시 포커스 설정 Toast.Show("검색어는 3글자 이상 입력해주세요.", 2f); return; } Debug.Log($"Searching2 for: {text}"); // 원본 데이터(data)를 기반으로 필터링된 새로운 리스트를 생성합니다. List filteredItems = data.Where(itemData => { return itemData.ItemName.Contains(text, StringComparison.OrdinalIgnoreCase); }).ToList(); if (filteredData == null) { filteredData = new List(); } else { filteredData.Clear(); } string resultText = LocalizationManager.Instance.GetString("검색결과"); if (searchResultText != null) { searchResultText.gameObject.SetActive(true); searchResultText.text = $"{resultText}: {filteredItems.Count}건"; } if (scrollList != null) { var rect = scrollList.GetComponent(); rect.anchoredPosition = new Vector2(originalScrollPosition.x, originalScrollPosition.y - 24); } // 필터링된 아이템들을 결과 리스트에 추가합니다. filteredData.AddRange(filteredItems); // 스크롤 리스트를 비우고 필터링된 결과로 새로 채웁니다. scrollList?.Clear(); scrollList?.InsertData(filteredData.ToArray(), true); } public void SetSearchText(string text) { if (inputField != null) { inputField.text = $"@{text} "; inputField.SetCaretToEndAsync().Forget(); } } /// /// 검색창의 'X' 버튼 클릭 시 호출됩니다. /// 입력 필드를 비우고, 적용되었던 모든 필터를 제거합니다. /// public virtual void OnClickClearText() { if (inputField != null && scrollList != null && data != null) { if (scrollList != null && !inputField.text.IsNullOrEmpty()) { var rect = scrollList.GetComponent(); rect.anchoredPosition = originalScrollPosition; } if (searchResultText != null) searchResultText.gameObject.SetActive(false); inputField.text = string.Empty; // 입력 필드 초기화 inputField.ActivateInputField(); // 입력 필드에 다시 포커스 설정 if (filteredData != null) { filteredData.Clear(); // 필터링된 데이터 리스트를 비웁니다. filteredData = null; } // scrollList에 설정된 필터를 제거(null)하여 모든 항목이 보이도록 합니다. scrollList?.SetFilter(null); scrollList?.ClearData(); // 스크롤 리스트의 내용을 비웁니다. scrollList?.InsertData(data.ToArray()); } } } }