refactor: move auto-fetch from global preference to repository settings
Some checks are pending
Continuous Integration / Build (push) Waiting to run
Continuous Integration / Prepare version string (push) Waiting to run
Continuous Integration / Package (push) Blocked by required conditions

This commit is contained in:
leo 2024-09-26 10:50:21 +08:00
parent 8e31ea9140
commit 1ba294a07b
No known key found for this signature in database
25 changed files with 166 additions and 227 deletions

View file

@ -534,7 +534,6 @@ namespace SourceGit
{ {
Native.OS.SetupEnternalTools(); Native.OS.SetupEnternalTools();
Models.AvatarManager.Instance.Start(); Models.AvatarManager.Instance.Start();
Models.AutoFetchManager.Instance.Start();
string startupRepo = null; string startupRepo = null;
if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0])) if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0]))

View file

@ -22,8 +22,6 @@ namespace SourceGit.Commands
Args += "--force "; Args += "--force ";
Args += remote; Args += remote;
Models.AutoFetchManager.Instance.MarkFetched(repo);
} }
public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action<string> outputHandler) public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action<string> outputHandler)

View file

@ -1,126 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SourceGit.Models
{
public class AutoFetchManager
{
public static AutoFetchManager Instance
{
get
{
if (_instance == null)
_instance = new AutoFetchManager();
return _instance;
}
}
public class Job
{
public string IndexLockFile = string.Empty;
public Commands.Fetch Cmd = null;
public DateTime NextRunTimepoint = DateTime.MinValue;
}
public bool IsEnabled
{
get;
set;
} = false;
public int Interval
{
get => _interval;
set
{
_interval = Math.Max(1, value);
lock (_lock)
{
foreach (var job in _jobs)
job.Value.NextRunTimepoint = DateTime.Now.AddMinutes(_interval * 1.0);
}
}
}
private static AutoFetchManager _instance = null;
private Dictionary<string, Job> _jobs = new Dictionary<string, Job>();
private object _lock = new object();
private int _interval = 10;
public void Start()
{
Task.Run(() =>
{
while (true)
{
if (!IsEnabled)
{
Thread.Sleep(10000);
continue;
}
var now = DateTime.Now;
var uptodate = new List<Job>();
lock (_lock)
{
foreach (var job in _jobs)
{
if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0)
uptodate.Add(job.Value);
}
}
foreach (var job in uptodate)
{
if (!File.Exists(job.IndexLockFile))
{
job.Cmd.Exec();
job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval));
}
}
Thread.Sleep(2000);
}
// ReSharper disable once FunctionNeverReturns
});
}
public void AddRepository(string repo, string gitDir)
{
var job = new Job
{
IndexLockFile = Path.Combine(gitDir, "index.lock"),
Cmd = new Commands.Fetch(repo, "--all", true, false, null) { RaiseError = false },
NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)),
};
lock (_lock)
{
_jobs[repo] = job;
}
}
public void RemoveRepository(string repo)
{
lock (_lock)
{
_jobs.Remove(repo);
}
}
public void MarkFetched(string repo)
{
lock (_lock)
{
if (_jobs.TryGetValue(repo, out var value))
value.NextRunTimepoint = DateTime.Now.AddMinutes(Interval * 1.0);
}
}
}
}

16
src/Models/IRepository.cs Normal file
View file

@ -0,0 +1,16 @@
namespace SourceGit.Models
{
public interface IRepository
{
string FullPath { get; set; }
string GitDir { get; set; }
void RefreshBranches();
void RefreshWorktrees();
void RefreshTags();
void RefreshCommits();
void RefreshSubmodules();
void RefreshWorkingCopyChanges();
void RefreshStashes();
}
}

View file

