diff --git a/src/App.axaml.cs b/src/App.axaml.cs index f09f9de2..a1eaee6a 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -528,6 +528,8 @@ namespace SourceGit private void TryLaunchedAsNormal(IClassicDesktopStyleApplicationLifetime desktop) { Native.OS.SetupEnternalTools(); + Models.AvatarManager.Instance.Start(); + Models.AutoFetchManager.Instance.Start(); string startupRepo = null; if (desktop.Args != null && desktop.Args.Length == 1 && Directory.Exists(desktop.Args[0])) diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs index df5a1c2b..2fb013c6 100644 --- a/src/Commands/Fetch.cs +++ b/src/Commands/Fetch.cs @@ -26,7 +26,7 @@ namespace SourceGit.Commands Args += remote; - AutoFetch.MarkFetched(repo); + Models.AutoFetchManager.Instance.MarkFetched(repo); } public Fetch(string repo, string remote, string localBranch, string remoteBranch, Action outputHandler) @@ -46,110 +46,4 @@ namespace SourceGit.Commands private readonly Action _outputHandler; } - - public class AutoFetch - { - public static bool IsEnabled - { - get; - set; - } = false; - - public static int Interval - { - get => _interval; - set - { - if (value < 1) - return; - _interval = value; - lock (_lock) - { - foreach (var job in _jobs) - { - job.Value.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(_interval)); - } - } - } - } - - class Job - { - public Fetch Cmd = null; - public DateTime NextRunTimepoint = DateTime.MinValue; - } - - static AutoFetch() - { - Task.Run(() => - { - while (true) - { - if (!IsEnabled) - { - Thread.Sleep(10000); - continue; - } - - var now = DateTime.Now; - var uptodate = new List(); - lock (_lock) - { - foreach (var job in _jobs) - { - if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0) - { - uptodate.Add(job.Value); - } - } - } - - foreach (var job in uptodate) - { - job.Cmd.Exec(); - job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); - } - - Thread.Sleep(2000); - } - }); - } - - public static void AddRepository(string repo) - { - var job = new Job - { - Cmd = new Fetch(repo, "--all", true, false, null) { RaiseError = false }, - NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)), - }; - - lock (_lock) - { - _jobs[repo] = job; - } - } - - public static void RemoveRepository(string repo) - { - lock (_lock) - { - _jobs.Remove(repo); - } - } - - public static void MarkFetched(string repo) - { - lock (_lock) - { - if (_jobs.TryGetValue(repo, out var value)) - { - value.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); - } - } - } - - private static readonly Dictionary _jobs = new Dictionary(); - private static readonly object _lock = new object(); - private static int _interval = 10; - } } diff --git a/src/Models/AutoFetchManager.cs b/src/Models/AutoFetchManager.cs new file mode 100644 index 00000000..138a1de2 --- /dev/null +++ b/src/Models/AutoFetchManager.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +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 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 _jobs = new Dictionary(); + 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(); + lock (_lock) + { + foreach (var job in _jobs) + { + if (job.Value.NextRunTimepoint.Subtract(now).TotalSeconds <= 0) + uptodate.Add(job.Value); + } + } + + foreach (var job in uptodate) + { + job.Cmd.Exec(); + job.NextRunTimepoint = DateTime.Now.AddMinutes(Convert.ToDouble(Interval)); + } + + Thread.Sleep(2000); + } + + // ReSharper disable once FunctionNeverReturns + }); + } + + public void AddRepository(string repo) + { + var job = new Job + { + 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); + } + } + } +} diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs index e85de1fd..8193dda8 100644 --- a/src/Models/AvatarManager.cs +++ b/src/Models/AvatarManager.cs @@ -20,15 +20,31 @@ namespace SourceGit.Models void OnAvatarResourceChanged(string email); } - public static partial class AvatarManager + public partial class AvatarManager { - public static string SelectedServer + public static AvatarManager Instance { - get; - set; - } = "https://www.gravatar.com/avatar/"; + get + { + if (_instance == null) + _instance = new AvatarManager(); - static AvatarManager() + return _instance; + } + } + + private static AvatarManager _instance = null; + + [GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@users\.noreply\.github\.com$")] + private static partial Regex REG_GITHUB_USER_EMAIL(); + + private object _synclock = new object(); + private string _storePath; + private List _avatars = new List(); + private Dictionary _resources = new Dictionary(); + private HashSet _requesting = new HashSet(); + + public void Start() { _storePath = Path.Combine(Native.OS.DataDir, "avatars"); if (!Directory.Exists(_storePath)) @@ -62,7 +78,7 @@ namespace SourceGit.Models var matchGithubUser = REG_GITHUB_USER_EMAIL().Match(email); var url = matchGithubUser.Success ? $"https://avatars.githubusercontent.com/{matchGithubUser.Groups[2].Value}" : - $"{SelectedServer}{md5}?d=404"; + $"https://www.gravatar.com/avatar/{md5}?d=404"; var localFile = Path.Combine(_storePath, md5); var img = null as Bitmap; @@ -105,20 +121,22 @@ namespace SourceGit.Models NotifyResourceChanged(email); }); } + + // ReSharper disable once FunctionNeverReturns }); } - public static void Subscribe(IAvatarHost host) + public void Subscribe(IAvatarHost host) { _avatars.Add(host); } - public static void Unsubscribe(IAvatarHost host) + public void Unsubscribe(IAvatarHost host) { _avatars.Remove(host); } - public static Bitmap Request(string email, bool forceRefetch) + public Bitmap Request(string email, bool forceRefetch) { if (forceRefetch) { @@ -167,7 +185,7 @@ namespace SourceGit.Models return null; } - private static string GetEmailHash(string email) + private string GetEmailHash(string email) { var lowered = email.ToLower(CultureInfo.CurrentCulture).Trim(); var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(lowered)); @@ -177,21 +195,12 @@ namespace SourceGit.Models return builder.ToString(); } - private static void NotifyResourceChanged(string email) + private void NotifyResourceChanged(string email) { foreach (var avatar in _avatars) { avatar.OnAvatarResourceChanged(email); } } - - private static readonly object _synclock = new object(); - private static readonly string _storePath; - private static readonly List _avatars = new List(); - private static readonly Dictionary _resources = new Dictionary(); - private static readonly HashSet _requesting = new HashSet(); - - [GeneratedRegex(@"^(?:(\d+)\+)?(.+?)@users\.noreply\.github\.com$")] - private static partial Regex REG_GITHUB_USER_EMAIL(); } } diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml index cd162f52..649dc7c9 100644 --- a/src/Resources/Locales/de_DE.axaml +++ b/src/Resources/Locales/de_DE.axaml @@ -378,7 +378,6 @@ Design Design-Anpassungen ALLGEMEIN - Avatar Server Beim Starten nach Updates suchen Sprache Commit-Historie diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 001d042a..57e199ac 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -380,7 +380,6 @@ Theme Theme Overrides GENERAL - Avatar Server Check for updates on startup Language History Commits diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml index 3a3bebad..637f9a21 100644 --- a/src/Resources/Locales/pt_BR.axaml +++ b/src/Resources/Locales/pt_BR.axaml @@ -383,7 +383,6 @@ Tema Sobrescrever Tema GERAL - Servidor de Avatar Verificar atualizações na inicialização Idioma Commits do Histórico diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 2bd21da2..3aa37333 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -383,7 +383,6 @@ 主题 主题自定义 通用配置 - 头像服务 启动时检测软件更新 显示语言 最大历史提交数 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index ea4a2cde..682335b7 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -383,7 +383,6 @@ 主題 主題自訂 通用配置 - 頭像服務 啟動時檢測軟體更新 顯示語言 最大歷史提交數 diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 71584098..7661b28a 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -141,7 +141,7 @@ namespace SourceGit.ViewModels var last = Pages[0]; if (last.Data is Repository repo) { - Commands.AutoFetch.RemoveRepository(repo.FullPath); + Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath); repo.Close(); last.Node = new RepositoryNode() { Id = Guid.NewGuid().ToString() }; @@ -245,7 +245,7 @@ namespace SourceGit.ViewModels }; repo.Open(); - Commands.AutoFetch.AddRepository(repo.FullPath); + Models.AutoFetchManager.Instance.AddRepository(repo.FullPath); if (page == null) { @@ -371,7 +371,7 @@ namespace SourceGit.ViewModels { if (page.Data is Repository repo) { - Commands.AutoFetch.RemoveRepository(repo.FullPath); + Models.AutoFetchManager.Instance.RemoveRepository(repo.FullPath); repo.Close(); } diff --git a/src/ViewModels/Preference.cs b/src/ViewModels/Preference.cs index 5a7ca874..ba67ec7c 100644 --- a/src/ViewModels/Preference.cs +++ b/src/ViewModels/Preference.cs @@ -128,19 +128,6 @@ namespace SourceGit.ViewModels set => SetProperty(ref _layout, value); } - public string AvatarServer - { - get => Models.AvatarManager.SelectedServer; - set - { - if (Models.AvatarManager.SelectedServer != value) - { - Models.AvatarManager.SelectedServer = value; - OnPropertyChanged(); - } - } - } - public int MaxHistoryCommits { get => _maxHistoryCommits; @@ -262,9 +249,7 @@ namespace SourceGit.ViewModels set { if (Native.OS.SetShell(value)) - { OnPropertyChanged(); - } } } @@ -276,12 +261,12 @@ namespace SourceGit.ViewModels public bool GitAutoFetch { - get => Commands.AutoFetch.IsEnabled; + get => Models.AutoFetchManager.Instance.IsEnabled; set { - if (Commands.AutoFetch.IsEnabled != value) + if (Models.AutoFetchManager.Instance.IsEnabled != value) { - Commands.AutoFetch.IsEnabled = value; + Models.AutoFetchManager.Instance.IsEnabled = value; OnPropertyChanged(); } } @@ -289,15 +274,15 @@ namespace SourceGit.ViewModels public int? GitAutoFetchInterval { - get => Commands.AutoFetch.Interval; + get => Models.AutoFetchManager.Instance.Interval; set { - if (value is null or < 1) + if (value is null || value < 1) return; - - if (Commands.AutoFetch.Interval != value) + + if (Models.AutoFetchManager.Instance.Interval != value) { - Commands.AutoFetch.Interval = (int)value; + Models.AutoFetchManager.Instance.Interval = (int)value; OnPropertyChanged(); } } @@ -336,7 +321,7 @@ namespace SourceGit.ViewModels { get; set; - } = new List(); + } = []; public int LastActiveTabIdx { diff --git a/src/Views/Avatar.cs b/src/Views/Avatar.cs index e48f972e..24ac229f 100644 --- a/src/Views/Avatar.cs +++ b/src/Views/Avatar.cs @@ -39,7 +39,7 @@ namespace SourceGit.Views refetch.Click += (_, _) => { if (User != null) - Models.AvatarManager.Request(User.Email, true); + Models.AvatarManager.Instance.Request(User.Email, true); }; ContextMenu = new ContextMenu(); @@ -54,7 +54,7 @@ namespace SourceGit.Views return; var corner = (float)Math.Max(2, Bounds.Width / 16); - var img = Models.AvatarManager.Request(User.Email, false); + var img = Models.AvatarManager.Instance.Request(User.Email, false); if (img != null) { var rect = new Rect(0, 0, Bounds.Width, Bounds.Height); @@ -72,21 +72,19 @@ namespace SourceGit.Views public void OnAvatarResourceChanged(string email) { if (User.Email.Equals(email, StringComparison.Ordinal)) - { InvalidateVisual(); - } } protected override void OnLoaded(RoutedEventArgs e) { base.OnLoaded(e); - Models.AvatarManager.Subscribe(this); + Models.AvatarManager.Instance.Subscribe(this); } protected override void OnUnloaded(RoutedEventArgs e) { base.OnUnloaded(e); - Models.AvatarManager.Unsubscribe(this); + Models.AvatarManager.Instance.Unsubscribe(this); } private static void OnUserPropertyChanged(Avatar avatar, AvaloniaPropertyChangedEventArgs e) diff --git a/src/Views/Preference.axaml b/src/Views/Preference.axaml index 79eda516..6b34a1f1 100644 --- a/src/Views/Preference.axaml +++ b/src/Views/Preference.axaml @@ -57,7 +57,7 @@ - + - - - https://www.gravatar.com/avatar/ - https://cravatar.cn/avatar/ - - - - - - - - - + - - -