feature: workspace support (#445)

This commit is contained in:
leo 2024-09-09 18:26:43 +08:00
parent acd6171350
commit ebc112a627
No known key found for this signature in database
27 changed files with 473 additions and 109 deletions

View file

@ -0,0 +1,60 @@
using System;
using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class ConfigureWorkspace : ObservableObject
{
public AvaloniaList<Workspace> Workspaces
{
get;
private set;
}
public Workspace Selected
{
get => _selected;
set
{
if (SetProperty(ref _selected, value))
CanDeleteSelected = value != null && !value.IsActive;
}
}
public bool CanDeleteSelected
{
get => _canDeleteSelected;
private set => SetProperty(ref _canDeleteSelected, value);
}
public ConfigureWorkspace()
{
Workspaces = new AvaloniaList<Workspace>();
Workspaces.AddRange(Preference.Instance.Workspaces);
}
public void Add()
{
var workspace = new Workspace();
workspace.Name = $"Unnamed {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
workspace.Color = 4278221015;
Preference.Instance.Workspaces.Add(workspace);
Workspaces.Add(workspace);
Selected = workspace;
}
public void Delete()
{
if (_selected == null || _selected.IsActive)
return;
Preference.Instance.Workspaces.Remove(_selected);
Workspaces.Remove(_selected);
}
private Workspace _selected = null;
private bool _canDeleteSelected = false;
}
}

View file

@ -17,6 +17,12 @@ namespace SourceGit.ViewModels
private set;
}
public Workspace ActiveWorkspace
{
get => _activeWorkspace;
private set => SetProperty(ref _activeWorkspace, value);
}
public LauncherPage ActivePage
{
get => _activePage;
@ -29,11 +35,35 @@ namespace SourceGit.ViewModels
public Launcher(string startupRepo)
{
var pref = Preference.Instance;
Pages = new AvaloniaList<LauncherPage>();
ActiveWorkspace = pref.GetActiveWorkspace();
AddNewTab();
var pref = Preference.Instance;
if (!string.IsNullOrEmpty(startupRepo))
var repos = _activeWorkspace.Repositories.ToArray();
foreach (var repo in repos)
{
var node = pref.FindNode(repo);
if (node == null)
{
node = new RepositoryNode()
{
Id = repo,
Name = Path.GetFileName(repo),
Bookmark = 0,
IsRepository = true,
};
}
OpenRepositoryInTab(node, null);
}
if (string.IsNullOrEmpty(startupRepo))
{
ActivePage = Pages[0];
}
else
{
var test = new Commands.QueryRepositoryRootPath(startupRepo).ReadToEnd();
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
@ -51,53 +81,6 @@ namespace SourceGit.ViewModels
Welcome.Instance.Refresh();
OpenRepositoryInTab(node, null);
}
else if (pref.RestoreTabs)
{
foreach (var id in pref.OpenedTabs)
{
var node = pref.FindNode(id);
if (node == null)
{
node = new RepositoryNode()
{
Id = id,
Name = Path.GetFileName(id),
Bookmark = 0,
IsRepository = true,
};
}
OpenRepositoryInTab(node, null);
}
var lastActiveIdx = pref.LastActiveTabIdx;
if (lastActiveIdx >= 0 && lastActiveIdx < Pages.Count)
ActivePage = Pages[lastActiveIdx];
}
}
public void Quit()
{
var pref = Preference.Instance;
pref.OpenedTabs.Clear();
if (pref.RestoreTabs)
{
foreach (var page in Pages)
{
if (page.Node.IsRepository)
pref.OpenedTabs.Add(page.Node.Id);
}
}
pref.LastActiveTabIdx = Pages.IndexOf(ActivePage);
pref.Save();
foreach (var page in Pages)
{
if (page.Data is Repository repo)
repo.Close();
}
}
public void AddNewTab()
@ -247,6 +230,7 @@ namespace SourceGit.ViewModels
};
repo.Open();
ActiveWorkspace.AddRepository(repo.FullPath);
Models.AutoFetchManager.Instance.AddRepository(repo.FullPath);
if (page == null)
@ -294,6 +278,46 @@ namespace SourceGit.ViewModels
_activePage.Notifications.Add(notification);
}
public ContextMenu CreateContextForWorkspace()
{
var pref = Preference.Instance;
var menu = new ContextMenu();
for (var i = 0; i < pref.Workspaces.Count; i++)
{
var workspace = pref.Workspaces[i];
var icon = App.CreateMenuIcon(workspace.IsActive ? "Icons.Check" : "Icons.Workspace");
icon.Fill = workspace.Brush;
var item = new MenuItem();
item.Header = workspace.Name;
item.Icon = icon;
item.Click += (_, e) =>
{
if (!workspace.IsActive)
SwitchWorkspace(workspace);
e.Handled = true;
};
menu.Items.Add(item);
}
menu.Items.Add(new MenuItem() { Header = "-" });
var configure = new MenuItem();
configure.Header = App.Text("Workspace.Configure");
configure.Click += (_, e) =>
{
App.OpenDialog(new Views.ConfigureWorkspace() { DataContext = new ConfigureWorkspace() });
e.Handled = true;
};
menu.Items.Add(configure);
return menu;
}
public ContextMenu CreateContextForPageTab(LauncherPage page)
{
if (page == null)
@ -369,10 +393,50 @@ namespace SourceGit.ViewModels
return menu;
}
private void CloseRepositoryInTab(LauncherPage page)
private void SwitchWorkspace(Workspace to)
{
var pref = Preference.Instance;
foreach (var w in pref.Workspaces)
w.IsActive = false;
ActiveWorkspace = to;
to.IsActive = true;
foreach (var one in Pages)
CloseRepositoryInTab(one, false);
Pages.Clear();
ActivePage = null;
AddNewTab();
var repos = to.Repositories.ToArray();
foreach (var repo in repos)
{
var node = pref.FindNode(repo);
if (node == null)
{
node = new RepositoryNode()
{
Id = repo,
Name = Path.GetFileName(repo),
Bookmark = 0,
IsRepository = true,
};
}
OpenRepositoryInTab(node, null);
}
GC.Collect();
}
private void CloseRepositoryInTab(LauncherPage page, bool removeFromWorkspace = true)
{
if (page.Data is Repository repo)
{
if (removeFromWorkspace)
ActiveWorkspace.Repositories.Remove(repo.FullPath);
Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath);
repo.Close();
}
@ -380,6 +444,7 @@ namespace SourceGit.ViewModels
page.Data = null;
}
private Workspace _activeWorkspace = null;
private LauncherPage _activePage = null;
}
}

View file

@ -39,6 +39,9 @@ namespace SourceGit.ViewModels
if (!_instance.IsGitConfigured())
_instance.GitInstallPath = Native.OS.FindGitExecutable();
if (_instance.Workspaces.Count == 0)
_instance.Workspaces.Add(new Workspace() { Name = "Default", Color = 4278221015 });
return _instance;
}
}
@ -133,12 +136,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _subjectGuideLength, value);
}
public bool RestoreTabs
{
get => _restoreTabs;
set => SetProperty(ref _restoreTabs, value);
}
public bool UseFixedTabWidth
{
get => _useFixedTabWidth;
@ -304,18 +301,12 @@ namespace SourceGit.ViewModels
set;
} = [];
public List<string> OpenedTabs
public List<Workspace> Workspaces
{
get;
set;
} = [];
public int LastActiveTabIdx
{
get;
set;
} = 0;
public double LastCheckUpdateTime
{
get => _lastCheckUpdateTime;
@ -343,6 +334,19 @@ namespace SourceGit.ViewModels
return true;
}
public Workspace GetActiveWorkspace()
{
foreach (var w in Workspaces)
{
if (w.IsActive)
return w;
}
var first = Workspaces[0];
first.IsActive = true;
return first;
}
public void AddNode(RepositoryNode node, RepositoryNode to, bool save)
{
var collection = to == null ? RepositoryNodes : to.SubNodes;
@ -492,7 +496,6 @@ namespace SourceGit.ViewModels
private int _maxHistoryCommits = 20000;
private int _subjectGuideLength = 50;
private bool _restoreTabs = false;
private bool _useFixedTabWidth = true;
private bool _check4UpdatesOnStartup = true;

View file

@ -0,0 +1,58 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class Workspace : ObservableObject
{
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
public uint Color
{
get => _color;
set
{
if (SetProperty(ref _color, value))
Brush = new SolidColorBrush(value);
}
}
public List<string> Repositories
{
get;
set;
} = new List<string>();
public bool IsActive
{
get => _isActive;
set => SetProperty(ref _isActive, value);
}
[JsonIgnore]
public IBrush Brush
{
get => _brush;
private set => SetProperty(ref _brush, value);
}
public void AddRepository(string repo)
{
if (!Repositories.Contains(repo))
Repositories.Add(repo);
}
private string _name = string.Empty;
private uint _color = 0;
private IBrush _brush = null;
private bool _isActive = false;
}
}