@ -94,6 +94,18 @@ namespace SourceGit.Models
set; set;
} = new AvaloniaList<IssueTrackerRule>(); } = new AvaloniaList<IssueTrackerRule>();
public bool EnableAutoFetch
{
get;
set;
} = false;
public int AutoFetchInterval
{
get;
set;
} = 10;
public void PushCommitMessage(string message) public void PushCommitMessage(string message)
{ {
var existIdx = CommitMessages.IndexOf(message); var existIdx = CommitMessages.IndexOf(message);

View file

@ -6,20 +6,6 @@ using System.Threading.Tasks;
namespace SourceGit.Models namespace SourceGit.Models
{ {
public interface IRepository
{
string FullPath { get; set; }
string GitDir { get; set; }
void RefreshBranches();
void RefreshWorktrees();
void RefreshTags();
void RefreshCommits();
void RefreshSubmodules();
void RefreshWorkingCopyChanges();
void RefreshStashes();
}
public class Watcher : IDisposable public class Watcher : IDisposable
{ {
public Watcher(IRepository repo) public Watcher(IRepository repo)

View file

@ -137,6 +137,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Adresse</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Adresse</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email Adresse</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email Adresse</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Remotes automatisch fetchen</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(n)</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TICKETSYSTEM</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">TICKETSYSTEM</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Beispiel für Github-Regel hinzufügen</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Beispiel für Github-Regel hinzufügen</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Beispiel für Jira-Regel hinzufügen</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Beispiel für Jira-Regel hinzufügen</x:String>
@ -410,9 +412,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commit-Historie</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commit-Historie</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Längenvorgabe für Commit-Nachrichten</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Längenvorgabe für Commit-Nachrichten</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Remotes automatisch fetchen</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Auto-Fetch Intervall</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(n)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Aktiviere Auto-CRLF</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Aktiviere Auto-CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Clone Standardordner</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Clone Standardordner</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Benutzer Email</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Benutzer Email</x:String>

View file

@ -136,6 +136,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Address</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Email Address</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email address</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Email address</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch remotes automatically</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(s)</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String>
@ -409,9 +411,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">History Commits</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">History Commits</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Subject Guide Length</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Subject Guide Length</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Fetch remotes automatically</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Auto Fetch Interval</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minute(s)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Enable Auto CRLF</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Enable Auto CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Default Clone Dir</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Default Clone Dir</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">User Email</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">User Email</x:String>
@ -489,6 +488,7 @@
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">Unique name for this branch</x:String> <x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">Unique name for this branch</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Branch:</x:String> <x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">Branch:</x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">ABORT</x:String> <x:String x:Key="Text.Repository.Abort" xml:space="preserve">ABORT</x:String>
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">Auto fetching changes from remotes...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">Cleanup(GC &amp; Prune)</x:String> <x:String x:Key="Text.Repository.Clean" xml:space="preserve">Cleanup(GC &amp; Prune)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Run `git gc` command for this repository.</x:String> <x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">Run `git gc` command for this repository.</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Clear all</x:String> <x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">Clear all</x:String>

View file

@ -133,6 +133,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Addresse e-mail</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Addresse e-mail</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Addresse e-mail</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Addresse e-mail</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Fetch les dépôts distants automatiquement</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">minute(s)</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE TRACKER</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Add Sample Github Rule</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Add Sample Jira Rule</x:String>
@ -397,9 +399,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Historique de commits</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Historique de commits</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Guide de longueur du sujet</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Guide de longueur du sujet</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Fetch les dépôts distants automatiquement</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Intervalle de fetch auto</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">minute(s)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Activer auto CRLF</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Activer auto CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Répertoire de clônage par défaut</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Répertoire de clônage par défaut</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">E-mail utilsateur</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">E-mail utilsateur</x:String>

View file

@ -132,6 +132,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Endereço de Email</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Endereço de Email</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Endereço de email</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Endereço de email</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Buscar remotos automaticamente</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minuto(s)</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">RASTREADOR DE PROBLEMAS</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">RASTREADOR DE PROBLEMAS</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Adicionar Regra de Exemplo do Github</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Adicionar Regra de Exemplo do Github</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Adicionar Regra de Exemplo do Jira</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Adicionar Regra de Exemplo do Jira</x:String>
@ -391,9 +393,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commits do Histórico</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">Commits do Histórico</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Comprimento do Guia de Assunto</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Comprimento do Guia de Assunto</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Buscar remotos automaticamente</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Intervalo de Busca Automática</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Minuto(s)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Habilitar Auto CRLF</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Habilitar Auto CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Diretório Padrão de Clone</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Diretório Padrão de Clone</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">E-mail do Usuário</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">E-mail do Usuário</x:String>

View file

@ -136,6 +136,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">Адрес электронной почты</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">Адрес электронной почты</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Адрес электронной почты</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">Адрес электронной почты</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">Автоматическое извлечение внешних хранилищ</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">Минут(а/ы)</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ОТСЛЕЖИВАНИЕ ПРОБЛЕМ</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ОТСЛЕЖИВАНИЕ ПРОБЛЕМ</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Добавить пример правила для Git</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">Добавить пример правила для Git</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Добавить пример правила Jira</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">Добавить пример правила Jira</x:String>
@ -409,9 +411,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">История фиксаций</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">История фиксаций</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Длина темы фиксации</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">Длина темы фиксации</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">Автоматическое извлечение внешних хранилищ</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">Интервал автоматического извлечения</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">Минут(а/ы)</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Включить автозавершение CRLF</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">Включить автозавершение CRLF</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Каталог клонирования по-умолчанию</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">Каталог клонирования по-умолчанию</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Электроная почта пользователя</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">Электроная почта пользователя</x:String>
@ -573,7 +572,7 @@
<x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">НЕДЕЛЯ</x:String> <x:String x:Key="Text.Statistics.ThisWeek" xml:space="preserve">НЕДЕЛЯ</x:String>
<x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">ФИКСАЦИИ: </x:String> <x:String x:Key="Text.Statistics.TotalCommits" xml:space="preserve">ФИКСАЦИИ: </x:String>
<x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">АВТОРЫ: </x:String> <x:String x:Key="Text.Statistics.TotalAuthors" xml:space="preserve">АВТОРЫ: </x:String>
<x:String x:Key="Text.Statistics.Overview" xml:space="preserve">ОБЗОР</x:String> <x:String x:Key="Text.Statistics.Overview" xml:space="preserve">ОБЗОР</x:String>
<x:String x:Key="Text.Submodule" xml:space="preserve">ПОДМОДУЛИ</x:String> <x:String x:Key="Text.Submodule" xml:space="preserve">ПОДМОДУЛИ</x:String>
<x:String x:Key="Text.Submodule.Add" xml:space="preserve">Добавить подмодули</x:String> <x:String x:Key="Text.Submodule.Add" xml:space="preserve">Добавить подмодули</x:String>
<x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Копировать относительный путь</x:String> <x:String x:Key="Text.Submodule.CopyPath" xml:space="preserve">Копировать относительный путь</x:String>

View file

@ -139,6 +139,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">电子邮箱</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">电子邮箱</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">邮箱地址</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">邮箱地址</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT配置</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">GIT配置</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">启用定时自动拉取远程更新</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">分钟</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追踪</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">ISSUE追踪</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增匹配Github Issue规则</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增匹配Github Issue规则</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增匹配Jira规则</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增匹配Jira规则</x:String>
@ -408,9 +410,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">最大历史提交数</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">最大历史提交数</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">SUBJECT字数检测</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">SUBJECT字数检测</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT配置</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">GIT配置</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">启用定时自动拉取远程更新</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">自动拉取间隔</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">分钟</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">自动换行转换</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">自动换行转换</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">默认克隆路径</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">默认克隆路径</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">邮箱</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">邮箱</x:String>
@ -487,6 +486,7 @@
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">新的分支名不能与现有分支名相同</x:String> <x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">新的分支名不能与现有分支名相同</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">分支 </x:String> <x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">分支 </x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">终止合并</x:String> <x:String x:Key="Text.Repository.Abort" xml:space="preserve">终止合并</x:String>
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">自动拉取远端变更中...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">清理本仓库(GC)</x:String> <x:String x:Key="Text.Repository.Clean" xml:space="preserve">清理本仓库(GC)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">本操作将执行`git gc`命令。</x:String> <x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">本操作将执行`git gc`命令。</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">清空过滤规则</x:String> <x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">清空过滤规则</x:String>

View file

@ -139,6 +139,8 @@
<x:String x:Key="Text.Configure.Email" xml:space="preserve">電子郵件</x:String> <x:String x:Key="Text.Configure.Email" xml:space="preserve">電子郵件</x:String>
<x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">電子郵件地址</x:String> <x:String x:Key="Text.Configure.Email.Placeholder" xml:space="preserve">電子郵件地址</x:String>
<x:String x:Key="Text.Configure.Git" xml:space="preserve">Git 設定</x:String> <x:String x:Key="Text.Configure.Git" xml:space="preserve">Git 設定</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetch" xml:space="preserve">啟用定時自動提取 (fetch) 遠端更新</x:String>
<x:String x:Key="Text.Configure.Git.AutoFetchIntervalSuffix" xml:space="preserve">分鐘</x:String>
<x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">Issue 追蹤</x:String> <x:String x:Key="Text.Configure.IssueTracker" xml:space="preserve">Issue 追蹤</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增符合 GitHub Issue 規則</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleGithub" xml:space="preserve">新增符合 GitHub Issue 規則</x:String>
<x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增符合 Jira 規則</x:String> <x:String x:Key="Text.Configure.IssueTracker.AddSampleJira" xml:space="preserve">新增符合 Jira 規則</x:String>
@ -412,9 +414,6 @@
<x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">最大歷史提交數</x:String> <x:String x:Key="Text.Preference.General.MaxHistoryCommits" xml:space="preserve">最大歷史提交數</x:String>
<x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">提交標題字數偵測</x:String> <x:String x:Key="Text.Preference.General.SubjectGuideLength" xml:space="preserve">提交標題字數偵測</x:String>
<x:String x:Key="Text.Preference.Git" xml:space="preserve">Git 設定</x:String> <x:String x:Key="Text.Preference.Git" xml:space="preserve">Git 設定</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetch" xml:space="preserve">啟用定時自動提取 (fetch) 遠端更新</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchInterval" xml:space="preserve">自動提取間隔</x:String>
<x:String x:Key="Text.Preference.Git.AutoFetchIntervalSuffix" xml:space="preserve">分鐘</x:String>
<x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">自動換行轉換</x:String> <x:String x:Key="Text.Preference.Git.CRLF" xml:space="preserve">自動換行轉換</x:String>
<x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">預設複製 (clone) 路徑</x:String> <x:String x:Key="Text.Preference.Git.DefaultCloneDir" xml:space="preserve">預設複製 (clone) 路徑</x:String>
<x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">電子郵件</x:String> <x:String x:Key="Text.Preference.Git.Email" xml:space="preserve">電子郵件</x:String>
@ -492,6 +491,7 @@
<x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">新的分支名稱不能與現有分支名稱相同</x:String> <x:String x:Key="Text.RenameBranch.Name.Placeholder" xml:space="preserve">新的分支名稱不能與現有分支名稱相同</x:String>
<x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">分支:</x:String> <x:String x:Key="Text.RenameBranch.Target" xml:space="preserve">分支:</x:String>
<x:String x:Key="Text.Repository.Abort" xml:space="preserve">中止</x:String> <x:String x:Key="Text.Repository.Abort" xml:space="preserve">中止</x:String>
<x:String x:Key="Text.Repository.AutoFetching" xml:space="preserve">自動提取遠端變更中...</x:String>
<x:String x:Key="Text.Repository.Clean" xml:space="preserve">清理本存放庫 (GC)</x:String> <x:String x:Key="Text.Repository.Clean" xml:space="preserve">清理本存放庫 (GC)</x:String>
<x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">本操作將執行 `git gc` 命令。</x:String> <x:String x:Key="Text.Repository.CleanTips" xml:space="preserve">本操作將執行 `git gc` 命令。</x:String>
<x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">清空篩選規則</x:String> <x:String x:Key="Text.Repository.ClearAllCommitsFilter" xml:space="preserve">清空篩選規則</x:String>

View file

@ -104,6 +104,7 @@ namespace SourceGit.ViewModels
} }
CallUIThread(() => CallUIThread(() =>
{ {
_repo.MarkFetched();
_repo.MarkBranchesDirtyManually(); _repo.MarkBranchesDirtyManually();
_repo.SetWatcherEnabled(true); _repo.SetWatcherEnabled(true);
}); });

View file

@ -62,7 +62,12 @@ namespace SourceGit.ViewModels
new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, Prune, NoTags, SetProgressDescription).Exec(); new Commands.Fetch(_repo.FullPath, SelectedRemote.Name, Prune, NoTags, SetProgressDescription).Exec();
} }
CallUIThread(() => _repo.SetWatcherEnabled(true)); CallUIThread(() =>
{
_repo.MarkFetched();
_repo.SetWatcherEnabled(true);
});
return true; return true;
}); });
} }

