using System; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using UnityEngine.XR.ARSubsystems; public enum PopupState { None, ConfirmAddPoint, ConfirmModifyPoint, MoveOrDelete, ConfirmDelete } public class ProgramPresenter { private ProgramModel model; private IProgramView view; private TCPView tcpView; private RobotController controlledRobot; private string _programId; private bool lastKnownMotorState = false; private IInteractionView interactionView; private IPointManagerView pointManagerView; private IPathLineView pathLineView; private IPopupView popupView; private PopupState currentPopupState = PopupState.None; private RobotData pendingPointData; // ÆË¾÷â¿¡ ´ëÇÑ ÀÀ´äÀ» ±â´Ù¸®´Â Àӽà µ¥ÀÌÅÍ private int activePointIndex = -1; // ÇöÀç ¼öÁ¤/»èÁ¦ ÁßÀÎ Æ÷ÀÎÆ®ÀÇ À妽º private bool IsDragging = false; public ProgramPresenter(ProgramModel model, IProgramView view, TCPView tcpView, IInteractionView interactionView, IPointManagerView pmView, IPopupView popView, IPathLineView pathLineView) { this.model = model; this.view = view; this.tcpView = tcpView; this.view.OnCreateProgramClicked += async (id) => await HandleCreateProgram(id); this.view.OnLoadProgramListRequested += HandleLoadProgramList; this.view.OnProgramSelectedToLoad += HandleProgramSelected; this.view.OnOpenProgramClicked += async () => await HandleOpenProgram(); this.view.OnSaveClicked += HandleSaveProgram; this.view.OnAddPointClicked += HandleAddPoint; this.tcpView.OnTCPupdateRequested += HandleTCPViewUpdate; //this.interactionView.OnRobotReleased += HandleRobotReleased; //this.interactionView.OnPointClicked += HandlePointClicked; //this.interactionView.OnPointDragStart += HandlePointDragStart; //this.interactionView.OnPointDragUpdate += HandlePointDragUpdate; //this.interactionView.OnPointDragEnd += HandlePointDragEnd; //this.popupView.OnPopupResponse += HandlePopupResponse; } public void RegisterControlledRobot(RobotController robot) { this.controlledRobot = robot; this.controlledRobot.OnPoseUpdateRequest += HandlePoseViewUpdate; } public async Task UpdateMotorStateAsync() { try { bool currentState = await model.GetRobotMotorStateAsync(); if (currentState != lastKnownMotorState) { controlledRobot.SetMotorState(currentState); lastKnownMotorState = currentState; } } catch (Exception e) { Debug.LogWarning($"¸ðÅÍ »óÅ ¾÷µ¥ÀÌÆ® ½ÇÆÐ: {e.Message}"); } } public void OnApplicationStart() { if (controlledRobot != null) { Debug.Log("Á¦¾îÇÒ ·Îº¿ÀÌ µî·ÏµÇ¾ú½À´Ï´Ù."); } else { Debug.LogError("Á¦¾îÇÒ ·Îº¿ÀÌ µî·ÏµÇÁö ¾Ê¾Ò½À´Ï´Ù"); } } private async Task HandleCreateProgram(string programId) { if (await model.CreateNewProgram(programId)) { view.DisplayProgram(programId); view.HideProgramSelectPanel(); OnApplicationStart(); } else { view.ShowMessage($"Error: Program ID '{programId}.job' already exists or is invalid."); } } private void HandleLoadProgramList() { var programIds = model.GetAllProgramIds(); view.ShowProgramList(programIds); } private void HandleProgramSelected(string programId) { _programId = programId; } private async Task HandleOpenProgram() { if(_programId != null && await model.LoadProgram(_programId)) { view.DisplayProgram(_programId); view.HideProgramSelectPanel(); view.HideProgramList(); OnApplicationStart(); _programId = null; } } private void HandleSaveProgram() { //model.SaveCurrentProgram(); } private void HandleAddPoint() { //// ½ÇÁ¦·Î´Â UI»óÀÇ ÁÂÇ¥³ª ·Îº¿ ¿£µåÆ÷ÀÎÆ® ÁÂÇ¥¸¦ ¹Þ¾Æ¿Í¾ß ÇÔ //// ¿©±â¼­´Â ¿¹½Ã·Î ·£´ý ÁÂÇ¥¸¦ »ç¿ë //Vector3 newPoint = new Vector3(Random.Range(-1f, 1f), Random.Range(0f, 1f), Random.Range(-1f, 1f)); //model.AddPointToCurrentProgram(newPoint); //view.DisplayProgram(model.CurrentProgram); } private void HandleTCPViewUpdate() { if (model.IsNewDataAvailable()) { RobotData data = model.GetLatestRobotData(); tcpView.SetCoordinates(data); } } // --- ½Ç½Ã°£ µ¿±âÈ­ --- private void HandlePoseViewUpdate() { RobotData data = model.GetLatestRobotData(); controlledRobot.SetRobotPosition(data); // 3D °¡»ó ·Îº¿ ¸ðµ¨ À§Ä¡ ¾÷µ¥ÀÌÆ® } // --- »õ Æ÷ÀÎÆ® Ãß°¡ --- private void HandleRobotReleased(RobotData pose) { pendingPointData = pose; // 1. Àӽà ÀúÀå currentPopupState = PopupState.ConfirmAddPoint; // 2. »óÅ ¼³Á¤ popupView.ShowConfirmPopup("À§Ä¡ È®Á¤", "ÀÌ À§Ä¡¸¦ »õ Æ÷ÀÎÆ®·Î ÀúÀåÇϽðڽÀ´Ï±î?"); // 3. ÆË¾÷ ¿äû } // --- Æ÷ÀÎÆ® Ŭ¸¯ --- private void HandlePointClicked(int index) { activePointIndex = index; // À妽º ÀúÀå currentPopupState = PopupState.MoveOrDelete; // »óÅ ¼³Á¤ popupView.ShowOptionPopup("Æ÷ÀÎÆ® ÀÛ¾÷", "¹«¾ùÀ» ÇϽðڽÀ´Ï±î?", "¿©±â·Î À̵¿", "»èÁ¦"); // ÆË¾÷ ¿äû } // --- Æ÷ÀÎÆ® µå·¡±× --- private RobotData originalDragPose; // Ãë¼Ò ½Ã µ¹¾Æ°¥ ¿øº» À§Ä¡ private void HandlePointDragStart(int index) { IsDragging = true; activePointIndex = index; originalDragPose = model.CurrentProgram.GetStepPose(index); //interactionView.ShowDragArrow(GetPositionFromPose(originalDragPose)); interactionView.ShowGhostRobot(originalDragPose); } private async void HandlePointDragUpdate(int index, Vector3 newWorldPos) { if (!IsDragging) return; //RobotData newPose = ConvertVectorToRobotData(newWorldPos); // °í½ºÆ® ·Îº¿, Æ÷ÀÎÆ®, °æ·Î ½Ç½Ã°£ À̵¿ //interactionView.ShowGhostRobot(newPose); //pointManagerView.UpdatePointPosition(index, newPose); //pathLineView.DrawPath(GetFullPathOfProgramWithTempChange(index, newPose)); // Àӽà °æ·Î ±×¸®±â //await model.StreamPoseToRobotUdpAsync(newPose); } private void HandlePointDragEnd(int index) { //IsDragging = false; //interactionView.HideDragArrow(); //interactionView.HideGhostRobot(); //// (°¡»ó ·Îº¿ À§Ä¡ À̵¿ ·ÎÁ÷ - 5´Ü°è) //// robotController.SetRobotPosition(newPose); //pendingPointData = ConvertVectorToRobotData(GetLastDragPosition()); // Àӽà ÀúÀå //currentPopupState = PopupState.ConfirmModifyPoint; // »óÅ ¼³Á¤ //popupView.ShowConfirmPopup("À§Ä¡ ¼öÁ¤", "ÀÌ À§Ä¡·Î Æ÷ÀÎÆ®¸¦ ¼öÁ¤ÇϽðڽÀ´Ï±î?"); // ÆË¾÷ ¿äû } // --- ÆË¾÷ ÀÀ´ä ÅëÇÕ Çڵ鷯 --- private async void HandlePopupResponse(PopupResponse response) { popupView.HidePopup(); switch (currentPopupState) { case PopupState.ConfirmAddPoint: if (response == PopupResponse.Confirm) // È®Á¤ { await model.SavePointToProgramAsync(pendingPointData); RedrawSceneFromModel(); // ºä °»½Å } break; // µå·¡±× È®Á¤/Ãë¼Ò case PopupState.ConfirmModifyPoint: if (response == PopupResponse.Confirm) // È®Á¤ { // ÃÖÁ¾ À§Ä¡¸¦ ¼­¹ö¿¡ ÀúÀå // µå·¡±×°¡ ³¡³µÀ¸´Ï ÀÌ À§Ä¡¸¦ ÇÁ·Î±×·¥¿¡ ÀúÀå await model.SavePointToProgramAsync(pendingPointData, activePointIndex); RedrawSceneFromModel(); } else // Ãë¼Ò { pointManagerView.UpdatePointPosition(activePointIndex, originalDragPose); // ¿øÀ§Ä¡ RedrawSceneFromModel(); // °æ·Î ¿øÀ§Ä¡ } break; // À̵¿/»èÁ¦ case PopupState.MoveOrDelete: if (response == PopupResponse.Option1) // ¿©±â·Î À̵¿ { RobotData targetPose = model.CurrentProgram.GetStepPose(activePointIndex); //await model.StartMovement(targetPose); } else if (response == PopupResponse.Option2) // »èÁ¦ { currentPopupState = PopupState.ConfirmDelete; popupView.ShowConfirmPopup("»èÁ¦ È®ÀÎ", "Á¤¸»·Î ÀÌ Æ÷ÀÎÆ®¸¦ »èÁ¦ÇϽðڽÀ´Ï±î?"); } break; // ÃÖÁ¾ »èÁ¦ case PopupState.ConfirmDelete: if (response == PopupResponse.Confirm) { await model.DeletePointFromProgramAsync(activePointIndex); RedrawSceneFromModel(); } break; } // ¸ðµç ÀÛ¾÷ ÈÄ »óÅ ÃʱâÈ­ currentPopupState = PopupState.None; activePointIndex = -1; } // ModelÀÇ ÇöÀç »óŸ¦ ÀÐ¾î ¸ðµç View(Æ÷ÀÎÆ®, °æ·Î)¸¦ »õ·Î °íħ private void RedrawSceneFromModel() { //if (model.CurrentProgram == null) return; //// (RobotProgram.Steps (List)¸¦ List·Î º¯È¯ÇÏ´Â ·ÎÁ÷) //List poses = model.CurrentProgram.GetAllStepPoses(); //pointManagerView.RedrawPoints(poses); // Æ÷ÀÎÆ® ´Ù½Ã ±×¸² //pathLineView.DrawPath(poses); // °æ·Î ´Ù½Ã ±×¸² } private void Destroy() { this.view.OnCreateProgramClicked -= async (id) => await HandleCreateProgram(id); this.view.OnLoadProgramListRequested -= HandleLoadProgramList; this.view.OnProgramSelectedToLoad -= HandleProgramSelected; this.view.OnOpenProgramClicked -= async () => await HandleOpenProgram(); this.view.OnSaveClicked -= HandleSaveProgram; this.view.OnAddPointClicked -= HandleAddPoint; this.tcpView.OnTCPupdateRequested -= HandleTCPViewUpdate; } }