[Fix] Refactoring (Remove GameView) TEMP

This commit is contained in:
2026-06-07 00:18:30 +07:00
parent a9767c5301
commit 79a928ae52
34 changed files with 965 additions and 805 deletions
@@ -1,18 +1,12 @@
using Minesweeper.Config;
using Minesweeper.Core;
using Minesweeper.Presentation.Views;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minesweeper.Presentation.Factories
{
public sealed class CellViewFactory : ICellViewFactory
{
private const string ContentImagePath = "Content/Image";
private const string ContentLabelPath = "Content/Text (TMP)";
private const string ContentPath = "Content";
private readonly MinesweeperUiConfig uiConfig;
public CellViewFactory(MinesweeperUiConfig uiConfig)
@@ -23,22 +17,23 @@ namespace Minesweeper.Presentation.Factories
public CellView CreateCell(BoardCellData cell, Transform parent)
{
var prefab = uiConfig.CellButtonPrefab;
var go = prefab != null ? Object.Instantiate(prefab, parent) : CreateFallbackCell(parent);
if (prefab == null)
{
Debug.LogError("CellViewFactory failed: CellButtonPrefab is not assigned.");
return null;
}
var go = Object.Instantiate(prefab, parent);
go.name = BuildCellName(cell.X, cell.Y, cell.DisplayValue);
var view = go.GetComponent<CellView>();
if (view == null)
{
view = go.AddComponent<CellView>();
Debug.LogError($"CellViewFactory failed: '{prefab.name}' is missing CellView.");
Object.Destroy(go);
return null;
}
var button = go.GetComponent<Button>();
var backgroundImage = go.GetComponent<Image>();
var contentRoot = FindComponent<RectTransform>(go.transform, ContentPath);
var contentImage = FindComponent<Image>(go.transform, ContentImagePath);
var label = FindComponent<TMP_Text>(go.transform, ContentLabelPath);
view.Bind(button, backgroundImage, contentRoot, contentImage, label);
view.AutoBind();
view.Initialize(cell.X, cell.Y);
return view;
}
@@ -53,41 +48,5 @@ namespace Minesweeper.Presentation.Factories
return $"bt_{x}_{y}_{displayValue}";
}
private static T FindComponent<T>(Transform root, string path) where T : Component
{
var child = root.Find(path);
return child != null ? child.GetComponent<T>() : null;
}
private static GameObject CreateFallbackCell(Transform parent)
{
var go = new GameObject("Cell", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button));
go.transform.SetParent(parent, false);
var content = new GameObject("Content", typeof(RectTransform));
content.transform.SetParent(go.transform, false);
Stretch(content.GetComponent<RectTransform>());
var image = new GameObject("Image", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
image.transform.SetParent(content.transform, false);
Stretch(image.GetComponent<RectTransform>());
var text = new GameObject("Text (TMP)", typeof(RectTransform), typeof(CanvasRenderer), typeof(TextMeshProUGUI));
text.transform.SetParent(content.transform, false);
Stretch(text.GetComponent<RectTransform>());
var label = text.GetComponent<TextMeshProUGUI>();
label.alignment = TextAlignmentOptions.Center;
label.enableAutoSizing = true;
return go;
}
private static void Stretch(RectTransform rectTransform)
{
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.one;
rectTransform.offsetMin = Vector2.zero;
rectTransform.offsetMax = Vector2.zero;
}
}
}
@@ -1,8 +1,6 @@
using Minesweeper.Config;
using Minesweeper.Presentation.Views;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minesweeper.Presentation.Factories
{
@@ -12,10 +10,6 @@ namespace Minesweeper.Presentation.Factories
private const string BoardGridName = "BoardGrid";
private const string PausePanelName = "PausePanel";
private const string ResultPanelName = "ResultPanel";
private const string RestartButtonPath = "RestartButton";
private const string ContinueButtonPath = "ContinueButton";
private const string MainMenuButtonPath = "MainMenuButton";
private const string ResultTextPath = "ResultText";
public MinesweeperScreenRefs Spawn(Transform contentRoot, MinesweeperScreenCatalog catalog)
{
@@ -39,20 +33,20 @@ namespace Minesweeper.Presentation.Factories
var result = SpawnScreen(catalog.ResultPanelPrefab, contentRoot, ResultPanelName, 3);
var mainMenuView = RequireComponent<MainMenuView>(mainMenu.transform, MainMenuPanelName);
mainMenuView.BindRoot(mainMenu);
if (mainMenuView != null)
{
mainMenuView.BindRoot(mainMenu);
}
var boardView = RequireComponent<BoardView>(board.transform, BoardGridName);
var pauseView = RequireComponent<PauseView>(pause.transform, PausePanelName);
var resultView = RequireComponent<ResultView>(result.transform, ResultPanelName);
var refs = new MinesweeperScreenRefs(
mainMenuView,
RequireComponent<RectTransform>(board.transform, BoardGridName),
RequireComponent<GridLayoutGroup>(board.transform, BoardGridName),
pause,
RequireChildComponent<Button>(pause.transform, RestartButtonPath),
RequireChildComponent<Button>(pause.transform, ContinueButtonPath),
RequireChildComponent<Button>(pause.transform, MainMenuButtonPath),
result,
RequireChildComponent<Button>(result.transform, RestartButtonPath),
RequireChildComponent<Button>(result.transform, MainMenuButtonPath),
RequireChildComponent<TMP_Text>(result.transform, ResultTextPath));
boardView,
pauseView,
resultView);
mainMenu.SetActive(false);
board.SetActive(false);
@@ -92,24 +86,6 @@ namespace Minesweeper.Presentation.Factories
return component;
}
private static T RequireChildComponent<T>(Transform root, string path) where T : Component
{
var child = root.Find(path);
if (child == null)
{
Debug.LogError($"Minesweeper screen bootstrap failed: '{root.name}/{path}' was not found.");
return null;
}
var component = child.GetComponent<T>();
if (component == null)
{
Debug.LogError($"Minesweeper screen bootstrap failed: '{root.name}/{path}' is missing {typeof(T).Name}.");
}
return component;
}
private static void Stretch(RectTransform rectTransform)
{
if (rectTransform == null)
@@ -13,82 +13,57 @@ namespace Minesweeper.Presentation.Presenters
private readonly IGamePauseService pauseService;
private readonly IGameReadModel readModel;
private readonly IGameStateService gameStateService;
private readonly IGameTimerService timerService;
private readonly TopPanelPresenter topPanelPresenter;
private readonly IGameView view;
private readonly IBoardView boardView;
private readonly IPauseView pauseView;
private readonly IResultView resultView;
private bool boardBuilt;
public GamePresenter(IGameCommandDispatcher commandDispatcher, ICellViewFactory cellViewFactory, IGamePauseService pauseService, IGameReadModel readModel, IGameStateService gameStateService, IGameTimerService timerService, TopPanelPresenter topPanelPresenter, IGameView view = null)
public GamePresenter(IGameCommandDispatcher commandDispatcher, ICellViewFactory cellViewFactory, IGamePauseService pauseService, IGameReadModel readModel, IGameStateService gameStateService, TopPanelPresenter topPanelPresenter, IBoardView boardView, IPauseView pauseView, IResultView resultView)
{
this.commandDispatcher = commandDispatcher;
this.cellViewFactory = cellViewFactory;
this.pauseService = pauseService;
this.readModel = readModel;
this.gameStateService = gameStateService;
this.timerService = timerService;
this.topPanelPresenter = topPanelPresenter;
this.view = view;
this.boardView = boardView;
this.pauseView = pauseView;
this.resultView = resultView;
}
public void Initialize()
{
if (view != null)
{
view.RestartRequested += OnRestartRequested;
view.GoToMenuRequested += OnGoToMenuRequested;
view.PauseRequested += OnPauseRequested;
view.ResumeRequested += OnResumeRequested;
view.CellPressStarted += OnCellPressStarted;
view.CellPressEnded += OnCellPressEnded;
view.CellOpenRequested += OnCellOpenRequested;
view.CellFlagRequested += OnCellFlagRequested;
gameStateService.StateChanged += OnStateChanged;
pauseService.PauseChanged += OnPauseChanged;
timerService.TimeChanged += OnTimeChanged;
OnStateChanged(gameStateService.Current);
OnPauseChanged(pauseService.IsPaused);
OnTimeChanged(timerService.ElapsedSeconds);
}
boardView.CellPressStarted += OnCellPressStarted;
boardView.CellPressEnded += OnCellPressEnded;
boardView.PauseRequested += OnPauseRequested;
boardView.CellOpenRequested += OnCellOpenRequested;
boardView.CellFlagRequested += OnCellFlagRequested;
pauseView.RestartRequested += OnRestartRequested;
pauseView.ResumeRequested += OnResumeRequested;
pauseView.GoToMenuRequested += OnGoToMenuRequested;
resultView.RestartRequested += OnRestartRequested;
resultView.GoToMenuRequested += OnGoToMenuRequested;
gameStateService.StateChanged += OnStateChanged;
pauseService.PauseChanged += OnPauseChanged;
OnStateChanged(gameStateService.Current);
OnPauseChanged(pauseService.IsPaused);
}
public void Dispose()
{
if (view != null)
{
view.RestartRequested -= OnRestartRequested;
view.GoToMenuRequested -= OnGoToMenuRequested;
view.PauseRequested -= OnPauseRequested;
view.ResumeRequested -= OnResumeRequested;
view.CellPressStarted -= OnCellPressStarted;
view.CellPressEnded -= OnCellPressEnded;
view.CellOpenRequested -= OnCellOpenRequested;
view.CellFlagRequested -= OnCellFlagRequested;
gameStateService.StateChanged -= OnStateChanged;
pauseService.PauseChanged -= OnPauseChanged;
timerService.TimeChanged -= OnTimeChanged;
}
}
private void OnRestartRequested()
{
commandDispatcher.Dispatch(new RestartCommand());
RebuildBoard();
topPanelPresenter.RefreshCounters();
}
private void OnGoToMenuRequested()
{
commandDispatcher.Dispatch(new GoToMenuCommand());
}
private void OnPauseRequested()
{
commandDispatcher.Dispatch(new PauseCommand());
}
private void OnResumeRequested()
{
commandDispatcher.Dispatch(new ResumeCommand());
boardView.CellPressStarted -= OnCellPressStarted;
boardView.CellPressEnded -= OnCellPressEnded;
boardView.PauseRequested -= OnPauseRequested;
boardView.CellOpenRequested -= OnCellOpenRequested;
boardView.CellFlagRequested -= OnCellFlagRequested;
pauseView.RestartRequested -= OnRestartRequested;
pauseView.ResumeRequested -= OnResumeRequested;
pauseView.GoToMenuRequested -= OnGoToMenuRequested;
resultView.RestartRequested -= OnRestartRequested;
resultView.GoToMenuRequested -= OnGoToMenuRequested;
gameStateService.StateChanged -= OnStateChanged;
pauseService.PauseChanged -= OnPauseChanged;
}
private void OnCellOpenRequested(int x, int y)
@@ -123,22 +98,22 @@ namespace Minesweeper.Presentation.Presenters
if (state == GameState.FieldSelection)
{
boardBuilt = false;
view.HideGame();
view.HidePause();
view.HideResult();
boardView.Hide();
pauseView.Hide();
resultView.Hide();
return;
}
view.ShowGame();
boardView.Show();
if (state == GameState.Won || state == GameState.Lost)
{
view.HidePause();
view.ShowResult(state);
pauseView.Hide();
resultView.Show(state);
}
else
{
view.HideResult();
resultView.Hide();
}
if (!boardBuilt || state == GameState.Preparing)
@@ -157,26 +132,20 @@ namespace Minesweeper.Presentation.Presenters
{
if (isPaused && gameStateService.Current == GameState.Playing)
{
view.ShowPause();
pauseView.Show();
}
else
{
view.HidePause();
pauseView.Hide();
}
UpdateBoardInput();
}
private void OnTimeChanged(float seconds)
{
view.SetTimer(seconds);
}
private void RebuildBoard()
{
var cells = readModel.GetCells();
view.SetMineCount(readModel.MinesCount);
view.RebuildBoard(cells, readModel.Width, readModel.Height, cellViewFactory, IsFinalState());
boardView.Rebuild(cells, readModel.Width, readModel.Height, cellViewFactory, IsFinalState());
boardBuilt = true;
topPanelPresenter.RefreshCounters();
UpdateBoardInput();
@@ -184,7 +153,7 @@ namespace Minesweeper.Presentation.Presenters
private void RefreshBoard()
{
view.RefreshBoard(readModel.GetCells(), IsFinalState());
boardView.Refresh(readModel.GetCells(), IsFinalState());
}
private bool IsFinalState()
@@ -196,7 +165,29 @@ namespace Minesweeper.Presentation.Presenters
private void UpdateBoardInput()
{
var state = gameStateService.Current;
view.SetBoardInputEnabled(!pauseService.IsPaused && (state == GameState.Preparing || state == GameState.Playing));
boardView.SetInputEnabled(!pauseService.IsPaused && (state == GameState.Preparing || state == GameState.Playing));
}
private void OnRestartRequested()
{
commandDispatcher.Dispatch(new RestartCommand());
RebuildBoard();
topPanelPresenter.RefreshCounters();
}
private void OnGoToMenuRequested()
{
commandDispatcher.Dispatch(new GoToMenuCommand());
}
private void OnResumeRequested()
{
commandDispatcher.Dispatch(new ResumeCommand());
}
private void OnPauseRequested()
{
commandDispatcher.Dispatch(new PauseCommand());
}
}
}
@@ -3,13 +3,12 @@ using System.Collections.Generic;
using Minesweeper.Config;
using Minesweeper.Core;
using Minesweeper.Presentation.Factories;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minesweeper.Presentation.Views
{
public sealed class GameView : MonoBehaviour, IGameView
public sealed class BoardView : MonoBehaviour, IBoardView
{
private const float ResizeRefreshDelaySeconds = 0.5f;
private const float ResizeSizeEpsilon = 0.5f;
@@ -18,25 +17,14 @@ namespace Minesweeper.Presentation.Views
private const float ContentPaddingReferencePadding = 15f;
private const float MinimumContentPadding = 1f;
[SerializeField] private GameObject gameRoot;
[SerializeField] private GameObject pauseRoot;
[SerializeField] private GameObject resultRoot;
[SerializeField] private GameObject root;
[SerializeField] private RectTransform boardPanel;
[SerializeField] private GridLayoutGroup gridLayoutGroup;
[SerializeField] private Button pauseButton;
[SerializeField] private Button restartButton;
[SerializeField] private Button resumeButton;
[SerializeField] private Button mainMenuButton;
[SerializeField] private Button resultRestartButton;
[SerializeField] private Button resultMainMenuButton;
[SerializeField] private TMP_Text resultText;
[SerializeField] private TMP_Text timerText;
[SerializeField] private TMP_Text mineText;
[SerializeField] private MinesweeperUiConfig uiConfig;
private readonly Dictionary<int, CellView> cellsByCoordinate = new Dictionary<int, CellView>();
private IReadOnlyList<BoardCellData> currentCells;
private bool boardInputEnabled = true;
private bool inputEnabled = true;
private bool currentRevealUnflaggedMines;
private bool resizeRefreshPending;
private int currentBoardWidth;
@@ -46,101 +34,30 @@ namespace Minesweeper.Presentation.Views
private float resizeStableAt;
private Vector2 lastObservedLayoutSize;
public event Action RestartRequested;
public event Action GoToMenuRequested;
public event Action PauseRequested;
public event Action ResumeRequested;
private GameObject Root => root != null ? root : gameObject;
public event Action CellPressStarted;
public event Action CellPressEnded;
public event Action PauseRequested;
public event Action<int, int> CellOpenRequested;
public event Action<int, int> CellFlagRequested;
private void Awake()
{
if (gameRoot == null)
if (root == null)
{
gameRoot = gameObject;
root = gameObject;
}
}
private void OnEnable()
{
AddButtonListeners();
}
private void OnDisable()
{
RemoveButtonListeners();
if (boardPanel == null)
{
boardPanel = transform as RectTransform;
}
}
private void Update()
{
TrackBoardResize();
}
public void ShowGame()
{
gameRoot.SetActive(true);
SetBoardRootActive(true);
}
public void HideGame()
{
gameRoot.SetActive(true);
SetBoardRootActive(false);
}
public void ShowPause()
{
if (pauseRoot != null)
{
pauseRoot.SetActive(true);
}
}
public void HidePause()
{
if (pauseRoot != null)
{
pauseRoot.SetActive(false);
}
}
public void ShowResult(GameState state)
{
if (resultRoot != null)
{
resultRoot.SetActive(true);
}
if (resultText != null)
{
resultText.text = state == GameState.Won ? "YOU WIN" : "GAME OVER";
}
}
public void HideResult()
{
if (resultRoot != null)
{
resultRoot.SetActive(false);
}
}
public void SetTimer(float seconds)
{
if (timerText != null)
{
timerText.text = Mathf.FloorToInt(seconds).ToString("00000");
}
}
public void SetMineCount(int minesCount)
{
if (mineText != null)
{
mineText.text = minesCount.ToString("00000");
}
TrackResize();
}
public void BindConfig(MinesweeperUiConfig config)
@@ -148,34 +65,20 @@ namespace Minesweeper.Presentation.Views
uiConfig = config;
}
public void BindScreens(MinesweeperScreenRefs refs)
public void Show()
{
if (isActiveAndEnabled)
{
RemoveButtonListeners();
}
boardPanel = refs.BoardPanel;
gridLayoutGroup = refs.BoardGrid;
pauseRoot = refs.PauseRoot;
restartButton = refs.PauseRestartButton;
resumeButton = refs.PauseResumeButton;
mainMenuButton = refs.PauseMainMenuButton;
resultRoot = refs.ResultRoot;
resultRestartButton = refs.ResultRestartButton;
resultMainMenuButton = refs.ResultMainMenuButton;
resultText = refs.ResultText;
Root.SetActive(true);
ResetResizeTracking();
if (isActiveAndEnabled)
{
AddButtonListeners();
}
}
public void RebuildBoard(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines)
public void Hide()
{
ClearBoard();
Root.SetActive(false);
}
public void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines)
{
Clear();
currentBoardWidth = width;
currentBoardHeight = height;
currentCells = cells;
@@ -187,10 +90,10 @@ namespace Minesweeper.Presentation.Views
CreateCell(cells[i], cellViewFactory);
}
RefreshBoard(cells, revealUnflaggedMines);
Refresh(cells, revealUnflaggedMines);
}
public void RefreshBoard(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
{
currentCells = cells;
currentRevealUnflaggedMines = revealUnflaggedMines;
@@ -205,95 +108,16 @@ namespace Minesweeper.Presentation.Views
}
}
public void SetBoardInputEnabled(bool enabled)
public void SetInputEnabled(bool enabled)
{
boardInputEnabled = enabled;
inputEnabled = enabled;
foreach (var cell in cellsByCoordinate.Values)
{
cell.SetInputEnabled(enabled);
}
}
private void AddButtonListeners()
{
if (pauseButton != null)
{
pauseButton.onClick.AddListener(OnPauseClicked);
}
if (restartButton != null)
{
restartButton.onClick.AddListener(OnRestartClicked);
}
if (resumeButton != null)
{
resumeButton.onClick.AddListener(OnResumeClicked);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.AddListener(OnMainMenuClicked);
}
if (resultRestartButton != null)
{
resultRestartButton.onClick.AddListener(OnRestartClicked);
}
if (resultMainMenuButton != null)
{
resultMainMenuButton.onClick.AddListener(OnMainMenuClicked);
}
}
private void RemoveButtonListeners()
{
if (pauseButton != null)
{
pauseButton.onClick.RemoveListener(OnPauseClicked);
}
if (restartButton != null)
{
restartButton.onClick.RemoveListener(OnRestartClicked);
}
if (resumeButton != null)
{
resumeButton.onClick.RemoveListener(OnResumeClicked);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.RemoveListener(OnMainMenuClicked);
}
if (resultRestartButton != null)
{
resultRestartButton.onClick.RemoveListener(OnRestartClicked);
}
if (resultMainMenuButton != null)
{
resultMainMenuButton.onClick.RemoveListener(OnMainMenuClicked);
}
}
private void SetBoardRootActive(bool active)
{
if (boardPanel != null)
{
boardPanel.gameObject.SetActive(active);
}
if (active)
{
ResetResizeTracking();
}
}
private void TrackBoardResize()
private void TrackResize()
{
if (boardPanel == null || !boardPanel.gameObject.activeInHierarchy || currentCells == null || currentBoardWidth <= 0 || currentBoardHeight <= 0)
{
@@ -317,19 +141,19 @@ namespace Minesweeper.Presentation.Views
if (resizeRefreshPending && Time.unscaledTime >= resizeStableAt)
{
resizeRefreshPending = false;
RefreshBoardLayout();
RefreshLayout();
}
}
private void RefreshBoardLayout()
private void RefreshLayout()
{
ConfigureGrid(currentBoardWidth, currentBoardHeight);
RefreshBoard(currentCells, currentRevealUnflaggedMines);
Refresh(currentCells, currentRevealUnflaggedMines);
}
private void ConfigureGrid(int width, int height)
{
if (gridLayoutGroup == null || boardPanel == null)
if (gridLayoutGroup == null || boardPanel == null || uiConfig == null)
{
return;
}
@@ -358,11 +182,6 @@ namespace Minesweeper.Presentation.Views
lastObservedLayoutSize = layoutSize;
}
private static float CalculateContentPadding(float cellSize)
{
return Mathf.Max(MinimumContentPadding, cellSize * ContentPaddingReferencePadding / ContentPaddingReferenceCellSize);
}
private Vector2 GetLayoutSourceSize()
{
var parentRect = boardPanel.parent as RectTransform;
@@ -379,11 +198,6 @@ namespace Minesweeper.Presentation.Views
}
}
private static bool HasSizeChanged(Vector2 current, Vector2 previous)
{
return Mathf.Abs(current.x - previous.x) > ResizeSizeEpsilon || Mathf.Abs(current.y - previous.y) > ResizeSizeEpsilon;
}
private float CalculateCellSize(float panelWidth, float panelHeight, int width, int height)
{
var widthUnits = width + 2f * uiConfig.BoardPaddingRatio + Mathf.Max(0, width - 1) * uiConfig.GridSpacingRatio;
@@ -395,8 +209,18 @@ namespace Minesweeper.Presentation.Views
private void CreateCell(BoardCellData cell, ICellViewFactory cellViewFactory)
{
if (gridLayoutGroup == null)
{
return;
}
var view = cellViewFactory.CreateCell(cell, gridLayoutGroup.transform);
view.SetInputEnabled(boardInputEnabled);
if (view == null)
{
return;
}
view.SetInputEnabled(inputEnabled);
view.OpenRequested += OnCellOpenRequested;
view.FlagRequested += OnCellFlagRequested;
view.PressStarted += OnCellPressStarted;
@@ -404,7 +228,7 @@ namespace Minesweeper.Presentation.Views
cellsByCoordinate[ToKey(cell.X, cell.Y)] = view;
}
private void ClearBoard()
private void Clear()
{
foreach (var cell in cellsByCoordinate.Values)
{
@@ -455,19 +279,14 @@ namespace Minesweeper.Presentation.Views
PauseRequested?.Invoke();
}
private void OnRestartClicked()
private static float CalculateContentPadding(float cellSize)
{
RestartRequested?.Invoke();
return Mathf.Max(MinimumContentPadding, cellSize * ContentPaddingReferencePadding / ContentPaddingReferenceCellSize);
}
private void OnResumeClicked()
private static bool HasSizeChanged(Vector2 current, Vector2 previous)
{
ResumeRequested?.Invoke();
}
private void OnMainMenuClicked()
{
GoToMenuRequested?.Invoke();
return Mathf.Abs(current.x - previous.x) > ResizeSizeEpsilon || Mathf.Abs(current.y - previous.y) > ResizeSizeEpsilon;
}
private static int ToKey(int x, int y)
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8e5eb8dfe520e3b40af304e66728dcfb
@@ -10,10 +10,6 @@ namespace Minesweeper.Presentation.Views
{
public sealed class CellView : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
{
private const string ContentImagePath = "Content/Image";
private const string ContentLabelPath = "Content/Text (TMP)";
private const string ContentPath = "Content";
[SerializeField] private Button button;
[SerializeField] private Image backgroundImage;
[SerializeField] private RectTransform contentRoot;
@@ -39,46 +35,6 @@ namespace Minesweeper.Presentation.Views
this.label = label;
}
public void AutoBind()
{
if (button == null)
{
button = GetComponent<Button>();
}
if (backgroundImage == null)
{
backgroundImage = GetComponent<Image>();
}
if (contentRoot == null)
{
var contentTransform = transform.Find(ContentPath);
if (contentTransform != null)
{
contentRoot = contentTransform.GetComponent<RectTransform>();
}
}
if (contentImage == null)
{
var contentImageTransform = transform.Find(ContentImagePath);
if (contentImageTransform != null)
{
contentImage = contentImageTransform.GetComponent<Image>();
}
}
if (label == null)
{
var labelTransform = transform.Find(ContentLabelPath);
if (labelTransform != null)
{
label = labelTransform.GetComponent<TMP_Text>();
}
}
}
public void Initialize(int x, int y)
{
this.x = x;
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 1c906a10872edd04480e534703fc4fea
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using Minesweeper.Core;
using Minesweeper.Presentation.Factories;
namespace Minesweeper.Presentation.Views
{
public interface IBoardView : IView
{
event Action CellPressStarted;
event Action CellPressEnded;
event Action PauseRequested;
event Action<int, int> CellOpenRequested;
event Action<int, int> CellFlagRequested;
void Show();
void Hide();
void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines);
void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines);
void SetInputEnabled(bool enabled);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cfdc53be4df29994fa56373d71a3b43a
@@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using Minesweeper.Core;
using Minesweeper.Presentation.Factories;
namespace Minesweeper.Presentation.Views
{
public interface IGameView : IView
{
event Action RestartRequested;
event Action GoToMenuRequested;
event Action PauseRequested;
event Action ResumeRequested;
event Action CellPressStarted;
event Action CellPressEnded;
event Action<int, int> CellOpenRequested;
event Action<int, int> CellFlagRequested;
void ShowGame();
void HideGame();
void ShowPause();
void HidePause();
void ShowResult(GameState state);
void HideResult();
void SetMineCount(int minesCount);
void SetTimer(float seconds);
void RebuildBoard(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines);
void RefreshBoard(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines);
void SetBoardInputEnabled(bool enabled);
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: a8c5423ea37354a4e82b05aadfbf239f
@@ -0,0 +1,14 @@
using System;
namespace Minesweeper.Presentation.Views
{
public interface IPauseView : IView
{
event Action RestartRequested;
event Action ResumeRequested;
event Action GoToMenuRequested;
void Show();
void Hide();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 68d5d80ca9e50564b8616608563e8d73
@@ -0,0 +1,14 @@
using System;
using Minesweeper.Core;
namespace Minesweeper.Presentation.Views
{
public interface IResultView : IView
{
event Action RestartRequested;
event Action GoToMenuRequested;
void Show(GameState state);
void Hide();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ab5a37a62d4a8284ea45b6d2c835a4d1
@@ -1,47 +1,22 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minesweeper.Presentation.Views
{
public readonly struct MinesweeperScreenRefs
{
public MinesweeperScreenRefs(
MainMenuView mainMenuView,
RectTransform boardPanel,
GridLayoutGroup boardGrid,
GameObject pauseRoot,
Button pauseRestartButton,
Button pauseResumeButton,
Button pauseMainMenuButton,
GameObject resultRoot,
Button resultRestartButton,
Button resultMainMenuButton,
TMP_Text resultText)
BoardView boardView,
PauseView pauseView,
ResultView resultView)
{
MainMenuView = mainMenuView;
BoardPanel = boardPanel;
BoardGrid = boardGrid;
PauseRoot = pauseRoot;
PauseRestartButton = pauseRestartButton;
PauseResumeButton = pauseResumeButton;
PauseMainMenuButton = pauseMainMenuButton;
ResultRoot = resultRoot;
ResultRestartButton = resultRestartButton;
ResultMainMenuButton = resultMainMenuButton;
ResultText = resultText;
BoardView = boardView;
PauseView = pauseView;
ResultView = resultView;
}
public MainMenuView MainMenuView { get; }
public RectTransform BoardPanel { get; }
public GridLayoutGroup BoardGrid { get; }
public GameObject PauseRoot { get; }
public Button PauseRestartButton { get; }
public Button PauseResumeButton { get; }
public Button PauseMainMenuButton { get; }
public GameObject ResultRoot { get; }
public Button ResultRestartButton { get; }
public Button ResultMainMenuButton { get; }
public TMP_Text ResultText { get; }
public BoardView BoardView { get; }
public PauseView PauseView { get; }
public ResultView ResultView { get; }
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using Minesweeper.Core;
using Minesweeper.Presentation.Factories;
namespace Minesweeper.Presentation.Views
{
public sealed class NullBoardView : IBoardView
{
public event Action CellPressStarted { add { } remove { } }
public event Action CellPressEnded { add { } remove { } }
public event Action PauseRequested { add { } remove { } }
public event Action<int, int> CellOpenRequested { add { } remove { } }
public event Action<int, int> CellFlagRequested { add { } remove { } }
public void Show() { }
public void Hide() { }
public void Rebuild(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines) { }
public void Refresh(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines) { }
public void SetInputEnabled(bool enabled) { }
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0e79bb89d6efdcb4a8c7462de1871790
@@ -1,102 +0,0 @@
using System;
using System.Collections.Generic;
using Minesweeper.Core;
using Minesweeper.Presentation.Factories;
namespace Minesweeper.Presentation.Views
{
public sealed class NullGameView : IGameView
{
public event Action RestartRequested
{
add { }
remove { }
}
public event Action GoToMenuRequested
{
add { }
remove { }
}
public event Action PauseRequested
{
add { }
remove { }
}
public event Action ResumeRequested
{
add { }
remove { }
}
public event Action CellPressStarted
{
add { }
remove { }
}
public event Action CellPressEnded
{
add { }
remove { }
}
public event Action<int, int> CellOpenRequested
{
add { }
remove { }
}
public event Action<int, int> CellFlagRequested
{
add { }
remove { }
}
public void ShowGame()
{
}
public void HideGame()
{
}
public void ShowPause()
{
}
public void HidePause()
{
}
public void ShowResult(GameState state)
{
}
public void HideResult()
{
}
public void SetMineCount(int minesCount)
{
}
public void SetTimer(float seconds)
{
}
public void RebuildBoard(IReadOnlyList<BoardCellData> cells, int width, int height, ICellViewFactory cellViewFactory, bool revealUnflaggedMines)
{
}
public void RefreshBoard(IReadOnlyList<BoardCellData> cells, bool revealUnflaggedMines)
{
}
public void SetBoardInputEnabled(bool enabled)
{
}
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: c800a42df535f9347bea10f164fd2e15
@@ -0,0 +1,13 @@
using System;
namespace Minesweeper.Presentation.Views
{
public sealed class NullPauseView : IPauseView
{
public event Action RestartRequested { add { } remove { } }
public event Action ResumeRequested { add { } remove { } }
public event Action GoToMenuRequested { add { } remove { } }
public void Show() { }
public void Hide() { }
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a2128d569219f1240ba7bb7c146fa1fd
@@ -0,0 +1,13 @@
using System;
using Minesweeper.Core;
namespace Minesweeper.Presentation.Views
{
public sealed class NullResultView : IResultView
{
public event Action RestartRequested { add { } remove { } }
public event Action GoToMenuRequested { add { } remove { } }
public void Show(GameState state) { }
public void Hide() { }
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b1db865929a8fc24097435b51a80e818
@@ -0,0 +1,99 @@
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Minesweeper.Presentation.Views
{
public sealed class PauseView : MonoBehaviour, IPauseView
{
[SerializeField] private GameObject root;
[SerializeField] private Button restartButton;
[SerializeField] private Button resumeButton;
[SerializeField] private Button mainMenuButton;
public event Action RestartRequested;
public event Action ResumeRequested;
public event Action GoToMenuRequested;
private GameObject Root => root != null ? root : gameObject;
private void Awake()
{
if (root == null)
{
root = gameObject;
}
}
private void OnEnable()
{
AddListeners();
}
private void OnDisable()
{
RemoveListeners();
}
public void Show()
{
Root.SetActive(true);
}
public void Hide()
{
Root.SetActive(false);
}
private void AddListeners()
{
if (restartButton != null)
{
restartButton.onClick.AddListener(OnRestartClicked);
}
if (resumeButton != null)
{
resumeButton.onClick.AddListener(OnResumeClicked);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.AddListener(OnMainMenuClicked);
}
}
private void RemoveListeners()
{
if (restartButton != null)
{
restartButton.onClick.RemoveListener(OnRestartClicked);
}
if (resumeButton != null)
{
resumeButton.onClick.RemoveListener(OnResumeClicked);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.RemoveListener(OnMainMenuClicked);
}
}
private void OnRestartClicked()
{
RestartRequested?.Invoke();
}
private void OnResumeClicked()
{
ResumeRequested?.Invoke();
}
private void OnMainMenuClicked()
{
GoToMenuRequested?.Invoke();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 548c3a1ddca35cc4d823c260a88dcecf
@@ -0,0 +1,89 @@
using System;
using Minesweeper.Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace Minesweeper.Presentation.Views
{
public sealed class ResultView : MonoBehaviour, IResultView
{
[SerializeField] private GameObject root;
[SerializeField] private Button restartButton;
[SerializeField] private Button mainMenuButton;
[SerializeField] private TMP_Text resultText;
public event Action RestartRequested;
public event Action GoToMenuRequested;
private GameObject Root => root != null ? root : gameObject;
private void Awake()
{
if (root == null)
{
root = gameObject;
}
}
private void OnEnable()
{
AddListeners();
}
private void OnDisable()
{
RemoveListeners();
}
public void Show(GameState state)
{
Root.SetActive(true);
if (resultText != null)
{
resultText.text = state == GameState.Won ? "YOU WIN" : "GAME OVER";
}
}
public void Hide()
{
Root.SetActive(false);
}
private void AddListeners()
{
if (restartButton != null)
{
restartButton.onClick.AddListener(OnRestartClicked);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.AddListener(OnMainMenuClicked);
}
}
private void RemoveListeners()
{
if (restartButton != null)
{
restartButton.onClick.RemoveListener(OnRestartClicked);
}
if (mainMenuButton != null)
{
mainMenuButton.onClick.RemoveListener(OnMainMenuClicked);
}
}
private void OnRestartClicked()
{
RestartRequested?.Invoke();
}
private void OnMainMenuClicked()
{
GoToMenuRequested?.Invoke();
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b0b04ab8a2ef00b4e8d36a96e4f034d8