View file

@ -179,7 +179,6 @@ namespace SourceGit.ViewModels
ActiveWorkspace.Repositories.Clear(); ActiveWorkspace.Repositories.Clear();
ActiveWorkspace.ActiveIdx = 0; ActiveWorkspace.ActiveIdx = 0;
Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath);
repo.Close(); repo.Close();
Welcome.Instance.ClearSearchFilter(); Welcome.Instance.ClearSearchFilter();
@ -293,7 +292,6 @@ namespace SourceGit.ViewModels
}; };
repo.Open(); repo.Open();
Models.AutoFetchManager.Instance.AddRepository(repo.FullPath, repo.GitDir);
if (page == null) if (page == null)
{ {
@ -522,7 +520,6 @@ namespace SourceGit.ViewModels
if (removeFromWorkspace) if (removeFromWorkspace)
ActiveWorkspace.Repositories.Remove(repo.FullPath); ActiveWorkspace.Repositories.Remove(repo.FullPath);
Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath);
repo.Close(); repo.Close();
} }

View file

@ -44,6 +44,14 @@ namespace SourceGit.ViewModels
return _node.Id; return _node.Id;
} }
public override bool IsInProgress()
{
if (_data is Repository { IsAutoFetching: true })
return true;
return base.IsInProgress();
}
public void CopyPath() public void CopyPath()
{ {
if (_node.IsRepository) if (_node.IsRepository)

View file

@ -18,7 +18,7 @@ namespace SourceGit.ViewModels
public static bool CanCreatePopup() public static bool CanCreatePopup()
{ {
return Active != null && (Active._popup == null || !Active._popup.InProgress); return Active?.IsInProgress() != true;
} }
public static void ShowPopup(Popup popup) public static void ShowPopup(Popup popup)
@ -40,6 +40,11 @@ namespace SourceGit.ViewModels
return string.Empty; return string.Empty;
} }
public virtual bool IsInProgress()
{
return _popup is { InProgress: true };
}
public async void ProcessPopup() public async void ProcessPopup()
{ {
if (_popup != null) if (_popup != null)

View file

@ -216,35 +216,6 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _gitDefaultCloneDir, value); set => SetProperty(ref _gitDefaultCloneDir, value);
} }
public bool GitAutoFetch
{
get => Models.AutoFetchManager.Instance.IsEnabled;
set
{
if (Models.AutoFetchManager.Instance.IsEnabled != value)
{
Models.AutoFetchManager.Instance.IsEnabled = value;
OnPropertyChanged();
}
}
}
public int? GitAutoFetchInterval
{
get => Models.AutoFetchManager.Instance.Interval;
set
{
if (value is null || value < 1)
return;
if (Models.AutoFetchManager.Instance.Interval != value)
{
Models.AutoFetchManager.Instance.Interval = (int)value;
OnPropertyChanged();
}
}
}
public int ShellOrTerminal public int ShellOrTerminal
{ {
get => _shellOrTerminal; get => _shellOrTerminal;

View file

@ -140,6 +140,8 @@ namespace SourceGit.ViewModels
if (!rs) if (!rs)
return false; return false;
_repo.MarkFetched();
// Use merge/rebase instead of pull as fetch is done manually. // Use merge/rebase instead of pull as fetch is done manually.
if (UseRebase) if (UseRebase)
{ {

View file

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Collections; using Avalonia.Collections;
@ -323,6 +324,12 @@ namespace SourceGit.ViewModels
} }
} }
public bool IsAutoFetching
{
get;
private set;
}
public void Open() public void Open()
{ {
var settingsFile = Path.Combine(_gitDir, "sourcegit.settings"); var settingsFile = Path.Combine(_gitDir, "sourcegit.settings");
@ -359,6 +366,7 @@ namespace SourceGit.ViewModels
_inProgressContext = null; _inProgressContext = null;
_hasUnsolvedConflicts = false; _hasUnsolvedConflicts = false;
_autoFetchTimer = new Timer(AutoFetchImpl, null, 5000, 5000);
RefreshAll(); RefreshAll();
} }
@ -377,6 +385,9 @@ namespace SourceGit.ViewModels
} }
_settings = null; _settings = null;
_autoFetchTimer.Dispose();
_autoFetchTimer = null;
_watcher?.Dispose(); _watcher?.Dispose();
_histories.Cleanup(); _histories.Cleanup();
_workingCopy.Cleanup(); _workingCopy.Cleanup();
@ -628,6 +639,11 @@ namespace SourceGit.ViewModels
_watcher.MarkWorkingCopyDirtyManually(); _watcher.MarkWorkingCopyDirtyManually();
} }
public void MarkFetched()
{
_lastFetchTime = DateTime.Now;
}
public void NavigateToCommit(string sha) public void NavigateToCommit(string sha)
{ {
if (_histories != null) if (_histories != null)
@ -1991,6 +2007,28 @@ namespace SourceGit.ViewModels
} }
} }
private void AutoFetchImpl(object sender)
{
if (!_settings.EnableAutoFetch || IsAutoFetching)
return;
var lockFile = Path.Combine(_gitDir, "index.lock");
if (File.Exists(lockFile))
return;
var now = DateTime.Now;
var desire = _lastFetchTime.AddMinutes(_settings.AutoFetchInterval);
if (desire > now)
return;
IsAutoFetching = true;
Dispatcher.UIThread.Invoke(() => OnPropertyChanged(nameof(IsAutoFetching)));
new Commands.Fetch(_fullpath, "--all", true, false, null) { RaiseError = false }.Exec();
_lastFetchTime = DateTime.Now;
IsAutoFetching = false;
Dispatcher.UIThread.Invoke(() => OnPropertyChanged(nameof(IsAutoFetching)));
}
private string _fullpath = string.Empty; private string _fullpath = string.Empty;
private string _gitDir = string.Empty; private string _gitDir = string.Empty;
private Models.RepositorySettings _settings = null; private Models.RepositorySettings _settings = null;
@ -2036,5 +2074,8 @@ namespace SourceGit.ViewModels
private InProgressContext _inProgressContext = null; private InProgressContext _inProgressContext = null;
private bool _hasUnsolvedConflicts = false; private bool _hasUnsolvedConflicts = false;
private Models.Commit _searchResultSelectedCommit = null; private Models.Commit _searchResultSelectedCommit = null;
private Timer _autoFetchTimer = null;
private DateTime _lastFetchTime = DateTime.MinValue;
} }
} }

