mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-11-01 13:13:21 -07:00
optimize<*>: remove deprecated apis (older than .NET 6)
This commit is contained in:
parent
890ff29ac7
commit
338f91357e
8 changed files with 677 additions and 749 deletions
|
@ -1,186 +1,178 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace SourceGit.Commands {
|
namespace SourceGit.Commands {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于取消命令执行的上下文对象
|
/// 用于取消命令执行的上下文对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Context {
|
public class Context {
|
||||||
public bool IsCancelRequested { get; set; } = false;
|
public bool IsCancelRequested { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 命令接口
|
/// 命令接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Command {
|
public class Command {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 读取全部输出时的结果
|
/// 读取全部输出时的结果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ReadToEndResult {
|
public class ReadToEndResult {
|
||||||
public bool IsSuccess { get; set; }
|
public bool IsSuccess { get; set; }
|
||||||
public string Output { get; set; }
|
public string Output { get; set; }
|
||||||
public string Error { get; set; }
|
public string Error { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上下文
|
/// 上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Context Ctx { get; set; } = null;
|
public Context Ctx { get; set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行路径
|
/// 运行路径
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Cwd { get; set; } = "";
|
public string Cwd { get; set; } = "";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参数
|
/// 参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Args { get; set; } = "";
|
public string Args { get; set; } = "";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否忽略错误
|
/// 是否忽略错误
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DontRaiseError { get; set; } = false;
|
public bool DontRaiseError { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用标准错误输出
|
/// 使用标准错误输出
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TraitErrorAsOutput { get; set; } = false;
|
public bool TraitErrorAsOutput { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于设置该进程独有的环境变量
|
/// 用于设置该进程独有的环境变量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, string> Envs { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> Envs { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行
|
/// 运行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exec() {
|
public bool Exec() {
|
||||||
var start = new ProcessStartInfo();
|
var start = new ProcessStartInfo();
|
||||||
start.FileName = Models.Preference.Instance.Git.Path;
|
start.FileName = Models.Preference.Instance.Git.Path;
|
||||||
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
|
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
|
||||||
start.UseShellExecute = false;
|
start.UseShellExecute = false;
|
||||||
start.CreateNoWindow = true;
|
start.CreateNoWindow = true;
|
||||||
start.RedirectStandardOutput = true;
|
start.RedirectStandardOutput = true;
|
||||||
start.RedirectStandardError = true;
|
start.RedirectStandardError = true;
|
||||||
start.StandardOutputEncoding = Encoding.UTF8;
|
start.StandardOutputEncoding = Encoding.UTF8;
|
||||||
start.StandardErrorEncoding = Encoding.UTF8;
|
start.StandardErrorEncoding = Encoding.UTF8;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Cwd)) start.WorkingDirectory = Cwd;
|
if (!string.IsNullOrEmpty(Cwd)) start.WorkingDirectory = Cwd;
|
||||||
|
|
||||||
foreach (var kv in Envs) start.EnvironmentVariables[kv.Key] = kv.Value;
|
foreach (var kv in Envs) start.EnvironmentVariables[kv.Key] = kv.Value;
|
||||||
|
|
||||||
var progressFilter = new Regex(@"\s\d+%\s");
|
var progressFilter = new Regex(@"\s\d+%\s");
|
||||||
var errs = new List<string>();
|
var errs = new List<string>();
|
||||||
var proc = new Process() { StartInfo = start };
|
var proc = new Process() { StartInfo = start };
|
||||||
var isCancelled = false;
|
var isCancelled = false;
|
||||||
|
|
||||||
proc.OutputDataReceived += (o, e) => {
|
proc.OutputDataReceived += (o, e) => {
|
||||||
if (Ctx != null && Ctx.IsCancelRequested) {
|
if (Ctx != null && Ctx.IsCancelRequested) {
|
||||||
isCancelled = true;
|
isCancelled = true;
|
||||||
proc.CancelErrorRead();
|
proc.CancelErrorRead();
|
||||||
proc.CancelOutputRead();
|
proc.CancelOutputRead();
|
||||||
#if NET48
|
if (!proc.HasExited) proc.Kill(true);
|
||||||
if (!proc.HasExited) proc.Kill();
|
return;
|
||||||
#else
|
}
|
||||||
if (!proc.HasExited) proc.Kill(true);
|
|
||||||
#endif
|
if (e.Data == null) return;
|
||||||
return;
|
OnReadline(e.Data);
|
||||||
}
|
};
|
||||||
|
proc.ErrorDataReceived += (o, e) => {
|
||||||
if (e.Data == null) return;
|
if (Ctx != null && Ctx.IsCancelRequested) {
|
||||||
OnReadline(e.Data);
|
isCancelled = true;
|
||||||
};
|
proc.CancelErrorRead();
|
||||||
proc.ErrorDataReceived += (o, e) => {
|
proc.CancelOutputRead();
|
||||||
if (Ctx != null && Ctx.IsCancelRequested) {
|
if (!proc.HasExited) proc.Kill(true);
|
||||||
isCancelled = true;
|
return;
|
||||||
proc.CancelErrorRead();
|
}
|
||||||
proc.CancelOutputRead();
|
|
||||||
#if NET48
|
if (string.IsNullOrEmpty(e.Data)) return;
|
||||||
if (!proc.HasExited) proc.Kill();
|
if (TraitErrorAsOutput) OnReadline(e.Data);
|
||||||
#else
|
|
||||||
if (!proc.HasExited) proc.Kill(true);
|
if (progressFilter.IsMatch(e.Data)) return;
|
||||||
#endif
|
if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal)) return;
|
||||||
return;
|
errs.Add(e.Data);
|
||||||
}
|
};
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(e.Data)) return;
|
try {
|
||||||
if (TraitErrorAsOutput) OnReadline(e.Data);
|
proc.Start();
|
||||||
|
} catch (Exception e) {
|
||||||
if (progressFilter.IsMatch(e.Data)) return;
|
if (!DontRaiseError) Models.Exception.Raise(e.Message);
|
||||||
if (e.Data.StartsWith("remote: Counting objects:", StringComparison.Ordinal)) return;
|
return false;
|
||||||
errs.Add(e.Data);
|
}
|
||||||
};
|
|
||||||
|
proc.BeginOutputReadLine();
|
||||||
try {
|
proc.BeginErrorReadLine();
|
||||||
proc.Start();
|
proc.WaitForExit();
|
||||||
} catch (Exception e) {
|
|
||||||
if (!DontRaiseError) Models.Exception.Raise(e.Message);
|
int exitCode = proc.ExitCode;
|
||||||
return false;
|
proc.Close();
|
||||||
}
|
|
||||||
|
if (!isCancelled && exitCode != 0 && errs.Count > 0) {
|
||||||
proc.BeginOutputReadLine();
|
if (!DontRaiseError) Models.Exception.Raise(string.Join("\n", errs));
|
||||||
proc.BeginErrorReadLine();
|
return false;
|
||||||
proc.WaitForExit();
|
} else {
|
||||||
|
return true;
|
||||||
int exitCode = proc.ExitCode;
|
}
|
||||||
proc.Close();
|
}
|
||||||
|
|
||||||
if (!isCancelled && exitCode != 0 && errs.Count > 0) {
|
/// <summary>
|
||||||
if (!DontRaiseError) Models.Exception.Raise(string.Join("\n", errs));
|
/// 直接读取全部标准输出
|
||||||
return false;
|
/// </summary>
|
||||||
} else {
|
public ReadToEndResult ReadToEnd() {
|
||||||
return true;
|
var start = new ProcessStartInfo();
|
||||||
}
|
start.FileName = Models.Preference.Instance.Git.Path;
|
||||||
}
|
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
|
||||||
|
start.UseShellExecute = false;
|
||||||
/// <summary>
|
start.CreateNoWindow = true;
|
||||||
/// 直接读取全部标准输出
|
start.RedirectStandardOutput = true;
|
||||||
/// </summary>
|
start.RedirectStandardError = true;
|
||||||
public ReadToEndResult ReadToEnd() {
|
start.StandardOutputEncoding = Encoding.UTF8;
|
||||||
var start = new ProcessStartInfo();
|
start.StandardErrorEncoding = Encoding.UTF8;
|
||||||
start.FileName = Models.Preference.Instance.Git.Path;
|
|
||||||
start.Arguments = "--no-pager -c core.quotepath=off " + Args;
|
if (!string.IsNullOrEmpty(Cwd)) start.WorkingDirectory = Cwd;
|
||||||
start.UseShellExecute = false;
|
|
||||||
start.CreateNoWindow = true;
|
var proc = new Process() { StartInfo = start };
|
||||||
start.RedirectStandardOutput = true;
|
try {
|
||||||
start.RedirectStandardError = true;
|
proc.Start();
|
||||||
start.StandardOutputEncoding = Encoding.UTF8;
|
} catch (Exception e) {
|
||||||
start.StandardErrorEncoding = Encoding.UTF8;
|
return new ReadToEndResult() {
|
||||||
|
Output = "",
|
||||||
if (!string.IsNullOrEmpty(Cwd)) start.WorkingDirectory = Cwd;
|
Error = e.Message,
|
||||||
|
IsSuccess = false,
|
||||||
var proc = new Process() { StartInfo = start };
|
};
|
||||||
try {
|
}
|
||||||
proc.Start();
|
|
||||||
} catch (Exception e) {
|
var rs = new ReadToEndResult();
|
||||||
return new ReadToEndResult() {
|
rs.Output = proc.StandardOutput.ReadToEnd();
|
||||||
Output = "",
|
rs.Error = proc.StandardError.ReadToEnd();
|
||||||
Error = e.Message,
|
|
||||||
IsSuccess = false,
|
proc.WaitForExit();
|
||||||
};
|
rs.IsSuccess = proc.ExitCode == 0;
|
||||||
}
|
proc.Close();
|
||||||
|
|
||||||
var rs = new ReadToEndResult();
|
return rs;
|
||||||
rs.Output = proc.StandardOutput.ReadToEnd();
|
}
|
||||||
rs.Error = proc.StandardError.ReadToEnd();
|
|
||||||
|
/// <summary>
|
||||||
proc.WaitForExit();
|
/// 调用Exec时的读取函数
|
||||||
rs.IsSuccess = proc.ExitCode == 0;
|
/// </summary>
|
||||||
proc.Close();
|
/// <param name="line"></param>
|
||||||
|
public virtual void OnReadline(string line) { }
|
||||||
return rs;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 调用Exec时的读取函数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="line"></param>
|
|
||||||
public virtual void OnReadline(string line) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,80 +1,69 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Net.Http;
|
||||||
#if NET6_0
|
|
||||||
using System.Net.Http;
|
namespace SourceGit.Models {
|
||||||
#else
|
|
||||||
using System.Net;
|
/// <summary>
|
||||||
using System.Text;
|
/// Github开放API中Release信息格式
|
||||||
#endif
|
/// </summary>
|
||||||
|
public class Version {
|
||||||
namespace SourceGit.Models {
|
[JsonPropertyName("id")]
|
||||||
|
public ulong Id { get; set; }
|
||||||
/// <summary>
|
[JsonPropertyName("tag_name")]
|
||||||
/// Github开放API中Release信息格式
|
public string TagName { get; set; }
|
||||||
/// </summary>
|
[JsonPropertyName("target_commitish")]
|
||||||
public class Version {
|
public string CommitSHA { get; set; }
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("prerelease")]
|
||||||
public ulong Id { get; set; }
|
public bool PreRelease { get; set; }
|
||||||
[JsonPropertyName("tag_name")]
|
[JsonPropertyName("name")]
|
||||||
public string TagName { get; set; }
|
public string Name { get; set; }
|
||||||
[JsonPropertyName("target_commitish")]
|
[JsonPropertyName("body")]
|
||||||
public string CommitSHA { get; set; }
|
public string Body { get; set; }
|
||||||
[JsonPropertyName("prerelease")]
|
[JsonPropertyName("created_at")]
|
||||||
public bool PreRelease { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
[JsonPropertyName("name")]
|
|
||||||
public string Name { get; set; }
|
public string PublishTime {
|
||||||
[JsonPropertyName("body")]
|
get { return CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); }
|
||||||
public string Body { get; set; }
|
}
|
||||||
[JsonPropertyName("created_at")]
|
|
||||||
public DateTime CreatedAt { get; set; }
|
public string IsPrerelease {
|
||||||
|
get { return PreRelease ? "YES" : "NO"; }
|
||||||
public string PublishTime {
|
}
|
||||||
get { return CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); }
|
|
||||||
}
|
public static void Check(Action<Version> onUpgradable) {
|
||||||
|
if (!Preference.Instance.General.CheckForUpdate) return;
|
||||||
public string IsPrerelease {
|
|
||||||
get { return PreRelease ? "YES" : "NO"; }
|
var curDayOfYear = DateTime.Now.DayOfYear;
|
||||||
}
|
var lastDayOfYear = Preference.Instance.General.LastCheckDay;
|
||||||
|
if (lastDayOfYear != curDayOfYear) {
|
||||||
public static void Check(Action<Version> onUpgradable) {
|
Preference.Instance.General.LastCheckDay = curDayOfYear;
|
||||||
if (!Preference.Instance.General.CheckForUpdate) return;
|
Task.Run(async () => {
|
||||||
|
try {
|
||||||
var curDayOfYear = DateTime.Now.DayOfYear;
|
var req = new HttpClient();
|
||||||
var lastDayOfYear = Preference.Instance.General.LastCheckDay;
|
var rsp = await req.GetAsync("https://api.github.com/repos/sourcegit-scm/sourcegit/releases/latest");
|
||||||
if (lastDayOfYear != curDayOfYear) {
|
rsp.EnsureSuccessStatusCode();
|
||||||
Preference.Instance.General.LastCheckDay = curDayOfYear;
|
|
||||||
Task.Run(async () => {
|
var raw = await rsp.Content.ReadAsStringAsync();
|
||||||
try {
|
var ver = JsonSerializer.Deserialize<Version>(raw);
|
||||||
#if NET6_0
|
var cur = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
var req = new HttpClient();
|
|
||||||
var rsp = await req.GetAsync("https://api.github.com/repos/sourcegit-scm/sourcegit/releases/latest");
|
var matches = Regex.Match(ver.TagName, @"^v(\d+)\.(\d+).*");
|
||||||
rsp.EnsureSuccessStatusCode();
|
if (!matches.Success) return;
|
||||||
|
|
||||||
var raw = await rsp.Content.ReadAsStringAsync();
|
var major = int.Parse(matches.Groups[1].Value);
|
||||||
#else
|
var minor = int.Parse(matches.Groups[2].Value);
|
||||||
var web = new WebClient() { Encoding = Encoding.UTF8 };
|
if (major > cur.Major || (major == cur.Major && minor > cur.Minor)) {
|
||||||
var raw = await web.DownloadStringTaskAsync("https://api.github.com/repos/sourcegit-scm/sourcegit/releases/latest");
|
onUpgradable?.Invoke(ver);
|
||||||
#endif
|
}
|
||||||
var ver = JsonSerializer.Deserialize<Version>(raw);
|
} catch {
|
||||||
var cur = Assembly.GetExecutingAssembly().GetName().Version;
|
}
|
||||||
|
});
|
||||||
var matches = Regex.Match(ver.TagName, @"^v(\d+)\.(\d+).*");
|
}
|
||||||
if (!matches.Success) return;
|
}
|
||||||
|
}
|
||||||
var major = int.Parse(matches.Groups[1].Value);
|
}
|
||||||
var minor = int.Parse(matches.Groups[2].Value);
|
|
||||||
if (major > cur.Major || (major == cur.Major && minor > cur.Minor)) {
|
|
||||||
onUpgradable?.Invoke(ver);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,124 +1,124 @@
|
||||||
<controls:Window
|
<controls:Window
|
||||||
x:Class="SourceGit.Views.About"
|
x:Class="SourceGit.Views.About"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:controls="clr-namespace:SourceGit.Views.Controls"
|
xmlns:controls="clr-namespace:SourceGit.Views.Controls"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
Title="{DynamicResource Text.About}"
|
Title="{DynamicResource Text.About}"
|
||||||
Width="420" SizeToContent="Height"
|
Width="420" SizeToContent="Height"
|
||||||
ResizeMode="NoResize">
|
ResizeMode="NoResize">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="28"/>
|
<RowDefinition Height="28"/>
|
||||||
<RowDefinition Height="1"/>
|
<RowDefinition Height="1"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Title bar -->
|
<!-- Title bar -->
|
||||||
<Grid Grid.Row="0" Background="{DynamicResource Brush.TitleBar}">
|
<Grid Grid.Row="0" Background="{DynamicResource Brush.TitleBar}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Icon -->
|
<!-- Icon -->
|
||||||
<Path Grid.Column="0" Margin="6,0" Width="16" Height="16" Data="{StaticResource Icon.Help}"/>
|
<Path Grid.Column="0" Margin="6,0" Width="16" Height="16" Data="{StaticResource Icon.Help}"/>
|
||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<TextBlock Grid.Column="1" Text="{DynamicResource Text.About}"/>
|
<TextBlock Grid.Column="1" Text="{DynamicResource Text.About}"/>
|
||||||
|
|
||||||
<!-- Close -->
|
<!-- Close -->
|
||||||
<controls:IconButton
|
<controls:IconButton
|
||||||
Grid.Column="3"
|
Grid.Column="3"
|
||||||
Click="Quit"
|
Click="Quit"
|
||||||
Width="28"
|
Width="28"
|
||||||
Padding="8"
|
Padding="8"
|
||||||
Icon="{StaticResource Icon.Close}"
|
Icon="{StaticResource Icon.Close}"
|
||||||
HoverBackground="Red"
|
HoverBackground="Red"
|
||||||
WindowChrome.IsHitTestVisibleInChrome="True"/>
|
WindowChrome.IsHitTestVisibleInChrome="True"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Rectangle
|
<Rectangle
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Height="1"
|
Height="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Fill="{DynamicResource Brush.Border0}"/>
|
Fill="{DynamicResource Brush.Border0}"/>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<StackPanel Grid.Row="2" Orientation="Vertical">
|
<StackPanel Grid.Row="2" Orientation="Vertical">
|
||||||
|
|
||||||
<!-- LOGO -->
|
<!-- LOGO -->
|
||||||
<Path
|
<Path
|
||||||
Margin="0,16,0,0"
|
Margin="0,16,0,0"
|
||||||
Width="64" Height="64"
|
Width="64" Height="64"
|
||||||
Data="{StaticResource Icon.Git}"
|
Data="{StaticResource Icon.Git}"
|
||||||
Fill="{DynamicResource Brush.Logo}"/>
|
Fill="{DynamicResource Brush.Logo}"/>
|
||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,24,0,8"
|
Margin="0,24,0,8"
|
||||||
Text="{DynamicResource Text.About.Title}"
|
Text="{DynamicResource Text.About.Title}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
FontSize="18"/>
|
FontSize="18"/>
|
||||||
|
|
||||||
<!-- Version -->
|
<!-- Version -->
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="version"
|
x:Name="version"
|
||||||
Margin="0,0,0,8"
|
Margin="0,0,0,8"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
FontSize="11"
|
FontSize="11"
|
||||||
Text="VERSION: v1.0 .NET: v5.0"/>
|
Text="VERSION: v1.0"/>
|
||||||
|
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="hotkeys"
|
x:Name="hotkeys"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="16,8"
|
Margin="16,8"
|
||||||
Background="{DynamicResource Brush.Contents}"
|
Background="{DynamicResource Brush.Contents}"
|
||||||
GridLinesVisibility="All"
|
GridLinesVisibility="All"
|
||||||
HorizontalGridLinesBrush="{DynamicResource Brush.Border0}"
|
HorizontalGridLinesBrush="{DynamicResource Brush.Border0}"
|
||||||
VerticalGridLinesBrush="{DynamicResource Brush.Border0}"
|
VerticalGridLinesBrush="{DynamicResource Brush.Border0}"
|
||||||
HeadersVisibility="Column"
|
HeadersVisibility="Column"
|
||||||
RowHeight="24"
|
RowHeight="24"
|
||||||
ColumnHeaderHeight="24"
|
ColumnHeaderHeight="24"
|
||||||
IsHitTestVisible="False"
|
IsHitTestVisible="False"
|
||||||
BorderThickness="1,1,0,0"
|
BorderThickness="1,1,0,0"
|
||||||
BorderBrush="{DynamicResource Brush.Border0}">
|
BorderBrush="{DynamicResource Brush.Border0}">
|
||||||
<DataGrid.ColumnHeaderStyle>
|
<DataGrid.ColumnHeaderStyle>
|
||||||
<Style TargetType="{x:Type DataGridColumnHeader}">
|
<Style TargetType="{x:Type DataGridColumnHeader}">
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
|
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
|
||||||
<Border BorderThickness="0,0,1,1" BorderBrush="{DynamicResource Brush.Border0}" Background="{DynamicResource Brush.Window}">
|
<Border BorderThickness="0,0,1,1" BorderBrush="{DynamicResource Brush.Border0}" Background="{DynamicResource Brush.Window}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Text="{TemplateBinding Content}"
|
Text="{TemplateBinding Content}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontWeight="DemiBold"/>
|
FontWeight="DemiBold"/>
|
||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</DataGrid.ColumnHeaderStyle>
|
</DataGrid.ColumnHeaderStyle>
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Width="100" Header="{DynamicResource Text.Hotkeys.Col.Key}" Binding="{Binding .Key}" ElementStyle="{StaticResource Style.TextBlock.LineContent}"/>
|
<DataGridTextColumn Width="100" Header="{DynamicResource Text.Hotkeys.Col.Key}" Binding="{Binding .Key}" ElementStyle="{StaticResource Style.TextBlock.LineContent}"/>
|
||||||
<DataGridTextColumn Width="*" Header="{DynamicResource Text.Hotkeys.Col.Desc}" Binding="{Binding .Desc}" ElementStyle="{StaticResource Style.TextBlock.LineContent}"/>
|
<DataGridTextColumn Width="*" Header="{DynamicResource Text.Hotkeys.Col.Desc}" Binding="{Binding .Desc}" ElementStyle="{StaticResource Style.TextBlock.LineContent}"/>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
<!-- Official site -->
|
<!-- Official site -->
|
||||||
<TextBlock HorizontalAlignment="Center" Margin="0,4,0,16">
|
<TextBlock HorizontalAlignment="Center" Margin="0,4,0,16">
|
||||||
<TextBlock Text="© 2021" Margin="0" Padding="0"/>
|
<TextBlock Text="© 2021" Margin="0" Padding="0"/>
|
||||||
<Hyperlink NavigateUri="https://github.com/sourcegit-scm/sourcegit.git" RequestNavigate="OnRequestNavigate" ToolTip="https://github.com/sourcegit-scm/sourcegit.git">
|
<Hyperlink NavigateUri="https://github.com/sourcegit-scm/sourcegit.git" RequestNavigate="OnRequestNavigate" ToolTip="https://github.com/sourcegit-scm/sourcegit.git">
|
||||||
<Run Text="SourceGit."/>
|
<Run Text="SourceGit."/>
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
<TextBlock Text="All rights reserved." Margin="0" Padding="0"/>
|
<TextBlock Text="All rights reserved." Margin="0" Padding="0"/>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</controls:Window>
|
</controls:Window>
|
||||||
|
|
|
@ -1,55 +1,48 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace SourceGit.Views {
|
namespace SourceGit.Views {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 关于对话框
|
/// 关于对话框
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class About : Controls.Window {
|
public partial class About : Controls.Window {
|
||||||
|
|
||||||
public class Keymap {
|
public class Keymap {
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
public string Desc { get; set; }
|
public string Desc { get; set; }
|
||||||
public Keymap(string k, string d) { Key = k; Desc = App.Text($"Hotkeys.{d}"); }
|
public Keymap(string k, string d) { Key = k; Desc = App.Text($"Hotkeys.{d}"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public About() {
|
public About() {
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
var asm = Assembly.GetExecutingAssembly().GetName();
|
var asm = Assembly.GetExecutingAssembly().GetName();
|
||||||
var framework = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
|
version.Text = $"VERSION : v{asm.Version.Major}.{asm.Version.Minor}";
|
||||||
var dotnetVer = framework.Substring(framework.IndexOf("=") + 1);
|
|
||||||
|
hotkeys.ItemsSource = new List<Keymap>() {
|
||||||
version.Text = $"VERSION : v{asm.Version.Major}.{asm.Version.Minor} .NET : {dotnetVer}";
|
new Keymap("CTRL + T", "NewTab"),
|
||||||
|
new Keymap("CTRL + W", "CloseTab"),
|
||||||
hotkeys.ItemsSource = new List<Keymap>() {
|
new Keymap("CTRL + TAB", "NextTab"),
|
||||||
new Keymap("CTRL + T", "NewTab"),
|
new Keymap("CTRL + [1-9]", "SwitchTo"),
|
||||||
new Keymap("CTRL + W", "CloseTab"),
|
new Keymap("CTRL + F", "Search"),
|
||||||
new Keymap("CTRL + TAB", "NextTab"),
|
new Keymap("F5", "Refresh"),
|
||||||
new Keymap("CTRL + [1-9]", "SwitchTo"),
|
new Keymap("SPACE", "ToggleStage"),
|
||||||
new Keymap("CTRL + F", "Search"),
|
new Keymap("ESC", "CancelPopup"),
|
||||||
new Keymap("F5", "Refresh"),
|
};
|
||||||
new Keymap("SPACE", "ToggleStage"),
|
}
|
||||||
new Keymap("ESC", "CancelPopup"),
|
|
||||||
};
|
private void OnRequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) {
|
||||||
}
|
var info = new ProcessStartInfo("cmd", $"/c start {e.Uri.AbsoluteUri}");
|
||||||
|
info.CreateNoWindow = true;
|
||||||
private void OnRequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) {
|
Process.Start(info);
|
||||||
#if NET48
|
}
|
||||||
Process.Start(e.Uri.AbsoluteUri);
|
|
||||||
#else
|
private void Quit(object sender, RoutedEventArgs e) {
|
||||||
var info = new ProcessStartInfo("cmd", $"/c start {e.Uri.AbsoluteUri}");
|
Close();
|
||||||
info.CreateNoWindow = true;
|
}
|
||||||
Process.Start(info);
|
}
|
||||||
#endif
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void Quit(object sender, RoutedEventArgs e) {
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,258 +1,230 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Net.Http;
|
||||||
#if NET6_0
|
|
||||||
using System.Net.Http;
|
namespace SourceGit.Views.Controls {
|
||||||
#endif
|
|
||||||
|
/// <summary>
|
||||||
namespace SourceGit.Views.Controls {
|
/// 头像控件
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public class Avatar : Image {
|
||||||
/// 头像控件
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public class Avatar : Image {
|
/// 显示FallbackLabel时的背景色
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
private static readonly Brush[] BACKGROUND_BRUSHES = new Brush[] {
|
||||||
/// 显示FallbackLabel时的背景色
|
new LinearGradientBrush(Colors.Orange, Color.FromRgb(255, 213, 134), 90),
|
||||||
/// </summary>
|
new LinearGradientBrush(Colors.DodgerBlue, Colors.LightSkyBlue, 90),
|
||||||
private static readonly Brush[] BACKGROUND_BRUSHES = new Brush[] {
|
new LinearGradientBrush(Colors.LimeGreen, Color.FromRgb(124, 241, 124), 90),
|
||||||
new LinearGradientBrush(Colors.Orange, Color.FromRgb(255, 213, 134), 90),
|
new LinearGradientBrush(Colors.Orchid, Color.FromRgb(248, 161, 245), 90),
|
||||||
new LinearGradientBrush(Colors.DodgerBlue, Colors.LightSkyBlue, 90),
|
new LinearGradientBrush(Colors.Tomato, Color.FromRgb(252, 165, 150), 90),
|
||||||
new LinearGradientBrush(Colors.LimeGreen, Color.FromRgb(124, 241, 124), 90),
|
};
|
||||||
new LinearGradientBrush(Colors.Orchid, Color.FromRgb(248, 161, 245), 90),
|
|
||||||
new LinearGradientBrush(Colors.Tomato, Color.FromRgb(252, 165, 150), 90),
|
/// <summary>
|
||||||
};
|
/// 头像资源本地缓存路径
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public static readonly string CACHE_PATH = Path.Combine(
|
||||||
/// 头像资源本地缓存路径
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
/// </summary>
|
"SourceGit",
|
||||||
public static readonly string CACHE_PATH = Path.Combine(
|
"avatars");
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
||||||
"SourceGit",
|
/// <summary>
|
||||||
"avatars");
|
/// 邮件属性定义
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public static readonly DependencyProperty EmailProperty = DependencyProperty.Register(
|
||||||
/// 邮件属性定义
|
"Email",
|
||||||
/// </summary>
|
typeof(string),
|
||||||
public static readonly DependencyProperty EmailProperty = DependencyProperty.Register(
|
typeof(Avatar),
|
||||||
"Email",
|
new PropertyMetadata(null, OnEmailChanged));
|
||||||
typeof(string),
|
|
||||||
typeof(Avatar),
|
/// <summary>
|
||||||
new PropertyMetadata(null, OnEmailChanged));
|
/// 邮件属性
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public string Email {
|
||||||
/// 邮件属性
|
get { return (string)GetValue(EmailProperty); }
|
||||||
/// </summary>
|
set { SetValue(EmailProperty, value); }
|
||||||
public string Email {
|
}
|
||||||
get { return (string)GetValue(EmailProperty); }
|
|
||||||
set { SetValue(EmailProperty, value); }
|
/// <summary>
|
||||||
}
|
/// 下载头像失败时显示的Label属性定义
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public static readonly DependencyProperty FallbackLabelProperty = DependencyProperty.Register(
|
||||||
/// 下载头像失败时显示的Label属性定义
|
"FallbackLabel",
|
||||||
/// </summary>
|
typeof(string),
|
||||||
public static readonly DependencyProperty FallbackLabelProperty = DependencyProperty.Register(
|
typeof(Avatar),
|
||||||
"FallbackLabel",
|
new PropertyMetadata("?", OnFallbackLabelChanged));
|
||||||
typeof(string),
|
|
||||||
typeof(Avatar),
|
/// <summary>
|
||||||
new PropertyMetadata("?", OnFallbackLabelChanged));
|
/// 下载头像失败时显示的Label属性
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public string FallbackLabel {
|
||||||
/// 下载头像失败时显示的Label属性
|
get { return (string)GetValue(FallbackLabelProperty); }
|
||||||
/// </summary>
|
set { SetValue(FallbackLabelProperty, value); }
|
||||||
public string FallbackLabel {
|
}
|
||||||
get { return (string)GetValue(FallbackLabelProperty); }
|
|
||||||
set { SetValue(FallbackLabelProperty, value); }
|
private static Dictionary<string, List<Avatar>> requesting = new Dictionary<string, List<Avatar>>();
|
||||||
}
|
private static Dictionary<string, BitmapImage> loaded = new Dictionary<string, BitmapImage>();
|
||||||
|
private static Task loader = null;
|
||||||
private static Dictionary<string, List<Avatar>> requesting = new Dictionary<string, List<Avatar>>();
|
|
||||||
private static Dictionary<string, BitmapImage> loaded = new Dictionary<string, BitmapImage>();
|
private int colorIdx = 0;
|
||||||
private static Task loader = null;
|
private FormattedText label = null;
|
||||||
|
|
||||||
private int colorIdx = 0;
|
public Avatar() {
|
||||||
private FormattedText label = null;
|
SetValue(RenderOptions.BitmapScalingModeProperty, BitmapScalingMode.HighQuality);
|
||||||
|
SetValue(RenderOptions.ClearTypeHintProperty, ClearTypeHint.Auto);
|
||||||
public Avatar() {
|
Unloaded += (o, e) => Cancel(Email);
|
||||||
SetValue(RenderOptions.BitmapScalingModeProperty, BitmapScalingMode.HighQuality);
|
}
|
||||||
SetValue(RenderOptions.ClearTypeHintProperty, ClearTypeHint.Auto);
|
|
||||||
Unloaded += (o, e) => Cancel(Email);
|
/// <summary>
|
||||||
}
|
/// 取消一个下载任务
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="email"></param>
|
||||||
/// 取消一个下载任务
|
private void Cancel(string email) {
|
||||||
/// </summary>
|
if (!string.IsNullOrEmpty(email) && requesting.ContainsKey(email)) {
|
||||||
/// <param name="email"></param>
|
if (requesting[email].Count <= 1) {
|
||||||
private void Cancel(string email) {
|
requesting.Remove(email);
|
||||||
if (!string.IsNullOrEmpty(email) && requesting.ContainsKey(email)) {
|
} else {
|
||||||
if (requesting[email].Count <= 1) {
|
requesting[email].Remove(this);
|
||||||
requesting.Remove(email);
|
}
|
||||||
} else {
|
}
|
||||||
requesting[email].Remove(this);
|
}
|
||||||
}
|
|
||||||
}
|
/// <summary>
|
||||||
}
|
/// 渲染实现
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="dc"></param>
|
||||||
/// 渲染实现
|
protected override void OnRender(DrawingContext dc) {
|
||||||
/// </summary>
|
base.OnRender(dc);
|
||||||
/// <param name="dc"></param>
|
|
||||||
protected override void OnRender(DrawingContext dc) {
|
if (Source == null && label != null) {
|
||||||
base.OnRender(dc);
|
var corner = Math.Max(2, Width / 16);
|
||||||
|
var offsetX = (double)0;
|
||||||
if (Source == null && label != null) {
|
if (HorizontalAlignment == HorizontalAlignment.Right) {
|
||||||
var corner = Math.Max(2, Width / 16);
|
offsetX = -Width * 0.5;
|
||||||
var offsetX = (double)0;
|
} else if (HorizontalAlignment == HorizontalAlignment.Left) {
|
||||||
if (HorizontalAlignment == HorizontalAlignment.Right) {
|
offsetX = Width * 0.5;
|
||||||
offsetX = -Width * 0.5;
|
}
|
||||||
} else if (HorizontalAlignment == HorizontalAlignment.Left) {
|
|
||||||
offsetX = Width * 0.5;
|
Brush brush = BACKGROUND_BRUSHES[colorIdx];
|
||||||
}
|
dc.DrawRoundedRectangle(brush, null, new Rect(-Width * 0.5 + offsetX, -Height * 0.5, Width, Height), corner, corner);
|
||||||
|
dc.DrawText(label, new Point(label.Width * -0.5 + offsetX, label.Height * -0.5));
|
||||||
Brush brush = BACKGROUND_BRUSHES[colorIdx];
|
}
|
||||||
dc.DrawRoundedRectangle(brush, null, new Rect(-Width * 0.5 + offsetX, -Height * 0.5, Width, Height), corner, corner);
|
}
|
||||||
dc.DrawText(label, new Point(label.Width * -0.5 + offsetX, label.Height * -0.5));
|
|
||||||
}
|
/// <summary>
|
||||||
}
|
/// 显示文本变化时触发
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="d"></param>
|
||||||
/// 显示文本变化时触发
|
/// <param name="e"></param>
|
||||||
/// </summary>
|
private static void OnFallbackLabelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
|
||||||
/// <param name="d"></param>
|
Avatar a = d as Avatar;
|
||||||
/// <param name="e"></param>
|
if (a == null) return;
|
||||||
private static void OnFallbackLabelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
|
|
||||||
Avatar a = d as Avatar;
|
var placeholder = a.FallbackLabel.Length > 0 ? a.FallbackLabel.Substring(0, 1) : "?";
|
||||||
if (a == null) return;
|
|
||||||
|
a.colorIdx = 0;
|
||||||
var placeholder = a.FallbackLabel.Length > 0 ? a.FallbackLabel.Substring(0, 1) : "?";
|
a.label = new FormattedText(
|
||||||
|
placeholder,
|
||||||
a.colorIdx = 0;
|
CultureInfo.CurrentCulture,
|
||||||
a.label = new FormattedText(
|
FlowDirection.LeftToRight,
|
||||||
placeholder,
|
new Typeface(new FontFamily(Models.Preference.Instance.General.FontFamilyWindow), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
|
||||||
CultureInfo.CurrentCulture,
|
a.Width * 0.65,
|
||||||
FlowDirection.LeftToRight,
|
Brushes.White,
|
||||||
new Typeface(new FontFamily(Models.Preference.Instance.General.FontFamilyWindow), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
|
VisualTreeHelper.GetDpi(a).PixelsPerDip);
|
||||||
a.Width * 0.65,
|
|
||||||
Brushes.White,
|
var chars = placeholder.ToCharArray();
|
||||||
VisualTreeHelper.GetDpi(a).PixelsPerDip);
|
foreach (var ch in chars) a.colorIdx += Math.Abs(ch);
|
||||||
|
a.colorIdx = a.colorIdx % BACKGROUND_BRUSHES.Length;
|
||||||
var chars = placeholder.ToCharArray();
|
}
|
||||||
foreach (var ch in chars) a.colorIdx += Math.Abs(ch);
|
|
||||||
a.colorIdx = a.colorIdx % BACKGROUND_BRUSHES.Length;
|
/// <summary>
|
||||||
}
|
/// 邮件变化时触发
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="d"></param>
|
||||||
/// 邮件变化时触发
|
/// <param name="e"></param>
|
||||||
/// </summary>
|
private static void OnEmailChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
|
||||||
/// <param name="d"></param>
|
Avatar a = d as Avatar;
|
||||||
/// <param name="e"></param>
|
if (a == null) return;
|
||||||
private static void OnEmailChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
|
|
||||||
Avatar a = d as Avatar;
|
a.Cancel(e.OldValue as string);
|
||||||
if (a == null) return;
|
a.Source = null;
|
||||||
|
a.InvalidateVisual();
|
||||||
a.Cancel(e.OldValue as string);
|
|
||||||
a.Source = null;
|
var email = e.NewValue as string;
|
||||||
a.InvalidateVisual();
|
if (string.IsNullOrEmpty(email)) return;
|
||||||
|
|
||||||
var email = e.NewValue as string;
|
if (loaded.ContainsKey(email)) {
|
||||||
if (string.IsNullOrEmpty(email)) return;
|
a.Source = loaded[email];
|
||||||
|
return;
|
||||||
if (loaded.ContainsKey(email)) {
|
}
|
||||||
a.Source = loaded[email];
|
|
||||||
return;
|
if (requesting.ContainsKey(email)) {
|
||||||
}
|
requesting[email].Add(a);
|
||||||
|
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");
|
||||||
byte[] hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(email.ToLower().Trim()));
|
md5 = md5.ToLower();
|
||||||
string md5 = "";
|
|
||||||
for (int i = 0; i < hash.Length; i++) md5 += hash[i].ToString("x2");
|
string filePath = Path.Combine(CACHE_PATH, md5);
|
||||||
md5 = md5.ToLower();
|
if (File.Exists(filePath)) {
|
||||||
|
var img = new BitmapImage(new Uri(filePath));
|
||||||
string filePath = Path.Combine(CACHE_PATH, md5);
|
loaded.Add(email, img);
|
||||||
if (File.Exists(filePath)) {
|
a.Source = img;
|
||||||
var img = new BitmapImage(new Uri(filePath));
|
return;
|
||||||
loaded.Add(email, img);
|
}
|
||||||
a.Source = img;
|
|
||||||
return;
|
requesting.Add(email, new List<Avatar>());
|
||||||
}
|
requesting[email].Add(a);
|
||||||
|
|
||||||
requesting.Add(email, new List<Avatar>());
|
Action job = () => {
|
||||||
requesting[email].Add(a);
|
if (!requesting.ContainsKey(email)) return;
|
||||||
|
|
||||||
Action job = () => {
|
try {
|
||||||
if (!requesting.ContainsKey(email)) return;
|
var req = new HttpClient().GetAsync(Models.Preference.Instance.General.AvatarServer + md5 + "?d=404");
|
||||||
|
req.Wait();
|
||||||
try {
|
|
||||||
#if NET6_0
|
var rsp = req.Result;
|
||||||
var req = new HttpClient().GetAsync(Models.Preference.Instance.General.AvatarServer + md5 + "?d=404");
|
if (rsp != null && rsp.StatusCode == HttpStatusCode.OK) {
|
||||||
req.Wait();
|
var writer = File.OpenWrite(filePath);
|
||||||
|
rsp.Content.CopyToAsync(writer).Wait();
|
||||||
var rsp = req.Result;
|
writer.Close();
|
||||||
if (rsp != null && rsp.StatusCode == HttpStatusCode.OK) {
|
|
||||||
var writer = File.OpenWrite(filePath);
|
a.Dispatcher.Invoke(() => {
|
||||||
rsp.Content.CopyToAsync(writer).Wait();
|
var img = new BitmapImage(new Uri(filePath));
|
||||||
writer.Close();
|
loaded.Add(email, img);
|
||||||
|
|
||||||
a.Dispatcher.Invoke(() => {
|
if (requesting.ContainsKey(email)) {
|
||||||
var img = new BitmapImage(new Uri(filePath));
|
foreach (var one in requesting[email]) one.Source = img;
|
||||||
loaded.Add(email, img);
|
}
|
||||||
|
});
|
||||||
if (requesting.ContainsKey(email)) {
|
} else {
|
||||||
foreach (var one in requesting[email]) one.Source = img;
|
if (!loaded.ContainsKey(email)) loaded.Add(email, null);
|
||||||
}
|
}
|
||||||
});
|
} catch {
|
||||||
} else {
|
if (!loaded.ContainsKey(email)) loaded.Add(email, null);
|
||||||
if (!loaded.ContainsKey(email)) loaded.Add(email, null);
|
}
|
||||||
}
|
|
||||||
#else
|
requesting.Remove(email);
|
||||||
HttpWebRequest req = WebRequest.CreateHttp(Models.Preference.Instance.General.AvatarServer + md5 + "?d=404");
|
};
|
||||||
req.Timeout = 2000;
|
|
||||||
req.Method = "GET";
|
if (loader != null && !loader.IsCompleted) {
|
||||||
|
loader = loader.ContinueWith(t => { job(); });
|
||||||
HttpWebResponse rsp = req.GetResponse() as HttpWebResponse;
|
} else {
|
||||||
if (rsp.StatusCode == HttpStatusCode.OK) {
|
loader = Task.Run(job);
|
||||||
using (Stream reader = rsp.GetResponseStream())
|
}
|
||||||
using (FileStream 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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!loaded.ContainsKey(email)) loaded.Add(email, null);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} catch {
|
|
||||||
if (!loaded.ContainsKey(email)) loaded.Add(email, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
requesting.Remove(email);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loader != null && !loader.IsCompleted) {
|
|
||||||
loader = loader.ContinueWith(t => { job(); });
|
|
||||||
} else {
|
|
||||||
loader = Task.Run(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,32 +1,28 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace SourceGit.Views {
|
namespace SourceGit.Views {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 新版本提示窗口
|
/// 新版本提示窗口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class Upgrade : Controls.Window {
|
public partial class Upgrade : Controls.Window {
|
||||||
public Models.Version Version { get; set; } = new Models.Version();
|
public Models.Version Version { get; set; } = new Models.Version();
|
||||||
|
|
||||||
public Upgrade(Models.Version ver) {
|
public Upgrade(Models.Version ver) {
|
||||||
Version = ver;
|
Version = ver;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
txtRelease.Text = App.Text("UpdateAvailable.Title", ver.Name);
|
txtRelease.Text = App.Text("UpdateAvailable.Title", ver.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Download(object sender, RoutedEventArgs e) {
|
private void Download(object sender, RoutedEventArgs e) {
|
||||||
var url = $"https://github.com/sourcegit-scm/sourcegit/releases/{Version.TagName}";
|
var url = $"https://github.com/sourcegit-scm/sourcegit/releases/{Version.TagName}";
|
||||||
#if NET48
|
var info = new ProcessStartInfo("cmd", $"/c start {url}");
|
||||||
Process.Start(url);
|
info.CreateNoWindow = true;
|
||||||
#else
|
Process.Start(info);
|
||||||
var info = new ProcessStartInfo("cmd", $"/c start {url}");
|
}
|
||||||
info.CreateNoWindow = true;
|
|
||||||
Process.Start(info);
|
private void Quit(object sender, RoutedEventArgs e) {
|
||||||
#endif
|
Close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private void Quit(object sender, RoutedEventArgs e) {
|
}
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -72,15 +72,6 @@ namespace SourceGit.Views.Widgets {
|
||||||
} else {
|
} else {
|
||||||
searching = true;
|
searching = true;
|
||||||
foreach (var c in cachedCommits) {
|
foreach (var c in cachedCommits) {
|
||||||
#if NET48
|
|
||||||
if (c.SHA.Contains(filter)
|
|
||||||
|| c.Subject.Contains(filter)
|
|
||||||
|| c.Message.Contains(filter)
|
|
||||||
|| c.Author.Name.Contains(filter)
|
|
||||||
|| c.Committer.Name.Contains(filter)) {
|
|
||||||
visible.Add(c);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (c.SHA.Contains(filter, StringComparison.Ordinal)
|
if (c.SHA.Contains(filter, StringComparison.Ordinal)
|
||||||
|| c.Subject.Contains(filter, StringComparison.Ordinal)
|
|| c.Subject.Contains(filter, StringComparison.Ordinal)
|
||||||
|| c.Message.Contains(filter, StringComparison.Ordinal)
|
|| c.Message.Contains(filter, StringComparison.Ordinal)
|
||||||
|
@ -88,7 +79,6 @@ namespace SourceGit.Views.Widgets {
|
||||||
|| c.Committer.Name.Contains(filter, StringComparison.Ordinal)) {
|
|| c.Committer.Name.Contains(filter, StringComparison.Ordinal)) {
|
||||||
visible.Add(c);
|
visible.Add(c);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,11 +215,7 @@ namespace SourceGit.Views.Widgets {
|
||||||
|
|
||||||
if (!added) Changes.Add(c);
|
if (!added) Changes.Add(c);
|
||||||
|
|
||||||
#if NET48
|
|
||||||
int sepIdx = c.Path.IndexOf("/", StringComparison.Ordinal);
|
|
||||||
#else
|
|
||||||
int sepIdx = c.Path.IndexOf('/', StringComparison.Ordinal);
|
int sepIdx = c.Path.IndexOf('/', StringComparison.Ordinal);
|
||||||
#endif
|
|
||||||
if (sepIdx < 0) {
|
if (sepIdx < 0) {
|
||||||
GetOrAddTreeNode(Nodes, c.Path, c, false);
|
GetOrAddTreeNode(Nodes, c.Path, c, false);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue