diff --git a/src/Resources/Locales/en_US.xaml b/src/Resources/Locales/en_US.xaml
index 310e403b..ee6eac93 100644
--- a/src/Resources/Locales/en_US.xaml
+++ b/src/Resources/Locales/en_US.xaml
@@ -298,8 +298,8 @@
SourceGit
Open Local Repository
Clone Remote Repository
- REPOSITORIES
- DRAG-DROP YOUR FOLDER
+ Bookmarks
+ Histories
Add Folder
Add Sub-Folder
Rename
diff --git a/src/Resources/Locales/zh_CN.xaml b/src/Resources/Locales/zh_CN.xaml
index a5984029..89561ac1 100644
--- a/src/Resources/Locales/zh_CN.xaml
+++ b/src/Resources/Locales/zh_CN.xaml
@@ -297,8 +297,8 @@
欢迎使用本软件
打开本地仓库
克隆远程仓库
- 仓库列表
- 支持拖放操作
+ 收藏/书签
+ 最近使用
新建分组
新建子分组
重命名
diff --git a/src/Views/Widgets/Welcome.xaml b/src/Views/Widgets/Welcome.xaml
index 55d457d8..0bd310b3 100644
--- a/src/Views/Widgets/Welcome.xaml
+++ b/src/Views/Widgets/Welcome.xaml
@@ -1,31 +1,30 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
+
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+ DragEnter="OnTreeBookmarksDragEnter"
+ DragLeave="OnTreeBookmarksDragLeave"
+ DragOver="OnTreeBookmarksDragOver"
+ Drop="OnTreeBookmarksDrop">
-
+
@@ -135,14 +185,14 @@
Color="{Binding Bookmark}"
IsNewPage="False"/>
-
+
-
-
-
+
+
+
diff --git a/src/Views/Widgets/Welcome.xaml.cs b/src/Views/Widgets/Welcome.xaml.cs
index eb255e83..30ea8923 100644
--- a/src/Views/Widgets/Welcome.xaml.cs
+++ b/src/Views/Widgets/Welcome.xaml.cs
@@ -14,92 +14,117 @@ namespace SourceGit.Views.Widgets {
/// 新标签页
///
public partial class Welcome : UserControl, Controls.IPopupContainer {
-
+
///
/// 树节点数据
///
public class Node : Controls.BindableBase {
- public string Id { get; set; }
- public string ParentId { get; set; }
-
+ public string Id {
+ get;
+ set;
+ }
+ public string ParentId {
+ get;
+ set;
+ }
+
private string name;
public string Name {
get => name;
set => SetProperty(ref name, value);
}
-
- public bool IsGroup { get; set; }
-
+
+ public bool IsGroup {
+ get;
+ set;
+ }
+
private bool isEditing = false;
public bool IsEditing {
get => isEditing;
set => SetProperty(ref isEditing, value);
}
-
- public bool IsExpanded { get; set; }
+
+ public bool IsExpanded {
+ get;
+ set;
+ }
private int bookmark = 0;
public int Bookmark {
get => bookmark;
set => SetProperty(ref bookmark, value);
}
-
- public List Children { get; set; }
+
+ public List Children {
+ get;
+ set;
+ }
}
-
+
///
/// 仓库节点编辑事件参数
///
public event Action OnNodeEdited;
+ private bool clearBookmark = false;
+
public Welcome() {
InitializeComponent();
UpdateTree();
}
-
+
#region POPUP_CONTAINER
public void Show(Controls.PopupWidget widget) {
popup.Show(widget);
}
-
+
public void ShowAndStart(Controls.PopupWidget widget) {
popup.ShowAndStart(widget);
}
-
+
public void UpdateProgress(string message) {
popup.UpdateProgress(message);
}
#endregion
-
+
#region FUNC_EVENTS
private void OnOpenClicked(object sender, RoutedEventArgs e) {
var dialog = new Controls.FolderDialog();
- if (dialog.ShowDialog() == true) CheckAndOpen(dialog.SelectedPath);
+
+ if (dialog.ShowDialog() == true) {
+ CheckAndOpen(dialog.SelectedPath);
+ }
}
-
+
private void OnCloneClicked(object sender, RoutedEventArgs e) {
- if (MakeSureReady()) new Popups.Clone().Show();
+ if (MakeSureReady()) {
+ new Popups.Clone().Show();
+ }
}
-
+
private void OnTreeNodeStatusChange(object sender, RoutedEventArgs e) {
var node = (sender as Controls.TreeItem).DataContext as Node;
+
if (node != null) {
var group = Models.Preference.Instance.FindGroup(node.Id);
group.IsExpanded = node.IsExpanded;
e.Handled = true;
}
}
-
+
private void OnTreeNodeDoubleClick(object sender, MouseButtonEventArgs e) {
var node = (sender as Controls.TreeItem).DataContext as Node;
+
if (node != null && !node.IsGroup) {
CheckAndOpen(node.Id);
e.Handled = true;
}
}
-
+
private void OnTreeContextMenuOpening(object sender, ContextMenuEventArgs e) {
- var item = tree.FindItem(e.OriginalSource as DependencyObject);
+ var item = treeHistory.FindItem(e.OriginalSource as DependencyObject);
+
if (item == null) {
var addFolder = new MenuItem();
addFolder.Header = App.Text("Welcome.NewFolder");
@@ -108,16 +133,20 @@ namespace SourceGit.Views.Widgets {
UpdateTree(group.Id);
ev.Handled = true;
};
-
var menu = new ContextMenu();
menu.Items.Add(addFolder);
menu.IsOpen = true;
e.Handled = true;
- } else {
+ }
+ else {
var node = item.DataContext as Node;
- if (node == null) return;
-
+
+ if (node == null) {
+ return;
+ }
+
var menu = new ContextMenu();
+
if (!node.IsGroup) {
var open = new MenuItem();
open.Header = App.Text("RepoCM.Open");
@@ -125,73 +154,71 @@ namespace SourceGit.Views.Widgets {
CheckAndOpen(node.Id);
ev.Handled = true;
};
-
var explore = new MenuItem();
explore.Header = App.Text("RepoCM.Explore");
explore.Click += (o, ev) => {
Process.Start("explorer", node.Id);
ev.Handled = true;
};
-
var iconBookmark = FindResource("Icon.Bookmark") as Geometry;
var bookmark = new MenuItem();
bookmark.Header = App.Text("RepoCM.Bookmark");
+
for (int i = 0; i < Controls.Bookmark.COLORS.Length; i++) {
var icon = new System.Windows.Shapes.Path();
icon.Data = iconBookmark;
icon.Fill = Controls.Bookmark.COLORS[i];
icon.Width = 8;
-
var mark = new MenuItem();
mark.Icon = icon;
mark.Header = $"{i}";
-
var refIdx = i;
mark.Click += (o, ev) => {
var repo = Models.Preference.Instance.FindRepository(node.Id);
+
if (repo != null) {
repo.Bookmark = refIdx;
- node.Bookmark = refIdx;
- OnNodeEdited?.Invoke(node);
+ UpdateTree();
}
+
ev.Handled = true;
};
-
bookmark.Items.Add(mark);
}
-
+
menu.Items.Add(open);
menu.Items.Add(explore);
menu.Items.Add(bookmark);
- } else {
+ }
+ else {
var addSubFolder = new MenuItem();
addSubFolder.Header = App.Text("Welcome.NewSubFolder");
addSubFolder.Click += (o, ev) => {
var parent = Models.Preference.Instance.FindGroup(node.Id);
- if (parent != null) parent.IsExpanded = true;
-
+
+ if (parent != null) {
+ parent.IsExpanded = true;
+ }
+
var group = Models.Preference.Instance.AddGroup("New Group", node.Id);
UpdateTree(group.Id);
ev.Handled = true;
};
-
menu.Items.Add(addSubFolder);
}
-
+
var rename = new MenuItem();
rename.Header = App.Text("Welcome.Rename");
rename.Click += (o, ev) => {
UpdateTree(node.Id);
ev.Handled = true;
};
-
var delete = new MenuItem();
delete.Header = App.Text("Welcome.Delete");
delete.Click += (o, ev) => {
DeleteNode(node);
ev.Handled = true;
};
-
menu.Items.Add(rename);
menu.Items.Add(delete);
menu.IsOpen = true;
@@ -199,93 +226,188 @@ namespace SourceGit.Views.Widgets {
}
}
#endregion
-
+
#region DRAP_DROP_EVENTS
- private void OnPageDragEnter(object sender, DragEventArgs e) {
- if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(typeof(Node))) {
- dropArea.Visibility = Visibility.Visible;
+ private void OnPageMouseDown(object sender, MouseButtonEventArgs e) {
+ var itemHistory = treeHistory.FindItem(e.OriginalSource as DependencyObject);
+
+ if (itemHistory == null) {
+ treeHistory.UnselectAll();
}
+
+ var itemBookmark = treeBookmarks.FindItem(e.OriginalSource as DependencyObject);
+
+ if (itemBookmark == null) {
+ treeBookmarks.UnselectAll();
+ }
+
+ clearBookmark = false;
}
-
- private void OnPageDragLeave(object sender, DragEventArgs e) {
- dropArea.Visibility = Visibility.Hidden;
- }
-
- private void OnPageDrop(object sender, DragEventArgs e) {
- dropArea.Visibility = Visibility.Hidden;
- }
-
- private void OnTreeMouseMove(object sender, MouseEventArgs e) {
- if (e.LeftButton != MouseButtonState.Pressed) return;
-
- var item = tree.FindItem(e.OriginalSource as DependencyObject);
- if (item == null) return;
-
- tree.UnselectAll();
-
+
+ private void OnPageMouseMove(object sender, MouseEventArgs e) {
+ if (e.LeftButton != MouseButtonState.Pressed) {
+ return;
+ }
+
+ var item = treeHistory.FindItem(e.OriginalSource as DependencyObject);
+
+ if (item == null) {
+ return;
+ }
+
+ treeHistory.UnselectAll();
var adorner = new Controls.DragDropAdorner(item);
DragDrop.DoDragDrop(item, item.DataContext, DragDropEffects.Move);
adorner.Remove();
}
-
- private void OnTreeDragOver(object sender, DragEventArgs e) {
- if (!e.Data.GetDataPresent(DataFormats.FileDrop) && !e.Data.GetDataPresent(typeof(Node))) return;
-
- var item = tree.FindItem(e.OriginalSource as DependencyObject);
- if (item == null) return;
-
- var node = item.DataContext as Node;
- if (node.IsGroup && !item.IsExpanded) item.IsExpanded = true;
- e.Handled = true;
- }
-
- private void OnTreeDrop(object sender, DragEventArgs e) {
+
+ private void OnPageDrop(object sender, DragEventArgs e) {
bool rebuild = false;
- dropArea.Visibility = Visibility.Hidden;
-
- var parent = "";
- var to = tree.FindItem(e.OriginalSource as DependencyObject);
- if (to != null) {
- var dst = to.DataContext as Node;
- parent = dst.IsGroup ? dst.Id : dst.ParentId;
- }
-
+
if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
- if (!MakeSureReady()) return;
-
+ if (!MakeSureReady()) {
+ return;
+ }
+
var paths = e.Data.GetData(DataFormats.FileDrop) as string[];
+
foreach (var path in paths) {
var dir = new Commands.QueryGitDir(path).Result();
+
if (dir != null) {
var root = new Commands.GetRepositoryRootPath(path).Result();
- Models.Preference.Instance.AddRepository(root, dir, parent);
+ Models.Preference.Instance.AddRepository(root, dir, "");
CheckAndOpen(path);
rebuild = true;
}
}
- } else if (e.Data.GetDataPresent(typeof(Node))) {
- var src = e.Data.GetData(typeof(Node)) as Node;
- if (src.IsGroup) {
- if (!Models.Preference.Instance.IsSubGroup(src.Id, parent)) {
- Models.Preference.Instance.FindGroup(src.Id).Parent = parent;
- rebuild = true;
+ }
+ else if (e.Data.GetDataPresent(typeof(Node))) {
+ var node = e.Data.GetData(typeof(Node)) as Node;
+
+ if (node.IsGroup) {
+ e.Handled = true;
+ return;
+ }
+ else {
+ var repo = Models.Preference.Instance.FindRepository(node.Id);
+
+ if (repo != null && repo.Bookmark != 0 && clearBookmark) {
+ repo.Bookmark = 0;
}
- } else {
- Models.Preference.Instance.FindRepository(src.Id).GroupId = parent;
+ clearBookmark = false;
rebuild = true;
}
}
+
+ if (rebuild) {
+ UpdateTree();
+ }
+
+ e.Handled = true;
+ }
+
+ private void OnTreeBookmarksDragEnter(object sender, DragEventArgs e) {
+ if (e.Data.GetDataPresent(DataFormats.FileDrop) || e.Data.GetDataPresent(typeof(Node))) {
+ dropArea.Visibility = Visibility.Visible;
+ }
+ }
+
+ private void OnTreeBookmarksDragLeave(object sender, DragEventArgs e) {
+ dropArea.Visibility = Visibility.Hidden;
+ }
+
+ private void OnTreeBookmarksDragOver(object sender, DragEventArgs e) {
+ if (!e.Data.GetDataPresent(DataFormats.FileDrop) && !e.Data.GetDataPresent(typeof(Node))) {
+ return;
+ }
+
+ var item = treeBookmarks.FindItem(e.OriginalSource as DependencyObject);
+
+ if (item == null) {
+ return;
+ }
+
+ var node = item.DataContext as Node;
+
+ if (node.IsGroup && !item.IsExpanded) {
+ item.IsExpanded = true;
+ }
- if (rebuild) UpdateTree();
+ clearBookmark = true;
+
+ e.Handled = true;
+ }
+
+ private void OnTreeBookmarksDrop(object sender, DragEventArgs e) {
+ bool rebuild = false;
+ var parent = "";
+
+ clearBookmark = false;
+ dropArea.Visibility = Visibility.Hidden;
+ var to = treeBookmarks.FindItem(e.OriginalSource as DependencyObject);
+
+ if (to != null) {
+ var dst = to.DataContext as Node;
+ parent = dst.IsGroup ? dst.Id : dst.ParentId;
+ }
+
+ if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
+ if (!MakeSureReady()) {
+ return;
+ }
+
+ var paths = e.Data.GetData(DataFormats.FileDrop) as string[];
+
+ foreach (var path in paths) {
+ var dir = new Commands.QueryGitDir(path).Result();
+
+ if (dir != null) {
+ var root = new Commands.GetRepositoryRootPath(path).Result();
+ Models.Preference.Instance.AddRepository(root, dir, parent).Bookmark = 1; // 默认添加的标签;
+ // CheckAndOpen(path);
+ rebuild = true;
+ }
+ }
+ }
+ else if (e.Data.GetDataPresent(typeof(Node))) {
+ var node = e.Data.GetData(typeof(Node)) as Node;
+
+ if (node.IsGroup) {
+ if (!Models.Preference.Instance.IsSubGroup(node.Id, parent)) {
+ Models.Preference.Instance.FindGroup(node.Id).Parent = parent;
+ rebuild = true;
+ }
+ }
+ else {
+ var repo = Models.Preference.Instance.FindRepository(node.Id);
+
+ if (repo != null) {
+ repo.GroupId = parent;
+
+ if (repo.Bookmark == 0) {
+ repo.Bookmark = 1;
+ }
+ }
+
+ rebuild = true;
+ }
+ }
+
+ if (rebuild) {
+ UpdateTree();
+ }
+
e.Handled = true;
}
#endregion
-
+
#region DATA
private void UpdateTree(string editingNodeId = null) {
var groupNodes = new Dictionary();
- var nodes = new List();
-
+ var nodesHistory = new List();
+ var nodesBookmarks = new List();
+
foreach (var group in Models.Preference.Instance.Groups) {
Node node = new Node() {
Id = group.Id,
@@ -297,20 +419,18 @@ namespace SourceGit.Views.Widgets {
Bookmark = 0,
Children = new List(),
};
-
groupNodes.Add(node.Id, node);
}
-
- nodes.Clear();
-
+
foreach (var kv in groupNodes) {
if (groupNodes.ContainsKey(kv.Value.ParentId)) {
groupNodes[kv.Value.ParentId].Children.Add(kv.Value);
- } else {
- nodes.Add(kv.Value);
+ }
+ else {
+ nodesBookmarks.Add(kv.Value);
}
}
-
+
foreach (var repo in Models.Preference.Instance.Repositories) {
Node node = new Node() {
Id = repo.Path,
@@ -322,109 +442,138 @@ namespace SourceGit.Views.Widgets {
Bookmark = repo.Bookmark,
Children = new List(),
};
-
- if (groupNodes.ContainsKey(repo.GroupId)) {
- groupNodes[repo.GroupId].Children.Add(node);
- } else {
- nodes.Add(node);
+ nodesHistory.Add(node);
+
+ if (repo.Bookmark != 0) {
+ if (groupNodes.ContainsKey(repo.GroupId)) {
+ groupNodes[repo.GroupId].Children.Add(node);
+ }
+ else {
+ nodesBookmarks.Add(node);
+ }
}
+
+ OnNodeEdited?.Invoke(node);
}
-
- tree.ItemsSource = nodes;
+
+ treeHistory.ItemsSource = nodesHistory;
+ treeBookmarks.ItemsSource = nodesBookmarks;
}
-
+
private void DeleteNode(Node node) {
if (node.IsGroup) {
Models.Preference.Instance.RemoveGroup(node.Id);
- } else {
+ }
+ else {
Models.Preference.Instance.RemoveRepository(node.Id);
}
-
+
UpdateTree();
}
-
+
private bool MakeSureReady() {
if (!Models.Preference.Instance.IsReady) {
Models.Exception.Raise(App.Text("NotConfigured"));
return false;
}
+
return true;
}
-
+
private void CheckAndOpen(string path) {
- if (!MakeSureReady()) return;
-
+ if (!MakeSureReady()) {
+ return;
+ }
+
if (!Directory.Exists(path)) {
Models.Exception.Raise(App.Text("PathNotFound", path));
return;
}
-
+
var root = new Commands.GetRepositoryRootPath(path).Result();
+
if (root == null) {
new Popups.Init(path).Show();
return;
}
-
+
var gitDir = new Commands.QueryGitDir(root).Result();
var repo = Models.Preference.Instance.AddRepository(root, gitDir, "");
Models.Watcher.Open(repo);
+ treeHistory.UnselectAll();
+ treeBookmarks.UnselectAll();
}
-
+
public void UpdateNodes(string id, int bookmark, IEnumerable nodes = null) {
- if (nodes == null) nodes = tree.ItemsSource.OfType();
+ if (nodes == null) {
+ nodes = treeHistory.ItemsSource.OfType();
+ }
+
foreach (var node in nodes) {
if (!node.IsGroup) {
if (node.Id == id) {
- node.Bookmark = bookmark;
+ Models.Preference.Instance.FindRepository(node.Id).Bookmark = bookmark;
+ UpdateTree();
break;
}
- } else if (node.Children.Count > 0) {
+ }
+ else if (node.Children.Count > 0) {
UpdateNodes(id, bookmark, node.Children);
}
}
-
}
#endregion
-
+
#region RENAME_NODES
private void RenameStart(object sender, RoutedEventArgs e) {
var edit = sender as Controls.TextEdit;
- if (edit == null || !edit.IsVisible) return;
-
+
+ if (edit == null || !edit.IsVisible) {
+ return;
+ }
+
edit.SelectAll();
edit.Focus();
}
-
+
private void RenameKeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Escape) {
UpdateTree();
e.Handled = true;
- } else if (e.Key == Key.Enter) {
+ }
+ else if (e.Key == Key.Enter) {
RenameEnd(sender, e);
e.Handled = true;
}
}
-
+
private void RenameEnd(object sender, RoutedEventArgs e) {
var edit = sender as Controls.TextEdit;
- if (edit == null) return;
-
+
+ if (edit == null) {
+ return;
+ }
+
if (string.IsNullOrWhiteSpace(edit.Text)) {
UpdateTree();
e.Handled = false;
return;
}
-
+
var node = edit.DataContext as Node;
+
if (node != null) {
node.Name = edit.Text;
node.IsEditing = false;
+
if (node.IsGroup) {
Models.Preference.Instance.RenameGroup(node.Id, edit.Text);
- } else {
+ }
+ else {
Models.Preference.Instance.RenameRepository(node.Id, node.Name);
OnNodeEdited?.Invoke(node);
}
+
e.Handled = false;
}
}