View file

@ -42,6 +42,26 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _httpProxy, value); set => SetProperty(ref _httpProxy, value);
} }
public bool EnableAutoFetch
{
get => _repo.Settings.EnableAutoFetch;
set => _repo.Settings.EnableAutoFetch = value;
}
public int? AutoFetchInterval
{
get => _repo.Settings.AutoFetchInterval;
set
{
if (value is null || value < 1)
return;
var interval = (int)value;
if (_repo.Settings.AutoFetchInterval != interval)
_repo.Settings.AutoFetchInterval = interval;
}
}
public AvaloniaList<Models.CommitTemplate> CommitTemplates public AvaloniaList<Models.CommitTemplate> CommitTemplates
{ {
get => _repo.Settings.CommitTemplates; get => _repo.Settings.CommitTemplates;

View file

@ -52,7 +52,7 @@
<TabItem.Header> <TabItem.Header>
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.General}"/> <TextBlock Classes="tab_header" Text="{DynamicResource Text.Preference.General}"/>
</TabItem.Header> </TabItem.Header>
<Grid Margin="8" RowDefinitions="32,32,32,32,32,32,Auto" ColumnDefinitions="Auto,*"> <Grid Margin="8" RowDefinitions="32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
Text="{DynamicResource Text.Preference.General.Locale}" Text="{DynamicResource Text.Preference.General.Locale}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
@ -116,32 +116,6 @@
Height="32" Height="32"
Content="{DynamicResource Text.Preference.General.Check4UpdatesOnStartup}" Content="{DynamicResource Text.Preference.General.Check4UpdatesOnStartup}"
IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=Check4UpdatesOnStartup, Mode=TwoWay}"/> IsChecked="{Binding Source={x:Static vm:Preference.Instance}, Path=Check4UpdatesOnStartup, Mode=TwoWay}"/>
<CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Preference.Git.AutoFetch}"
IsChecked="{Binding GitAutoFetch, Mode=TwoWay}"/>
<TextBlock Grid.Row="6" Grid.Column="0"
IsVisible="{Binding GitAutoFetch}"
Text="{DynamicResource Text.Preference.Git.AutoFetchInterval}"
HorizontalAlignment="Right"
Margin="0,0,16,0"/>
<Grid Grid.Row="6" Grid.Column="1" Height="32" ColumnDefinitions="*,Auto" IsVisible="{Binding GitAutoFetch}">
<NumericUpDown Grid.Column="0"
Minimum="1" Maximum="60" Increment="1"
Height="28"
Padding="4"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
CornerRadius="3"
ParsingNumberStyle="Integer"
FormatString="0"
Value="{Binding GitAutoFetchInterval, Mode=TwoWay, FallbackValue=10}"/>
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
Margin="5,0,0,0"
Text="{DynamicResource Text.Preference.Git.AutoFetchIntervalSuffix}" />
</Grid>
</Grid> </Grid>
</TabItem> </TabItem>

