1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012 |
- using UnityEngine;
- using UnityEditor;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- namespace UnityVersionControl
- {
- /// <summary>
- /// Branch and Stash Management System
- /// Provides GitHub Desktop-style branch switching and stash management
- /// </summary>
- public class BranchAndStashManager : EditorWindow
- {
- #region Fields
- private Vector2 scrollPosition;
- private int selectedTab = 0;
- private readonly string[] tabNames = { "Branches", "Stashes" };
-
- // Branch data
- private readonly List<BranchInfo> branches = new List<BranchInfo>();
- private readonly List<StashInfo> stashes = new List<StashInfo>();
- private string currentBranch = "main";
- private string newBranchName = "";
- private bool showCreateBranchDialog = false;
- private bool showStashDialog = false;
- private string stashMessage = "";
-
- // UI state
- private string searchFilter = "";
- private bool showMergedBranches = false;
- private BranchInfo branchToDelete = null;
- private StashInfo stashToDelete = null;
-
- // Visual constants
- private static readonly Color backgroundColor = new Color(0.22f, 0.22f, 0.22f);
- private static readonly Color cardColor = new Color(0.28f, 0.28f, 0.28f);
- private static readonly Color accentColor = new Color(0.3f, 0.7f, 1f);
- private static readonly Color successColor = new Color(0.3f, 0.8f, 0.3f);
- private static readonly Color warningColor = new Color(1f, 0.8f, 0.2f);
- private static readonly Color errorColor = new Color(1f, 0.4f, 0.4f);
- private static readonly Color currentBranchColor = new Color(0.2f, 0.8f, 0.2f);
- private static readonly Color remoteBranchColor = new Color(0.6f, 0.6f, 1f);
-
- // Caches
- private readonly Dictionary<string, Texture2D> textureCache = new Dictionary<string, Texture2D>();
- #endregion
- #region Unity Lifecycle
- [MenuItem("Window/Version Control/Branch & Stash Manager", false, 2)]
- public static void ShowWindow()
- {
- var window = GetWindow<BranchAndStashManager>();
- window.titleContent = new GUIContent("Branches & Stashes");
- window.minSize = new Vector2(400, 500);
- window.Initialize();
- }
- private void OnEnable()
- {
- Initialize();
- }
- private void OnDisable()
- {
- CleanupTextures();
- }
- private void OnGUI()
- {
- DrawBackground();
- DrawHeader();
- DrawTabs();
- EditorGUILayout.Space(8);
-
- switch (selectedTab)
- {
- case 0: DrawBranchesTab(); break;
- case 1: DrawStashesTab(); break;
- }
-
- DrawDialogs();
- }
- #endregion
- #region Initialization
- private void Initialize()
- {
- LoadMockBranches();
- LoadMockStashes();
- }
- private void LoadMockBranches()
- {
- branches.Clear();
-
- // Current branch
- branches.Add(new BranchInfo
- {
- name = "main",
- isRemote = false,
- isCurrent = true,
- lastCommitMessage = "Initial commit",
- lastCommitAuthor = "Developer",
- lastCommitDate = DateTime.Now.AddDays(-1),
- commitHash = "a1b2c3d",
- aheadCount = 0,
- behindCount = 0
- });
-
- // Local branches
- branches.Add(new BranchInfo
- {
- name = "feature/player-movement",
- isRemote = false,
- isCurrent = false,
- lastCommitMessage = "Add player jump mechanics",
- lastCommitAuthor = "John Doe",
- lastCommitDate = DateTime.Now.AddHours(-3),
- commitHash = "b2c3d4e",
- aheadCount = 2,
- behindCount = 0
- });
-
- branches.Add(new BranchInfo
- {
- name = "bugfix/ui-scaling",
- isRemote = false,
- isCurrent = false,
- lastCommitMessage = "Fix UI scaling on different resolutions",
- lastCommitAuthor = "Jane Smith",
- lastCommitDate = DateTime.Now.AddHours(-5),
- commitHash = "c3d4e5f",
- aheadCount = 1,
- behindCount = 1
- });
-
- // Remote branches
- branches.Add(new BranchInfo
- {
- name = "origin/feature/audio-system",
- isRemote = true,
- isCurrent = false,
- lastCommitMessage = "Implement 3D spatial audio",
- lastCommitAuthor = "Bob Johnson",
- lastCommitDate = DateTime.Now.AddHours(-8),
- commitHash = "d4e5f6g",
- aheadCount = 0,
- behindCount = 3
- });
-
- branches.Add(new BranchInfo
- {
- name = "origin/feature/multiplayer",
- isRemote = true,
- isCurrent = false,
- lastCommitMessage = "Add network synchronization",
- lastCommitAuthor = "Alice Brown",
- lastCommitDate = DateTime.Now.AddDays(-2),
- commitHash = "e5f6g7h",
- aheadCount = 0,
- behindCount = 5
- });
- }
- private void LoadMockStashes()
- {
- stashes.Clear();
-
- stashes.Add(new StashInfo
- {
- id = "stash@{0}",
- message = "WIP: Player controller improvements",
- branchName = "feature/player-movement",
- author = "Developer",
- date = DateTime.Now.AddMinutes(-30),
- changedFiles = new List<string>
- {
- "Assets/Scripts/PlayerController.cs",
- "Assets/Scripts/InputManager.cs",
- "Assets/Prefabs/Player.prefab"
- }
- });
-
- stashes.Add(new StashInfo
- {
- id = "stash@{1}",
- message = "Experimental UI changes",
- branchName = "main",
- author = "Developer",
- date = DateTime.Now.AddHours(-2),
- changedFiles = new List<string>
- {
- "Assets/UI/MainMenu.prefab",
- "Assets/Materials/UI_Button.mat"
- }
- });
-
- stashes.Add(new StashInfo
- {
- id = "stash@{2}",
- message = "Audio volume adjustments",
- branchName = "feature/audio-system",
- author = "Developer",
- date = DateTime.Now.AddDays(-1),
- changedFiles = new List<string>
- {
- "Assets/Audio/AudioMixer.mixer",
- "Assets/Scripts/AudioManager.cs"
- }
- });
- }
- private void CleanupTextures()
- {
- foreach (var texture in textureCache.Values)
- {
- if (texture != null) DestroyImmediate(texture);
- }
- textureCache.Clear();
- }
- #endregion
- #region GUI Drawing
- private void DrawBackground()
- {
- var rect = new Rect(0, 0, position.width, position.height);
- EditorGUI.DrawRect(rect, backgroundColor);
- }
- private void DrawHeader()
- {
- DrawCard(() =>
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- // Current branch indicator
- var currentBranchRect = GUILayoutUtility.GetRect(20, 20);
- var branchTexture = CreateRoundedTexture(currentBranchColor, 20, 10);
- GUI.DrawTexture(currentBranchRect, branchTexture);
-
- var branchIconStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
- branchIconStyle.normal.textColor = Color.white;
- branchIconStyle.fontSize = 10;
- branchIconStyle.fontStyle = FontStyle.Bold;
- GUI.Label(currentBranchRect, "⎇", branchIconStyle);
-
- GUILayout.Space(8);
-
- using (new EditorGUILayout.VerticalScope())
- {
- var titleStyle = new GUIStyle(EditorStyles.boldLabel);
- titleStyle.fontSize = 14;
- titleStyle.normal.textColor = Color.white;
- EditorGUILayout.LabelField($"Current Branch: {currentBranch}", titleStyle);
-
- var currentBranchInfo = branches.FirstOrDefault(b => b.isCurrent);
- if (currentBranchInfo != null)
- {
- var subtitleStyle = new GUIStyle(EditorStyles.label);
- subtitleStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
- subtitleStyle.fontSize = 11;
-
- var statusText = "";
- if (currentBranchInfo.aheadCount > 0)
- statusText += $"↑{currentBranchInfo.aheadCount} ";
- if (currentBranchInfo.behindCount > 0)
- statusText += $"↓{currentBranchInfo.behindCount} ";
- if (string.IsNullOrEmpty(statusText))
- statusText = "Up to date";
-
- EditorGUILayout.LabelField(statusText.Trim(), subtitleStyle);
- }
- }
-
- GUILayout.FlexibleSpace();
-
- // Quick actions
- var createBranchStyle = new GUIStyle(GUI.skin.button);
- createBranchStyle.normal.textColor = successColor;
- createBranchStyle.fixedHeight = 28;
-
- if (GUILayout.Button("+ NEW BRANCH", createBranchStyle, GUILayout.Width(100)))
- ShowCreateBranchDialog();
-
- GUILayout.Space(4);
-
- var stashStyle = new GUIStyle(GUI.skin.button);
- stashStyle.normal.textColor = warningColor;
- stashStyle.fixedHeight = 28;
-
- if (GUILayout.Button("📦 STASH", stashStyle, GUILayout.Width(80)))
- ShowStashDialog();
- }
- }, 12);
- }
- private void DrawTabs()
- {
- EditorGUILayout.Space(8);
-
- using (new EditorGUILayout.HorizontalScope())
- {
- for (int i = 0; i < tabNames.Length; i++)
- {
- var isSelected = selectedTab == i;
- var buttonStyle = new GUIStyle(GUI.skin.button);
-
- if (isSelected)
- {
- buttonStyle.normal.background = Texture2D.whiteTexture;
- buttonStyle.normal.textColor = backgroundColor;
- buttonStyle.fontStyle = FontStyle.Bold;
- }
- else
- {
- buttonStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
- }
-
- buttonStyle.fixedHeight = 32;
-
- var tabLabel = tabNames[i];
- if (i == 0) tabLabel += $" ({branches.Count})";
- if (i == 1) tabLabel += $" ({stashes.Count})";
-
- if (GUILayout.Button(tabLabel, buttonStyle))
- selectedTab = i;
- }
- }
- }
- private void DrawBranchesTab()
- {
- EditorGUILayout.Space(8);
-
- DrawBranchFilters();
- DrawBranchList();
- }
- private void DrawBranchFilters()
- {
- DrawCard(() =>
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- EditorGUILayout.LabelField("Search:", GUILayout.Width(50));
- searchFilter = EditorGUILayout.TextField(searchFilter);
-
- GUILayout.Space(8);
-
- var oldShowMerged = showMergedBranches;
- showMergedBranches = EditorGUILayout.Toggle("Show merged", showMergedBranches);
-
- if (oldShowMerged != showMergedBranches)
- Repaint();
- }
- }, 8);
- }
- private void DrawBranchList()
- {
- EditorGUILayout.Space(8);
-
- var filteredBranches = branches.Where(b =>
- string.IsNullOrEmpty(searchFilter) ||
- b.name.ToLower().Contains(searchFilter.ToLower())
- ).ToList();
-
- using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPosition))
- {
- scrollPosition = scrollView.scrollPosition;
-
- // Group branches by type
- var localBranches = filteredBranches.Where(b => !b.isRemote).ToList();
- var remoteBranches = filteredBranches.Where(b => b.isRemote).ToList();
-
- if (localBranches.Count > 0)
- {
- DrawBranchSection("Local Branches", localBranches);
- }
-
- if (remoteBranches.Count > 0)
- {
- EditorGUILayout.Space(12);
- DrawBranchSection("Remote Branches", remoteBranches);
- }
- }
- }
- private void DrawBranchSection(string title, List<BranchInfo> sectionBranches)
- {
- DrawCard(() =>
- {
- var sectionStyle = new GUIStyle(EditorStyles.boldLabel);
- sectionStyle.fontSize = 12;
- sectionStyle.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
- EditorGUILayout.LabelField(title, sectionStyle);
-
- EditorGUILayout.Space(8);
-
- foreach (var branch in sectionBranches)
- {
- DrawBranchItem(branch);
- if (branch != sectionBranches.Last())
- DrawSeparator(1f, 4f);
- }
- }, 12);
- }
- private void DrawBranchItem(BranchInfo branch)
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- // Branch icon and name
- var iconSize = 24;
- var iconRect = GUILayoutUtility.GetRect(iconSize, iconSize);
-
- Color iconColor;
- string iconText;
-
- if (branch.isCurrent)
- {
- iconColor = currentBranchColor;
- iconText = "●";
- }
- else if (branch.isRemote)
- {
- iconColor = remoteBranchColor;
- iconText = "⊗";
- }
- else
- {
- iconColor = accentColor;
- iconText = "⎇";
- }
-
- var iconTexture = CreateRoundedTexture(iconColor, iconSize, iconSize / 2);
- GUI.DrawTexture(iconRect, iconTexture);
-
- var iconStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
- iconStyle.normal.textColor = Color.white;
- iconStyle.fontSize = 10;
- iconStyle.fontStyle = FontStyle.Bold;
- GUI.Label(iconRect, iconText, iconStyle);
-
- GUILayout.Space(8);
-
- // Branch info
- using (new EditorGUILayout.VerticalScope())
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- var nameStyle = new GUIStyle(EditorStyles.boldLabel);
- nameStyle.fontSize = 13;
- nameStyle.normal.textColor = branch.isCurrent ? currentBranchColor : Color.white;
- EditorGUILayout.LabelField(branch.name, nameStyle);
-
- GUILayout.FlexibleSpace();
-
- // Ahead/behind indicators
- if (branch.aheadCount > 0)
- {
- DrawCommitCountBadge($"↑{branch.aheadCount}", successColor);
- GUILayout.Space(4);
- }
- if (branch.behindCount > 0)
- {
- DrawCommitCountBadge($"↓{branch.behindCount}", warningColor);
- GUILayout.Space(4);
- }
- }
-
- var infoStyle = new GUIStyle(EditorStyles.label);
- infoStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f);
- infoStyle.fontSize = 10;
-
- var infoText = $"{branch.lastCommitMessage} • {branch.lastCommitAuthor} • {FormatDate(branch.lastCommitDate)}";
- EditorGUILayout.LabelField(infoText, infoStyle);
- }
-
- GUILayout.FlexibleSpace();
-
- // Actions
- DrawBranchActions(branch);
- }
- }
- private void DrawBranchActions(BranchInfo branch)
- {
- using (new EditorGUILayout.VerticalScope(GUILayout.Width(100)))
- {
- if (!branch.isCurrent)
- {
- var checkoutStyle = new GUIStyle(GUI.skin.button);
- checkoutStyle.normal.textColor = accentColor;
- checkoutStyle.fixedHeight = 22;
-
- if (GUILayout.Button("CHECKOUT", checkoutStyle))
- CheckoutBranch(branch);
- }
-
- if (!branch.isCurrent && !branch.isRemote)
- {
- var deleteStyle = new GUIStyle(GUI.skin.button);
- deleteStyle.normal.textColor = errorColor;
- deleteStyle.fixedHeight = 22;
-
- if (GUILayout.Button("DELETE", deleteStyle))
- branchToDelete = branch;
- }
- }
- }
- private void DrawStashesTab()
- {
- EditorGUILayout.Space(8);
-
- if (stashes.Count == 0)
- {
- DrawEmptyStashState();
- return;
- }
-
- using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPosition))
- {
- scrollPosition = scrollView.scrollPosition;
-
- DrawCard(() =>
- {
- foreach (var stash in stashes)
- {
- DrawStashItem(stash);
- if (stash != stashes.Last())
- DrawSeparator(1f, 8f);
- }
- }, 12);
- }
- }
- private void DrawStashItem(StashInfo stash)
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- // Stash icon
- var iconSize = 32;
- var iconRect = GUILayoutUtility.GetRect(iconSize, iconSize);
- var iconTexture = CreateRoundedTexture(warningColor, iconSize, 6);
- GUI.DrawTexture(iconRect, iconTexture);
-
- var iconStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
- iconStyle.normal.textColor = Color.white;
- iconStyle.fontSize = 14;
- iconStyle.fontStyle = FontStyle.Bold;
- GUI.Label(iconRect, "📦", iconStyle);
-
- GUILayout.Space(12);
-
- // Stash info
- using (new EditorGUILayout.VerticalScope())
- {
- var messageStyle = new GUIStyle(EditorStyles.boldLabel);
- messageStyle.fontSize = 13;
- messageStyle.normal.textColor = Color.white;
- EditorGUILayout.LabelField(stash.message, messageStyle);
-
- var detailStyle = new GUIStyle(EditorStyles.label);
- detailStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f);
- detailStyle.fontSize = 10;
-
- EditorGUILayout.LabelField($"Branch: {stash.branchName} • {stash.author} • {FormatDate(stash.date)}", detailStyle);
-
- // Changed files
- var filesText = $"{stash.changedFiles.Count} changed file{(stash.changedFiles.Count != 1 ? "s" : "")}";
- EditorGUILayout.LabelField(filesText, detailStyle);
- }
-
- GUILayout.FlexibleSpace();
-
- // Actions
- using (new EditorGUILayout.VerticalScope(GUILayout.Width(80)))
- {
- var applyStyle = new GUIStyle(GUI.skin.button);
- applyStyle.normal.textColor = successColor;
- applyStyle.fixedHeight = 22;
-
- if (GUILayout.Button("APPLY", applyStyle))
- ApplyStash(stash);
-
- var deleteStyle = new GUIStyle(GUI.skin.button);
- deleteStyle.normal.textColor = errorColor;
- deleteStyle.fixedHeight = 22;
-
- if (GUILayout.Button("DELETE", deleteStyle))
- stashToDelete = stash;
- }
- }
- }
- private void DrawEmptyStashState()
- {
- DrawCard(() =>
- {
- var iconRect = GUILayoutUtility.GetRect(48, 48);
- var emptyTexture = CreateRoundedTexture(new Color(0.5f, 0.5f, 0.5f, 0.3f), 48, 12);
- GUI.DrawTexture(iconRect, emptyTexture);
-
- var iconStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);
- iconStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f);
- iconStyle.fontSize = 20;
- GUI.Label(iconRect, "📦", iconStyle);
-
- EditorGUILayout.Space(8);
-
- var titleStyle = new GUIStyle(EditorStyles.boldLabel);
- titleStyle.alignment = TextAnchor.MiddleCenter;
- titleStyle.normal.textColor = new Color(0.7f, 0.7f, 0.7f);
- EditorGUILayout.LabelField("No Stashes", titleStyle);
-
- var subtitleStyle = new GUIStyle(EditorStyles.label);
- subtitleStyle.alignment = TextAnchor.MiddleCenter;
- subtitleStyle.normal.textColor = new Color(0.6f, 0.6f, 0.6f);
- subtitleStyle.wordWrap = true;
- EditorGUILayout.LabelField("Stash your work-in-progress changes to switch branches safely.", subtitleStyle);
- }, 32);
- }
- private void DrawDialogs()
- {
- if (showCreateBranchDialog)
- DrawCreateBranchDialog();
-
- if (showStashDialog)
- DrawStashDialog();
-
- if (branchToDelete != null)
- DrawDeleteBranchDialog();
-
- if (stashToDelete != null)
- DrawDeleteStashDialog();
- }
- private void DrawCreateBranchDialog()
- {
- var dialogRect = new Rect(
- (position.width - 300) * 0.5f,
- (position.height - 150) * 0.5f,
- 300, 150
- );
-
- EditorGUI.DrawRect(dialogRect, new Color(0, 0, 0, 0.7f));
-
- GUILayout.BeginArea(dialogRect);
- DrawCard(() =>
- {
- EditorGUILayout.LabelField("Create New Branch", EditorStyles.boldLabel);
- EditorGUILayout.Space(8);
-
- EditorGUILayout.LabelField("Branch name:");
- newBranchName = EditorGUILayout.TextField(newBranchName);
-
- EditorGUILayout.Space(12);
-
- using (new EditorGUILayout.HorizontalScope())
- {
- if (GUILayout.Button("Create"))
- {
- CreateBranch(newBranchName);
- showCreateBranchDialog = false;
- newBranchName = "";
- }
-
- if (GUILayout.Button("Cancel"))
- {
- showCreateBranchDialog = false;
- newBranchName = "";
- }
- }
- }, 12);
- GUILayout.EndArea();
- }
- private void DrawStashDialog()
- {
- var dialogRect = new Rect(
- (position.width - 350) * 0.5f,
- (position.height - 180) * 0.5f,
- 350, 180
- );
-
- EditorGUI.DrawRect(dialogRect, new Color(0, 0, 0, 0.7f));
-
- GUILayout.BeginArea(dialogRect);
- DrawCard(() =>
- {
- EditorGUILayout.LabelField("Create Stash", EditorStyles.boldLabel);
- EditorGUILayout.Space(8);
-
- EditorGUILayout.LabelField("Stash message:");
- stashMessage = EditorGUILayout.TextArea(stashMessage, GUILayout.Height(50));
-
- EditorGUILayout.Space(12);
-
- using (new EditorGUILayout.HorizontalScope())
- {
- if (GUILayout.Button("Create Stash"))
- {
- CreateStash(stashMessage);
- showStashDialog = false;
- stashMessage = "";
- }
-
- if (GUILayout.Button("Cancel"))
- {
- showStashDialog = false;
- stashMessage = "";
- }
- }
- }, 12);
- GUILayout.EndArea();
- }
- private void DrawDeleteBranchDialog()
- {
- if (EditorUtility.DisplayDialog(
- "Delete Branch",
- $"Are you sure you want to delete branch '{branchToDelete.name}'?\n\nThis action cannot be undone.",
- "Delete",
- "Cancel"))
- {
- DeleteBranch(branchToDelete);
- }
-
- branchToDelete = null;
- }
- private void DrawDeleteStashDialog()
- {
- if (EditorUtility.DisplayDialog(
- "Delete Stash",
- $"Are you sure you want to delete stash '{stashToDelete.message}'?\n\nThis action cannot be undone.",
- "Delete",
- "Cancel"))
- {
- DeleteStash(stashToDelete);
- }
-
- stashToDelete = null;
- }
- #endregion
- #region Helper Methods
- private void DrawCard(System.Action content, int padding = 12)
- {
- var rect = EditorGUILayout.BeginVertical();
- EditorGUI.DrawRect(rect, cardColor);
-
- GUILayout.Space(padding);
- EditorGUILayout.BeginHorizontal();
- GUILayout.Space(padding);
- EditorGUILayout.BeginVertical();
-
- content?.Invoke();
-
- EditorGUILayout.EndVertical();
- GUILayout.Space(padding);
- EditorGUILayout.EndHorizontal();
- GUILayout.Space(padding);
-
- EditorGUILayout.EndVertical();
- }
- private void DrawSeparator(float thickness = 1f, float spacing = 8f)
- {
- EditorGUILayout.Space(spacing);
- var rect = EditorGUILayout.GetControlRect(false, thickness);
- EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 0.3f));
- EditorGUILayout.Space(spacing);
- }
- private void DrawCommitCountBadge(string text, Color color)
- {
- var badgeStyle = new GUIStyle(GUI.skin.box);
- badgeStyle.normal.textColor = Color.white;
- badgeStyle.normal.background = CreateRoundedTexture(color, 16, 8);
- badgeStyle.fontSize = 9;
- badgeStyle.padding = new RectOffset(6, 6, 2, 2);
- badgeStyle.margin = new RectOffset(0, 0, 0, 0);
-
- GUILayout.Label(text, badgeStyle);
- }
- private Texture2D CreateRoundedTexture(Color color, int size = 64, int cornerRadius = 8)
- {
- var key = $"{color}_{size}_{cornerRadius}";
- if (textureCache.TryGetValue(key, out var cachedTexture) && cachedTexture != null)
- return cachedTexture;
- var texture = new Texture2D(size, size);
- var pixels = new Color[size * size];
-
- for (int y = 0; y < size; y++)
- {
- for (int x = 0; x < size; x++)
- {
- float distanceToCorner = float.MaxValue;
-
- if (x < cornerRadius && y < cornerRadius)
- distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(cornerRadius, cornerRadius));
- else if (x >= size - cornerRadius && y < cornerRadius)
- distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(size - cornerRadius - 1, cornerRadius));
- else if (x < cornerRadius && y >= size - cornerRadius)
- distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(cornerRadius, size - cornerRadius - 1));
- else if (x >= size - cornerRadius && y >= size - cornerRadius)
- distanceToCorner = Vector2.Distance(new Vector2(x, y), new Vector2(size - cornerRadius - 1, size - cornerRadius - 1));
-
- pixels[y * size + x] = (distanceToCorner <= cornerRadius ||
- (x >= cornerRadius && x < size - cornerRadius) ||
- (y >= cornerRadius && y < size - cornerRadius)) ? color : Color.clear;
- }
- }
-
- texture.SetPixels(pixels);
- texture.Apply();
- textureCache[key] = texture;
- return texture;
- }
- private string FormatDate(DateTime date)
- {
- var diff = DateTime.Now - date;
-
- if (diff.TotalMinutes < 1) return "just now";
- if (diff.TotalMinutes < 60) return $"{(int)diff.TotalMinutes}m ago";
- if (diff.TotalHours < 24) return $"{(int)diff.TotalHours}h ago";
- if (diff.TotalDays < 7) return $"{(int)diff.TotalDays}d ago";
-
- return date.ToString("MMM dd");
- }
- private void ShowCreateBranchDialog()
- {
- showCreateBranchDialog = true;
- }
- private void ShowStashDialog()
- {
- showStashDialog = true;
- }
- #endregion
- #region Branch Operations
- private void CheckoutBranch(BranchInfo branch)
- {
- try
- {
- Debug.Log($"🔄 Checking out branch: {branch.name}");
-
- // Update current branch
- foreach (var b in branches)
- b.isCurrent = false;
- branch.isCurrent = true;
- currentBranch = branch.name;
-
- EditorUtility.DisplayDialog("Branch Checkout",
- $"Successfully checked out branch '{branch.name}'",
- "OK");
-
- Repaint();
- }
- catch (Exception ex)
- {
- EditorUtility.DisplayDialog("Checkout Failed",
- $"Failed to checkout branch: {ex.Message}",
- "OK");
- }
- }
- private void CreateBranch(string branchName)
- {
- if (string.IsNullOrWhiteSpace(branchName))
- {
- EditorUtility.DisplayDialog("Invalid Branch Name",
- "Branch name cannot be empty.",
- "OK");
- return;
- }
-
- if (branches.Any(b => b.name == branchName))
- {
- EditorUtility.DisplayDialog("Branch Exists",
- $"A branch named '{branchName}' already exists.",
- "OK");
- return;
- }
-
- var newBranch = new BranchInfo
- {
- name = branchName,
- isRemote = false,
- isCurrent = false,
- lastCommitMessage = "Branch created",
- lastCommitAuthor = "Developer",
- lastCommitDate = DateTime.Now,
- commitHash = Guid.NewGuid().ToString().Substring(0, 7),
- aheadCount = 0,
- behindCount = 0
- };
-
- branches.Insert(1, newBranch); // Insert after main branch
-
- Debug.Log($"✅ Created new branch: {branchName}");
- EditorUtility.DisplayDialog("Branch Created",
- $"Successfully created branch '{branchName}'",
- "OK");
-
- Repaint();
- }
- private void DeleteBranch(BranchInfo branch)
- {
- branches.Remove(branch);
-
- Debug.Log($"🗑️ Deleted branch: {branch.name}");
- EditorUtility.DisplayDialog("Branch Deleted",
- $"Successfully deleted branch '{branch.name}'",
- "OK");
-
- Repaint();
- }
- #endregion
- #region Stash Operations
- private void CreateStash(string message)
- {
- if (string.IsNullOrWhiteSpace(message))
- message = "WIP: Stashed changes";
-
- var newStash = new StashInfo
- {
- id = $"stash@{{{stashes.Count}}}",
- message = message,
- branchName = currentBranch,
- author = "Developer",
- date = DateTime.Now,
- changedFiles = new List<string> { "Assets/Scripts/TempFile.cs" } // Mock changed files
- };
-
- stashes.Insert(0, newStash);
-
- Debug.Log($"📦 Created stash: {message}");
- EditorUtility.DisplayDialog("Stash Created",
- $"Successfully stashed changes: '{message}'",
- "OK");
-
- Repaint();
- }
- private void ApplyStash(StashInfo stash)
- {
- Debug.Log($"📥 Applying stash: {stash.message}");
-
- EditorUtility.DisplayDialog("Stash Applied",
- $"Successfully applied stash: '{stash.message}'",
- "OK");
-
- // In real implementation, this would apply the stashed changes
- // For now, we'll just show the dialog
-
- Repaint();
- }
- private void DeleteStash(StashInfo stash)
- {
- stashes.Remove(stash);
-
- Debug.Log($"🗑️ Deleted stash: {stash.message}");
- EditorUtility.DisplayDialog("Stash Deleted",
- $"Successfully deleted stash: '{stash.message}'",
- "OK");
-
- Repaint();
- }
- #endregion
- }
- #region Data Models
- [Serializable]
- public class BranchInfo
- {
- public string name;
- public bool isRemote;
- public bool isCurrent;
- public string lastCommitMessage;
- public string lastCommitAuthor;
- public DateTime lastCommitDate;
- public string commitHash;
- public int aheadCount;
- public int behindCount;
- }
- [Serializable]
- public class StashInfo
- {
- public string id;
- public string message;
- public string branchName;
- public string author;
- public DateTime date;
- public List<string> changedFiles;
- }
- #endregion
- }
|