From 738daddbc7b561237016532a5826c04e6fab0a34 Mon Sep 17 00:00:00 2001 From: leo Date: Wed, 11 Oct 2023 18:23:33 +0800 Subject: [PATCH] feature: add context menu to manually re-fetch avatar --- src/Views/Controls/Avatar.cs | 101 ++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/src/Views/Controls/Avatar.cs b/src/Views/Controls/Avatar.cs index 9b5cfe6b..abbf0fa2 100644 --- a/src/Views/Controls/Avatar.cs +++ b/src/Views/Controls/Avatar.cs @@ -71,7 +71,9 @@ namespace SourceGit.Views.Controls { set { SetValue(FallbackLabelProperty, value); } } - private static Dictionary> requesting = new Dictionary>(); + private static event Action RefetchRequested; + private static event Action FetchCompleted; + private static Dictionary loaded = new Dictionary(); private static Task loader = null; @@ -79,23 +81,45 @@ namespace SourceGit.Views.Controls { private FormattedText label = null; public Avatar() { + RefetchRequested += email => { + if (email == Email) { + Source = null; + InvalidateVisual(); + } + }; + + FetchCompleted += email => { + if (email == Email) { + Source = loaded[Email]; + InvalidateVisual(); + } + }; + SetValue(RenderOptions.BitmapScalingModeProperty, BitmapScalingMode.HighQuality); SetValue(RenderOptions.ClearTypeHintProperty, ClearTypeHint.Auto); - Unloaded += (o, e) => Cancel(Email); + + var refetch = new MenuItem(); + refetch.Header = App.Text("Dashboard.Refresh"); + refetch.Click += (o, e) => Refetch(); + + ContextMenu = new ContextMenu(); + ContextMenu.Items.Add(refetch); } /// - /// 取消一个下载任务 + /// 手动刷新 /// - /// - private void Cancel(string email) { - if (!string.IsNullOrEmpty(email) && requesting.ContainsKey(email)) { - if (requesting[email].Count <= 1) { - requesting.Remove(email); - } else { - requesting[email].Remove(this); - } - } + private void Refetch() { + byte[] hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(Email.ToLower().Trim())); + string md5 = ""; + for (int i = 0; i < hash.Length; i++) md5 += hash[i].ToString("x2"); + md5 = md5.ToLower(); + string filePath = Path.Combine(CACHE_PATH, md5); + if (File.Exists(filePath)) File.Delete(filePath); + + RefetchRequested?.Invoke(Email); + if (loaded.ContainsKey(Email)) loaded.Remove(Email); + OnEmailChanged(this, new DependencyPropertyChangedEventArgs(EmailProperty, null, Email)); } /// @@ -146,6 +170,7 @@ namespace SourceGit.Views.Controls { var chars = placeholder.ToCharArray(); foreach (var ch in chars) a.colorIdx += Math.Abs(ch); a.colorIdx = a.colorIdx % BACKGROUND_BRUSHES.Length; + if (a.Source == null) a.InvalidateVisual(); } /// @@ -157,9 +182,10 @@ namespace SourceGit.Views.Controls { Avatar a = d as Avatar; if (a == null) return; - a.Cancel(e.OldValue as string); - a.Source = null; - a.InvalidateVisual(); + if (a.Source != null) { + a.Source = null; + a.InvalidateVisual(); + } var email = e.NewValue as string; if (string.IsNullOrEmpty(email)) return; @@ -169,11 +195,6 @@ namespace SourceGit.Views.Controls { return; } - if (requesting.ContainsKey(email)) { - requesting[email].Add(a); - return; - } - byte[] hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(email.ToLower().Trim())); string md5 = ""; for (int i = 0; i < hash.Length; i++) md5 += hash[i].ToString("x2"); @@ -181,18 +202,15 @@ namespace SourceGit.Views.Controls { string filePath = Path.Combine(CACHE_PATH, md5); if (File.Exists(filePath)) { - var img = new BitmapImage(new Uri(filePath)); + var img = LoadFromFile(filePath); loaded.Add(email, img); a.Source = img; return; } - requesting.Add(email, new List()); - requesting[email].Add(a); + loaded.Add(email, null); Action job = () => { - if (!requesting.ContainsKey(email)) return; - try { var req = WebRequest.CreateHttp($"https://cravatar.cn/avatar/{md5}?d=404"); req.Timeout = 2000; @@ -200,27 +218,18 @@ namespace SourceGit.Views.Controls { var rsp = req.GetResponse() as HttpWebResponse; if (rsp != null && rsp.StatusCode == HttpStatusCode.OK) { - using (var reader = rsp.GetResponseStream()) - using (var writer = File.OpenWrite(filePath)) { - reader.CopyTo(writer); - } + using (var reader = rsp.GetResponseStream()) { + using (var writer = File.OpenWrite(filePath)) { + reader.CopyTo(writer); + } + } a.Dispatcher.Invoke(() => { - var img = new BitmapImage(new Uri(filePath)); - loaded.Add(email, img); - - if (requesting.ContainsKey(email)) { - foreach (var one in requesting[email]) one.Source = img; - } + loaded[email] = LoadFromFile(filePath); + FetchCompleted?.Invoke(email); }); - } else { - if (!loaded.ContainsKey(email)) loaded.Add(email, null); } - } catch { - if (!loaded.ContainsKey(email)) loaded.Add(email, null); - } - - requesting.Remove(email); + } catch {} }; if (loader != null && !loader.IsCompleted) { @@ -229,5 +238,13 @@ namespace SourceGit.Views.Controls { loader = Task.Run(job); } } + + private static BitmapImage LoadFromFile(string file) { + var img = new BitmapImage(); + img.BeginInit(); + img.StreamSource = new MemoryStream(File.ReadAllBytes(file)); + img.EndInit(); + return img; + } } }