backup
This commit is contained in:
8
Assets/Scripts/Simulator/UI/SimulationList.meta
Normal file
8
Assets/Scripts/Simulator/UI/SimulationList.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d47ffe056b460d4dbc64066a60ee9b3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Simulator.Data
|
||||
{
|
||||
[Serializable]
|
||||
public class SimulationListResponse
|
||||
{
|
||||
public int status;
|
||||
public string code;
|
||||
public string message;
|
||||
public SimulationListData data;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SimulationListData
|
||||
{
|
||||
public List<SimulationRowData> rows;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SimulationRowData
|
||||
{
|
||||
public int id;
|
||||
public int userId;
|
||||
public string name;
|
||||
public string description;
|
||||
public string createdAt;
|
||||
public string updatedAt;
|
||||
public string deletedAt;
|
||||
public SimulationUserData User;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SimulationUserData
|
||||
{
|
||||
public int id;
|
||||
public string userid;
|
||||
public string name;
|
||||
public string auth;
|
||||
public string email;
|
||||
public bool active;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e9b519de167e2c46b447a57ea42ac4a
|
||||
@@ -0,0 +1,88 @@
|
||||
using Simulator.Data;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Simulator.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 시뮬레이션 목록의 개별 행 View
|
||||
/// Row Prefab에 붙여서 사용합니다.
|
||||
/// </summary>
|
||||
public class SimulationListRowView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text nameText;
|
||||
[SerializeField] private TMP_Text userText;
|
||||
[SerializeField] private TMP_Text dateText;
|
||||
|
||||
[SerializeField] private Button rowButton;
|
||||
[SerializeField] private Image backgroundImage;
|
||||
|
||||
[Header("선택 색상")]
|
||||
[SerializeField] private Color normalColor = new Color(1f, 1f, 1f, 0f);
|
||||
[SerializeField] private Color selectedColor = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||
|
||||
public SimulationRowData Data { get; private set; }
|
||||
|
||||
public event Action<SimulationListRowView> OnClicked;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (rowButton != null)
|
||||
{
|
||||
rowButton.onClick.AddListener(() => OnClicked?.Invoke(this));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 행에 데이터를 바인딩합니다.
|
||||
/// </summary>
|
||||
public void SetData(SimulationRowData data)
|
||||
{
|
||||
Data = data;
|
||||
|
||||
if (nameText != null)
|
||||
nameText.text = data.name ?? "";
|
||||
|
||||
if (userText != null)
|
||||
userText.text = data.User?.userid ?? "";
|
||||
|
||||
if (dateText != null)
|
||||
dateText.text = FormatDate(data.createdAt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 선택 상태를 설정합니다.
|
||||
/// </summary>
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
if (backgroundImage != null)
|
||||
backgroundImage.color = selected ? selectedColor : normalColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 서버에서 받은 날짜 문자열을 표시용으로 포맷합니다.
|
||||
/// "2026-02-23 07:53:14.669396+00" → "2026-02-23 16:53:14" (로컬 시간)
|
||||
/// </summary>
|
||||
private string FormatDate(string dateString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(dateString)) return "";
|
||||
|
||||
if (DateTimeOffset.TryParse(dateString, CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.None, out var dto))
|
||||
{
|
||||
return dto.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
return dateString;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (rowButton != null)
|
||||
rowButton.onClick.RemoveAllListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c584342c7e46ab45945103a9178172e
|
||||
164
Assets/Scripts/Simulator/UI/SimulationList/SimulationListView.cs
Normal file
164
Assets/Scripts/Simulator/UI/SimulationList/SimulationListView.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Simulator.Config;
|
||||
using Simulator.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UVC.Network;
|
||||
|
||||
namespace Simulator.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 시뮬레이션 목록을 표시하는 View 스크립트
|
||||
/// UI Prefab의 루트에 붙여서 사용합니다.
|
||||
/// </summary>
|
||||
public class SimulationListView : MonoBehaviour
|
||||
{
|
||||
[Header("리스트")]
|
||||
[SerializeField] private Transform listContainer;
|
||||
[SerializeField] private GameObject rowPrefab;
|
||||
|
||||
[Header("검색")]
|
||||
[SerializeField] private TMP_InputField searchInput;
|
||||
|
||||
[Header("정보")]
|
||||
[SerializeField] private TMP_Text dataCountText;
|
||||
|
||||
private List<SimulationRowData> allRows = new List<SimulationRowData>();
|
||||
private List<SimulationListRowView> rowViews = new List<SimulationListRowView>();
|
||||
|
||||
private SimulationRowData selectedRow;
|
||||
|
||||
/// <summary>
|
||||
/// 행 선택 시 호출되는 이벤트 (선택된 SimulationRowData 전달)
|
||||
/// </summary>
|
||||
public event Action<SimulationRowData> OnRowSelected;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
FetchSimulationList().Forget();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// API에서 시뮬레이션 목록을 가져옵니다.
|
||||
/// </summary>
|
||||
public async UniTaskVoid FetchSimulationList()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await HttpRequester.RequestGet<SimulationListResponse>(
|
||||
$"{Constants.HTTP_DOMAIN}/simulation/projects", null, null, true);
|
||||
|
||||
if (response?.data?.rows == null) return;
|
||||
|
||||
allRows = response.data.rows;
|
||||
ApplyFilter();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"시뮬레이션 목록 조회 실패: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 검색 필터를 적용하여 목록을 갱신합니다.
|
||||
/// </summary>
|
||||
public void ApplyFilter()
|
||||
{
|
||||
string keyword = searchInput != null ? searchInput.text.Trim() : "";
|
||||
|
||||
List<SimulationRowData> filtered;
|
||||
if (string.IsNullOrEmpty(keyword))
|
||||
{
|
||||
filtered = allRows;
|
||||
}
|
||||
else
|
||||
{
|
||||
filtered = allRows.FindAll(row =>
|
||||
row.name != null && row.name.Contains(keyword, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
RenderRows(filtered);
|
||||
|
||||
if (dataCountText != null)
|
||||
{
|
||||
dataCountText.text = $"검색된 데이터 수: {filtered.Count} / {allRows.Count}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 행 UI를 생성/갱신합니다.
|
||||
/// </summary>
|
||||
private void RenderRows(List<SimulationRowData> rows)
|
||||
{
|
||||
// 기존 행 제거
|
||||
foreach (var view in rowViews)
|
||||
{
|
||||
Destroy(view.gameObject);
|
||||
}
|
||||
rowViews.Clear();
|
||||
selectedRow = null;
|
||||
|
||||
// 새로운 행 생성
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var go = Instantiate(rowPrefab, listContainer);
|
||||
var rowView = go.GetComponent<SimulationListRowView>();
|
||||
if (rowView != null)
|
||||
{
|
||||
rowView.SetData(row);
|
||||
rowView.OnClicked += OnRowClicked;
|
||||
rowViews.Add(rowView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRowClicked(SimulationListRowView rowView)
|
||||
{
|
||||
// 기존 선택 해제
|
||||
foreach (var view in rowViews)
|
||||
{
|
||||
view.SetSelected(false);
|
||||
}
|
||||
|
||||
// 새 선택
|
||||
rowView.SetSelected(true);
|
||||
selectedRow = rowView.Data;
|
||||
OnRowSelected?.Invoke(selectedRow);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 선택된 시뮬레이션 데이터를 반환합니다.
|
||||
/// </summary>
|
||||
public SimulationRowData GetSelectedRow()
|
||||
{
|
||||
return selectedRow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 검색 InputField의 OnValueChanged에 연결할 수 있는 public 메서드
|
||||
/// </summary>
|
||||
public void OnSearchValueChanged(string value)
|
||||
{
|
||||
ApplyFilter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 새로고침 버튼에 연결할 수 있는 public 메서드
|
||||
/// </summary>
|
||||
public void Refresh()
|
||||
{
|
||||
FetchSimulationList().Forget();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
foreach (var view in rowViews)
|
||||
{
|
||||
if (view != null)
|
||||
view.OnClicked -= OnRowClicked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9f067e05daf4a544bac2affe7a41a36
|
||||
Reference in New Issue
Block a user