View file

@ -631,5 +631,19 @@
</ContentControl.DataTemplates> </ContentControl.DataTemplates>
</ContentControl> </ContentControl>
</Grid> </Grid>
<!-- Right (Auto-Fetch) -->
<Border Grid.Column="2" Margin="12" HorizontalAlignment="Center" VerticalAlignment="Center" Effect="drop-shadow(0 0 12 #A0000000)" IsVisible="{Binding IsAutoFetching}">
<Border Background="{DynamicResource Brush.Popup}" CornerRadius="6">
<StackPanel Orientation="Vertical" Margin="16,8">
<TextBlock Text="{DynamicResource Text.Repository.AutoFetching}"/>
<ProgressBar Margin="0,8,0,0"
HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsAutoFetching}"
Background="{DynamicResource Brush.FG2}" Foreground="{DynamicResource Brush.Accent}"
Minimum="0" Maximum="100"/>
</StackPanel>
</Border>
</Border>
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -51,7 +51,7 @@
<TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.Git}"/> <TextBlock Classes="tab_header" Text="{DynamicResource Text.Configure.Git}"/>
</TabItem.Header> </TabItem.Header>
<Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32" ColumnDefinitions="Auto,*"> <Grid Margin="16,4,16,8" RowDefinitions="32,32,32,32,32,32,32" ColumnDefinitions="Auto,*">
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0" Margin="0,0,8,0"
@ -106,6 +106,26 @@
<CheckBox Grid.Row="5" Grid.Column="1" <CheckBox Grid.Row="5" Grid.Column="1"
Content="{DynamicResource Text.Preference.GPG.TagEnabled}" Content="{DynamicResource Text.Preference.GPG.TagEnabled}"
IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/> IsChecked="{Binding GPGTagSigningEnabled, Mode=TwoWay}"/>
<StackPanel Grid.Row="6" Grid.Column="1" Orientation="Horizontal">
<CheckBox x:Name="AutoFetchCheckBox"
Content="{DynamicResource Text.Configure.Git.AutoFetch}"
IsChecked="{Binding EnableAutoFetch, Mode=TwoWay}"/>
<NumericUpDown Minimum="1" Maximum="60" Increment="1"
Height="26"
Margin="8,0,0,0" Padding="4"
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
CornerRadius="3"
ParsingNumberStyle="Integer"
FormatString="0"
Value="{Binding AutoFetchInterval, Mode=TwoWay, FallbackValue=10}"
IsEnabled="{Binding #AutoFetchCheckBox.IsChecked}"/>
<TextBlock VerticalAlignment="Center"
Margin="5,0,0,0"
Text="{DynamicResource Text.Configure.Git.AutoFetchIntervalSuffix}" />
</StackPanel>
</Grid> </Grid>
</TabItem> </TabItem>