mirror of
https://github.com/zs-yg/kortapp-z.git
synced 2025-12-07 00:20:43 +08:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d454ac0fdc | ||
|
|
d5c83d854c | ||
|
|
1c2bc713be | ||
|
|
1539c665f0 | ||
|
|
074e55fbbc | ||
|
|
334fa56070 | ||
|
|
0268e13b56 | ||
|
|
cba6c9eeca | ||
|
|
70a776125a | ||
|
|
f7250dae08 | ||
|
|
ac93c8418f | ||
|
|
5a49714ed7 | ||
|
|
19056a1a8c | ||
|
|
7c4250f912 | ||
|
|
d056c24a1b | ||
|
|
5651e944f9 | ||
|
|
1dbd9968c9 | ||
|
|
e387d22fee | ||
|
|
68bd471bd2 | ||
|
|
53392a2ce8 | ||
|
|
5ecfe2da2a | ||
|
|
5b9532acfe | ||
|
|
c87d071ee0 |
@@ -17,12 +17,13 @@ namespace AppStore
|
|||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.Dock = DockStyle.Fill;
|
this.Dock = DockStyle.Fill;
|
||||||
this.BackColor = Color.White;
|
this.BackColor = ThemeManager.BackgroundColor;
|
||||||
this.Padding = new Padding(20);
|
this.Padding = new Padding(20);
|
||||||
|
|
||||||
// 创建主布局面板
|
// 创建主布局面板
|
||||||
TableLayoutPanel mainLayout = new TableLayoutPanel();
|
TableLayoutPanel mainLayout = new TableLayoutPanel();
|
||||||
mainLayout.Dock = DockStyle.Fill;
|
mainLayout.Dock = DockStyle.Fill;
|
||||||
|
mainLayout.BackColor = ThemeManager.BackgroundColor;
|
||||||
mainLayout.ColumnCount = 1;
|
mainLayout.ColumnCount = 1;
|
||||||
mainLayout.RowCount = 2;
|
mainLayout.RowCount = 2;
|
||||||
mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||||
@@ -50,7 +51,7 @@ namespace AppStore
|
|||||||
|
|
||||||
// 初始化并添加应用信息
|
// 初始化并添加应用信息
|
||||||
infoLabel = new Label();
|
infoLabel = new Label();
|
||||||
infoLabel.Text = "kortapp-z\n版本: 1.0.8\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
|
infoLabel.Text = "kortapp-z\n版本: 1.1.3\n作者: zs-yg\n一个简单、开源的应用商店\nkortapp-z是完全免费\n基于.NET8和C/C++的软件";
|
||||||
infoLabel.Font = new Font("Microsoft YaHei", 12);
|
infoLabel.Font = new Font("Microsoft YaHei", 12);
|
||||||
infoLabel.AutoSize = false;
|
infoLabel.AutoSize = false;
|
||||||
infoLabel.Width = 300;
|
infoLabel.Width = 300;
|
||||||
@@ -68,6 +69,7 @@ namespace AppStore
|
|||||||
// 在底部添加GitHub链接区域
|
// 在底部添加GitHub链接区域
|
||||||
TableLayoutPanel githubPanel = new TableLayoutPanel();
|
TableLayoutPanel githubPanel = new TableLayoutPanel();
|
||||||
githubPanel.Dock = DockStyle.Bottom;
|
githubPanel.Dock = DockStyle.Bottom;
|
||||||
|
githubPanel.BackColor = ThemeManager.BackgroundColor;
|
||||||
githubPanel.Height = 60;
|
githubPanel.Height = 60;
|
||||||
githubPanel.ColumnCount = 3;
|
githubPanel.ColumnCount = 3;
|
||||||
githubPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
githubPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||||
@@ -109,6 +111,7 @@ namespace AppStore
|
|||||||
// 创建包含图标和文字的面板
|
// 创建包含图标和文字的面板
|
||||||
Panel linkPanel = new Panel();
|
Panel linkPanel = new Panel();
|
||||||
linkPanel.AutoSize = true;
|
linkPanel.AutoSize = true;
|
||||||
|
linkPanel.BackColor = ThemeManager.BackgroundColor;
|
||||||
linkPanel.Controls.Add(githubIcon);
|
linkPanel.Controls.Add(githubIcon);
|
||||||
linkPanel.Controls.Add(githubLabel);
|
linkPanel.Controls.Add(githubLabel);
|
||||||
githubIcon.Location = new Point(0, 0);
|
githubIcon.Location = new Point(0, 0);
|
||||||
|
|||||||
53
AppCard.cs
53
AppCard.cs
@@ -13,7 +13,9 @@ namespace AppStore
|
|||||||
{
|
{
|
||||||
private PictureBox iconBox;
|
private PictureBox iconBox;
|
||||||
private Label nameLabel;
|
private Label nameLabel;
|
||||||
|
private Panel namePanel;
|
||||||
private Button downloadBtn;
|
private Button downloadBtn;
|
||||||
|
private Color borderColor = SystemColors.ControlDark;
|
||||||
private static readonly ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath> PathCache =
|
private static readonly ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath> PathCache =
|
||||||
new ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath>();
|
new ConcurrentDictionary<string, System.Drawing.Drawing2D.GraphicsPath>();
|
||||||
|
|
||||||
@@ -27,6 +29,7 @@ namespace AppStore
|
|||||||
// 确保关键对象不为null
|
// 确保关键对象不为null
|
||||||
iconBox = new PictureBox() { SizeMode = PictureBoxSizeMode.StretchImage };
|
iconBox = new PictureBox() { SizeMode = PictureBoxSizeMode.StretchImage };
|
||||||
nameLabel = new Label() { Text = string.Empty };
|
nameLabel = new Label() { Text = string.Empty };
|
||||||
|
namePanel = new Panel();
|
||||||
downloadBtn = new Button() { Text = "下载" };
|
downloadBtn = new Button() { Text = "下载" };
|
||||||
|
|
||||||
// 确保DownloadManager已初始化
|
// 确保DownloadManager已初始化
|
||||||
@@ -57,14 +60,29 @@ namespace AppStore
|
|||||||
iconBox.SizeMode = PictureBoxSizeMode.StretchImage;
|
iconBox.SizeMode = PictureBoxSizeMode.StretchImage;
|
||||||
this.Controls.Add(iconBox);
|
this.Controls.Add(iconBox);
|
||||||
|
|
||||||
// 应用名称
|
// 应用名称 - 使用Panel包裹Label实现边框颜色
|
||||||
|
// namePanel已在构造函数中初始化
|
||||||
|
namePanel.Size = new Size(Width - 20, 40);
|
||||||
|
namePanel.Location = new Point(10, 100);
|
||||||
|
namePanel.Paint += (sender, e) => {
|
||||||
|
ControlPaint.DrawBorder(e.Graphics, namePanel.ClientRectangle,
|
||||||
|
borderColor, ButtonBorderStyle.Solid);
|
||||||
|
};
|
||||||
|
|
||||||
nameLabel = new Label();
|
nameLabel = new Label();
|
||||||
nameLabel.AutoSize = false;
|
nameLabel.Dock = DockStyle.Fill;
|
||||||
nameLabel.Size = new Size(Width - 20, 40);
|
|
||||||
nameLabel.Location = new Point(10, 100);
|
|
||||||
nameLabel.Font = new Font("Microsoft YaHei", 10, FontStyle.Bold);
|
nameLabel.Font = new Font("Microsoft YaHei", 10, FontStyle.Bold);
|
||||||
nameLabel.TextAlign = ContentAlignment.MiddleCenter;
|
nameLabel.TextAlign = ContentAlignment.MiddleCenter;
|
||||||
this.Controls.Add(nameLabel);
|
|
||||||
|
namePanel.Controls.Add(nameLabel);
|
||||||
|
|
||||||
|
// 初始主题设置
|
||||||
|
UpdateLabelTheme();
|
||||||
|
|
||||||
|
// 订阅主题变化事件
|
||||||
|
ThemeManager.ThemeChanged += (theme) => UpdateLabelTheme();
|
||||||
|
|
||||||
|
this.Controls.Add(namePanel);
|
||||||
|
|
||||||
// 下载按钮
|
// 下载按钮
|
||||||
downloadBtn = new Button();
|
downloadBtn = new Button();
|
||||||
@@ -92,6 +110,25 @@ namespace AppStore
|
|||||||
downloadBtn.Visible = ShowDownloadButton;
|
downloadBtn.Visible = ShowDownloadButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateLabelTheme()
|
||||||
|
{
|
||||||
|
if (ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Dark)
|
||||||
|
{
|
||||||
|
nameLabel.BackColor = Color.Black;
|
||||||
|
nameLabel.ForeColor = Color.White;
|
||||||
|
namePanel.BackColor = Color.Black;
|
||||||
|
borderColor = Color.White;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nameLabel.BackColor = Color.White;
|
||||||
|
nameLabel.ForeColor = Color.Black;
|
||||||
|
namePanel.BackColor = Color.White;
|
||||||
|
borderColor = SystemColors.ControlDark;
|
||||||
|
}
|
||||||
|
namePanel.Invalidate(); // 触发重绘
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化卡片边框路径
|
/// 初始化卡片边框路径
|
||||||
/// 使用C++程序计算高性能边框路径并缓存结果
|
/// 使用C++程序计算高性能边框路径并缓存结果
|
||||||
@@ -309,10 +346,16 @@ namespace AppStore
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateDisplay()
|
public void UpdateDisplay()
|
||||||
|
{
|
||||||
|
if (nameLabel != null)
|
||||||
{
|
{
|
||||||
nameLabel.Text = AppName;
|
nameLabel.Text = AppName;
|
||||||
|
}
|
||||||
|
if (iconBox != null && AppIcon != null)
|
||||||
|
{
|
||||||
iconBox.Image = AppIcon;
|
iconBox.Image = AppIcon;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DownloadBtn_Click(object sender, EventArgs e)
|
private void DownloadBtn_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
|||||||
57
AppSearch.cs
Normal file
57
AppSearch.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace AppStore
|
||||||
|
{
|
||||||
|
public static class AppSearch
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 搜索应用卡片
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="flowPanel">包含应用卡片的FlowLayoutPanel</param>
|
||||||
|
/// <param name="searchText">搜索文本</param>
|
||||||
|
public static void SearchApps(FlowLayoutPanel flowPanel, string searchText)
|
||||||
|
{
|
||||||
|
if (flowPanel == null || string.IsNullOrWhiteSpace(searchText))
|
||||||
|
{
|
||||||
|
ShowAllApps(flowPanel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Control control in flowPanel.Controls)
|
||||||
|
{
|
||||||
|
if (control is AppCard appCard)
|
||||||
|
{
|
||||||
|
bool isMatch = IsMatchSearch(appCard.AppName, searchText);
|
||||||
|
control.Visible = isMatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 显示所有应用卡片
|
||||||
|
/// </summary>
|
||||||
|
public static void ShowAllApps(FlowLayoutPanel? flowPanel)
|
||||||
|
{
|
||||||
|
if (flowPanel == null) return;
|
||||||
|
|
||||||
|
foreach (Control control in flowPanel.Controls)
|
||||||
|
{
|
||||||
|
control.Visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查应用名称是否匹配搜索文本
|
||||||
|
/// </summary>
|
||||||
|
private static bool IsMatchSearch(string appName, string searchText)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(appName)) return false;
|
||||||
|
|
||||||
|
// 不区分大小写比较
|
||||||
|
return appName.Contains(searchText, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,4 +33,8 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ZXing.Net" Version="0.16.9" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -23,13 +23,40 @@ namespace AppStore
|
|||||||
cancelBtn = new Button();
|
cancelBtn = new Button();
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
ThemeManager.ThemeChanged += (theme) => {
|
||||||
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
ApplyTheme();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyTheme()
|
||||||
|
{
|
||||||
|
this.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? Color.White
|
||||||
|
: Color.Black;
|
||||||
|
this.ForeColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? Color.Black
|
||||||
|
: Color.White;
|
||||||
|
|
||||||
|
cancelBtn.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? SystemColors.Control
|
||||||
|
: Color.FromArgb(70, 70, 70);
|
||||||
|
cancelBtn.ForeColor = ThemeManager.TextColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
this.Size = new Size(400, 60);
|
this.Size = new Size(400, 60);
|
||||||
this.BackColor = Color.White;
|
this.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? Color.White
|
||||||
|
: Color.Black;
|
||||||
this.BorderStyle = BorderStyle.FixedSingle;
|
this.BorderStyle = BorderStyle.FixedSingle;
|
||||||
|
this.ForeColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? Color.Black
|
||||||
|
: Color.White;
|
||||||
|
|
||||||
// 文件名标签
|
// 文件名标签
|
||||||
nameLabel = new Label();
|
nameLabel = new Label();
|
||||||
@@ -56,6 +83,12 @@ namespace AppStore
|
|||||||
cancelBtn.Text = "取消";
|
cancelBtn.Text = "取消";
|
||||||
cancelBtn.Size = new Size(60, 25);
|
cancelBtn.Size = new Size(60, 25);
|
||||||
cancelBtn.Location = new Point(320, 30);
|
cancelBtn.Location = new Point(320, 30);
|
||||||
|
cancelBtn.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? SystemColors.Control
|
||||||
|
: Color.FromArgb(70, 70, 70);
|
||||||
|
cancelBtn.ForeColor = ThemeManager.TextColor;
|
||||||
|
cancelBtn.FlatStyle = FlatStyle.Flat;
|
||||||
|
cancelBtn.FlatAppearance.BorderSize = 0;
|
||||||
cancelBtn.Click += CancelBtn_Click;
|
cancelBtn.Click += CancelBtn_Click;
|
||||||
this.Controls.Add(cancelBtn);
|
this.Controls.Add(cancelBtn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
@@ -85,37 +86,40 @@ namespace AppStore
|
|||||||
|
|
||||||
private void DownloadFile(DownloadItem downloadItem, string fileName, string url)
|
private void DownloadFile(DownloadItem downloadItem, string fileName, string url)
|
||||||
{
|
{
|
||||||
|
string downloadsDir = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 设置下载目录为用户文件夹中的Downloads
|
// 获取并验证下载路径
|
||||||
// 获取系统下载文件夹路径
|
downloadsDir = GetDownloadPath();
|
||||||
// 获取系统下载文件夹路径
|
|
||||||
string downloadsDir;
|
|
||||||
IntPtr pathPtr = IntPtr.Zero;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 使用SHGetKnownFolderPath API获取下载文件夹
|
// 检查路径是否有效
|
||||||
var downloadsFolderGuid = new Guid("374DE290-123F-4565-9164-39C4925E467B");
|
if (string.IsNullOrWhiteSpace(downloadsDir))
|
||||||
if (SHGetKnownFolderPath(downloadsFolderGuid, 0, IntPtr.Zero, out pathPtr) != 0)
|
|
||||||
{
|
{
|
||||||
throw new Exception("无法获取下载文件夹路径");
|
throw new Exception("下载路径为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadsDir = Marshal.PtrToStringUni(pathPtr);
|
// 尝试创建目录(如果不存在)
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw new Exception("无法确定下载文件夹位置,请手动指定下载路径");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (pathPtr != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Marshal.FreeCoTaskMem(pathPtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Directory.CreateDirectory(downloadsDir);
|
Directory.CreateDirectory(downloadsDir);
|
||||||
|
|
||||||
|
// 验证目录是否可写
|
||||||
|
string testFile = Path.Combine(downloadsDir, "write_test.tmp");
|
||||||
|
File.WriteAllText(testFile, "test");
|
||||||
|
File.Delete(testFile);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 回退到默认下载路径
|
||||||
|
string defaultPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||||
|
"Downloads");
|
||||||
|
|
||||||
|
Logger.LogError($"下载路径{downloadsDir}不可用,将使用默认路径: {defaultPath}", ex);
|
||||||
|
downloadsDir = defaultPath;
|
||||||
|
Directory.CreateDirectory(downloadsDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 构建aria2c路径
|
// 构建aria2c路径
|
||||||
@@ -311,9 +315,17 @@ namespace AppStore
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
downloadItem.Status = $"下载错误: {ex.Message}";
|
string errorDetails = $"下载错误: {ex.Message}\n";
|
||||||
DownloadCompleted?.Invoke(downloadItem);
|
errorDetails += $"目标路径: {downloadsDir}\n";
|
||||||
|
errorDetails += $"URL: {url}";
|
||||||
|
|
||||||
|
downloadItem.Status = $"下载失败: {ex.Message}";
|
||||||
|
Logger.LogError(errorDetails, ex);
|
||||||
|
|
||||||
|
MessageBox.Show($"下载失败:\n{errorDetails}", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
|
||||||
|
DownloadCompleted?.Invoke(downloadItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +334,7 @@ namespace AppStore
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var process = currentProcess;
|
var process = currentProcess;
|
||||||
if (process == null || process.HasExited || process.StartInfo == null)
|
if (process?.StartInfo == null || process.HasExited)
|
||||||
{
|
{
|
||||||
item.Status = "已取消";
|
item.Status = "已取消";
|
||||||
DownloadProgressChanged?.Invoke(item);
|
DownloadProgressChanged?.Invoke(item);
|
||||||
@@ -342,5 +354,138 @@ namespace AppStore
|
|||||||
DownloadProgressChanged?.Invoke(item);
|
DownloadProgressChanged?.Invoke(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetDownloadPath()
|
||||||
|
{
|
||||||
|
// 1. 优先读取用户设置的下载路径
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string jsonPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"zsyg", "kortapp-z", ".date", "dl_path", "download_path.json");
|
||||||
|
|
||||||
|
Logger.Log($"尝试读取下载路径配置文件: {jsonPath}");
|
||||||
|
|
||||||
|
if (File.Exists(jsonPath))
|
||||||
|
{
|
||||||
|
string jsonString = File.ReadAllText(jsonPath);
|
||||||
|
Logger.Log($"配置文件内容: {jsonString}");
|
||||||
|
|
||||||
|
var jsonData = JsonSerializer.Deserialize<JsonElement>(jsonString);
|
||||||
|
string customPath = jsonData.GetProperty("DownloadPath").GetString()?.Trim();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(customPath))
|
||||||
|
{
|
||||||
|
Logger.Log($"读取到自定义路径: {customPath}");
|
||||||
|
|
||||||
|
// 处理路径格式
|
||||||
|
customPath = customPath.Replace(@"\\", @"\");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 处理路径中的环境变量和特殊字符
|
||||||
|
customPath = Environment.ExpandEnvironmentVariables(customPath);
|
||||||
|
customPath = Path.GetFullPath(customPath);
|
||||||
|
Logger.Log($"标准化后的路径: {customPath}");
|
||||||
|
|
||||||
|
// 确保路径以目录分隔符结尾
|
||||||
|
if (!customPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
|
||||||
|
{
|
||||||
|
customPath += Path.DirectorySeparatorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证驱动器是否存在
|
||||||
|
string drive = Path.GetPathRoot(customPath);
|
||||||
|
if (!Directory.Exists(drive))
|
||||||
|
{
|
||||||
|
Logger.LogError($"驱动器不存在: {drive}");
|
||||||
|
throw new Exception($"驱动器 {drive} 不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证路径
|
||||||
|
if (!Directory.Exists(customPath))
|
||||||
|
{
|
||||||
|
Logger.Log($"创建目录: {customPath}");
|
||||||
|
Directory.CreateDirectory(customPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更严格的路径可写性测试
|
||||||
|
string testFile = Path.Combine(customPath, $"write_test_{Guid.NewGuid()}.tmp");
|
||||||
|
Logger.Log($"测试路径可写性: {testFile}");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.WriteAllText(testFile, DateTime.Now.ToString());
|
||||||
|
string content = File.ReadAllText(testFile);
|
||||||
|
File.Delete(testFile);
|
||||||
|
Logger.Log($"路径验证成功: {customPath}");
|
||||||
|
return customPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError($"路径不可写: {customPath}", ex);
|
||||||
|
throw new Exception($"路径不可写: {customPath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError($"路径处理失败: {customPath}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Log("未找到下载路径配置文件");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("读取自定义下载路径失败", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 回退到系统默认下载路径
|
||||||
|
IntPtr pathPtr = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var downloadsFolderGuid = new Guid("374DE290-123F-4565-9164-39C4925E467B");
|
||||||
|
if (SHGetKnownFolderPath(downloadsFolderGuid, 0, IntPtr.Zero, out pathPtr) == 0)
|
||||||
|
{
|
||||||
|
string defaultPath = Marshal.PtrToStringUni(pathPtr);
|
||||||
|
if (!string.IsNullOrEmpty(defaultPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(defaultPath);
|
||||||
|
return defaultPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("获取系统下载路径失败", ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (pathPtr != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeCoTaskMem(pathPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 最终回退到相对路径 ~/Downloads
|
||||||
|
string relativePath = "~/Downloads";
|
||||||
|
string fallbackPath = relativePath.Replace("~",
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
|
||||||
|
fallbackPath = Path.GetFullPath(fallbackPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Directory.CreateDirectory(fallbackPath);
|
||||||
|
// 测试路径可写性
|
||||||
|
string testFile = Path.Combine(fallbackPath, "write_test.tmp");
|
||||||
|
File.WriteAllText(testFile, "test");
|
||||||
|
File.Delete(testFile);
|
||||||
|
return fallbackPath;
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw new Exception($"无法使用默认下载路径: {fallbackPath}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 704 KiB |
152
MainForm.cs
152
MainForm.cs
@@ -140,11 +140,19 @@ namespace AppStore
|
|||||||
this.StartPosition = FormStartPosition.CenterScreen;
|
this.StartPosition = FormStartPosition.CenterScreen;
|
||||||
this.Icon = new Icon("img/ico/icon.ico"); // 设置窗体图标
|
this.Icon = new Icon("img/ico/icon.ico"); // 设置窗体图标
|
||||||
|
|
||||||
|
// 注册主题变更事件
|
||||||
|
ThemeManager.ThemeChanged += (theme) =>
|
||||||
|
{
|
||||||
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
AnimateThemeChange();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 现代化顶部导航栏
|
// 现代化顶部导航栏
|
||||||
Panel buttonPanel = new Panel();
|
Panel buttonPanel = new Panel();
|
||||||
buttonPanel.Dock = DockStyle.Top;
|
buttonPanel.Dock = DockStyle.Top;
|
||||||
buttonPanel.Height = 70;
|
buttonPanel.Height = 70;
|
||||||
buttonPanel.BackColor = Color.FromArgb(240, 240, 240);
|
buttonPanel.BackColor = ThemeManager.ControlBackgroundColor;
|
||||||
buttonPanel.Padding = new Padding(10, 15, 10, 0);
|
buttonPanel.Padding = new Padding(10, 15, 10, 0);
|
||||||
buttonPanel.AutoScroll = true;
|
buttonPanel.AutoScroll = true;
|
||||||
buttonPanel.AutoSize = true;
|
buttonPanel.AutoSize = true;
|
||||||
@@ -154,11 +162,13 @@ namespace AppStore
|
|||||||
Action<Button> styleButton = (Button btn) => {
|
Action<Button> styleButton = (Button btn) => {
|
||||||
btn.FlatStyle = FlatStyle.Flat;
|
btn.FlatStyle = FlatStyle.Flat;
|
||||||
btn.FlatAppearance.BorderSize = 0;
|
btn.FlatAppearance.BorderSize = 0;
|
||||||
btn.BackColor = Color.Transparent;
|
btn.BackColor = ThemeManager.ControlBackgroundColor;
|
||||||
btn.ForeColor = Color.FromArgb(64, 64, 64);
|
btn.ForeColor = ThemeManager.TextColor;
|
||||||
btn.Font = new Font("Microsoft YaHei", 10, FontStyle.Regular);
|
btn.Font = new Font("Microsoft YaHei", 10, FontStyle.Regular);
|
||||||
btn.Size = new Size(120, 40);
|
btn.Size = new Size(120, 40);
|
||||||
btn.Cursor = Cursors.Hand;
|
btn.Cursor = Cursors.Hand;
|
||||||
|
btn.FlatAppearance.MouseOverBackColor = ThemeManager.ButtonHoverColor;
|
||||||
|
btn.FlatAppearance.MouseDownBackColor = ThemeManager.ButtonActiveColor;
|
||||||
|
|
||||||
// 悬停效果
|
// 悬停效果
|
||||||
btn.MouseEnter += (s, e) => {
|
btn.MouseEnter += (s, e) => {
|
||||||
@@ -167,7 +177,7 @@ namespace AppStore
|
|||||||
};
|
};
|
||||||
|
|
||||||
btn.MouseLeave += (s, e) => {
|
btn.MouseLeave += (s, e) => {
|
||||||
btn.ForeColor = Color.FromArgb(64, 64, 64);
|
btn.ForeColor = ThemeManager.TextColor;
|
||||||
btn.Font = new Font(btn.Font, FontStyle.Regular);
|
btn.Font = new Font(btn.Font, FontStyle.Regular);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -230,7 +240,7 @@ namespace AppStore
|
|||||||
// 现代化内容区域
|
// 现代化内容区域
|
||||||
contentPanel = new Panel();
|
contentPanel = new Panel();
|
||||||
contentPanel.Dock = DockStyle.Fill;
|
contentPanel.Dock = DockStyle.Fill;
|
||||||
contentPanel.BackColor = Color.White;
|
contentPanel.BackColor = ThemeManager.BackgroundColor;
|
||||||
contentPanel.Padding = new Padding(20);
|
contentPanel.Padding = new Padding(20);
|
||||||
this.Controls.Add(contentPanel);
|
this.Controls.Add(contentPanel);
|
||||||
|
|
||||||
@@ -238,11 +248,13 @@ namespace AppStore
|
|||||||
Panel separator = new Panel();
|
Panel separator = new Panel();
|
||||||
separator.Dock = DockStyle.Top;
|
separator.Dock = DockStyle.Top;
|
||||||
separator.Height = 1;
|
separator.Height = 1;
|
||||||
separator.BackColor = Color.FromArgb(230, 230, 230);
|
separator.BackColor = ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Light
|
||||||
|
? Color.FromArgb(230, 230, 230)
|
||||||
|
: Color.FromArgb(60, 60, 60);
|
||||||
contentPanel.Controls.Add(separator);
|
contentPanel.Controls.Add(separator);
|
||||||
|
|
||||||
this.Controls.Add(buttonPanel);
|
this.Controls.Add(buttonPanel);
|
||||||
this.BackColor = Color.White;
|
this.BackColor = ThemeManager.BackgroundColor;
|
||||||
|
|
||||||
// 默认显示软件下载视图
|
// 默认显示软件下载视图
|
||||||
ShowAppsView();
|
ShowAppsView();
|
||||||
@@ -501,6 +513,59 @@ namespace AppStore
|
|||||||
}
|
}
|
||||||
flowPanel.Controls.Add(calculatorCard);
|
flowPanel.Controls.Add(calculatorCard);
|
||||||
|
|
||||||
|
// 图片查看工具卡片
|
||||||
|
var imageViewerCard = new KortAppZ.Tools.Viewer.ImageViewerToolCard();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "ImageCompressor.png");
|
||||||
|
if (File.Exists(iconPath))
|
||||||
|
{
|
||||||
|
imageViewerCard.ToolIcon = Image.FromFile(iconPath);
|
||||||
|
}
|
||||||
|
imageViewerCard.UpdateDisplay();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("加载图片查看器图标失败", ex);
|
||||||
|
}
|
||||||
|
flowPanel.Controls.Add(imageViewerCard);
|
||||||
|
|
||||||
|
// 密码生成器工具卡片
|
||||||
|
var passwordGeneratorCard = new ToolCard();
|
||||||
|
passwordGeneratorCard.ToolName = "密码生成器";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "password_generator.png");
|
||||||
|
if (File.Exists(iconPath))
|
||||||
|
{
|
||||||
|
passwordGeneratorCard.ToolIcon = Image.FromFile(iconPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
passwordGeneratorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
passwordGeneratorCard.ToolIcon = SystemIcons.Shield.ToBitmap();
|
||||||
|
}
|
||||||
|
passwordGeneratorCard.ToolCardClicked += (s, e) => {
|
||||||
|
try {
|
||||||
|
string toolPath = Path.Combine(Application.StartupPath, "resource", "password_generator.exe");
|
||||||
|
if (File.Exists(toolPath)) {
|
||||||
|
Process.Start(toolPath);
|
||||||
|
} else {
|
||||||
|
MessageBox.Show("密码生成器工具未找到,请确保已正确安装", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
MessageBox.Show($"启动密码生成器失败: {ex.Message}", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
passwordGeneratorCard.UpdateDisplay();
|
||||||
|
flowPanel.Controls.Add(passwordGeneratorCard);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -650,7 +715,7 @@ namespace AppStore
|
|||||||
|
|
||||||
flowPanel.Controls.Add(CreateAppCard(
|
flowPanel.Controls.Add(CreateAppCard(
|
||||||
"XDM",
|
"XDM",
|
||||||
"https://github.com/subhra74/xdm/releases/download/7.2.11/xdm-setup.msi",
|
"https://ghproxy.net/https://github.com/subhra74/xdm/releases/download/7.2.11/xdm-setup.msi",
|
||||||
"img/png/XDM.png"));
|
"img/png/XDM.png"));
|
||||||
|
|
||||||
flowPanel.Controls.Add(CreateAppCard(
|
flowPanel.Controls.Add(CreateAppCard(
|
||||||
@@ -715,7 +780,7 @@ namespace AppStore
|
|||||||
|
|
||||||
flowPanel.Controls.Add(CreateAppCard(
|
flowPanel.Controls.Add(CreateAppCard(
|
||||||
"Msys2",
|
"Msys2",
|
||||||
"https://github.com/msys2/msys2-installer/releases/download/2025-02-21/msys2-x86_64-20250221.exe",
|
"https://ghproxy.net/https://github.com/msys2/msys2-installer/releases/download/2025-02-21/msys2-x86_64-20250221.exe",
|
||||||
"img/png/MSYS2.png"));
|
"img/png/MSYS2.png"));
|
||||||
|
|
||||||
flowPanel.Controls.Add(CreateAppCard(
|
flowPanel.Controls.Add(CreateAppCard(
|
||||||
@@ -815,7 +880,7 @@ namespace AppStore
|
|||||||
|
|
||||||
flowPanel.Controls.Add(CreateAppCard(
|
flowPanel.Controls.Add(CreateAppCard(
|
||||||
"frp",
|
"frp",
|
||||||
"https://github.com/fatedier/frp/releases/download/v0.62.1/frp_0.62.1_windows_amd64.zip",
|
"https://ghproxy.net/https://github.com/fatedier/frp/releases/download/v0.62.1/frp_0.62.1_windows_amd64.zip",
|
||||||
""));
|
""));
|
||||||
|
|
||||||
flowPanel.Controls.Add(CreateAppCard(
|
flowPanel.Controls.Add(CreateAppCard(
|
||||||
@@ -1218,6 +1283,9 @@ namespace AppStore
|
|||||||
// 初始化窗体组件
|
// 初始化窗体组件
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// 应用主题
|
||||||
|
ThemeManager.ApplyTheme(this);
|
||||||
|
|
||||||
// 订阅下载管理器事件
|
// 订阅下载管理器事件
|
||||||
DownloadManager.Instance.DownloadAdded += OnDownloadAdded; // 下载添加事件
|
DownloadManager.Instance.DownloadAdded += OnDownloadAdded; // 下载添加事件
|
||||||
DownloadManager.Instance.DownloadProgressChanged += OnDownloadProgressChanged; // 下载进度变化事件
|
DownloadManager.Instance.DownloadProgressChanged += OnDownloadProgressChanged; // 下载进度变化事件
|
||||||
@@ -1299,5 +1367,69 @@ namespace AppStore
|
|||||||
Logger.Log($"下载完成: {item.FileName}, 状态: {item.Status}"); // 记录日志
|
Logger.Log($"下载完成: {item.FileName}, 状态: {item.Status}"); // 记录日志
|
||||||
item.UpdateDisplay(); // 更新UI显示
|
item.UpdateDisplay(); // 更新UI显示
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主题切换动画效果
|
||||||
|
/// </summary>
|
||||||
|
private void AnimateThemeChange()
|
||||||
|
{
|
||||||
|
const int animationSteps = 10;
|
||||||
|
const int animationInterval = 30;
|
||||||
|
|
||||||
|
var timer = new System.Windows.Forms.Timer { Interval = animationInterval };
|
||||||
|
int step = 0;
|
||||||
|
|
||||||
|
// 保存当前和目标颜色
|
||||||
|
var originalBackColor = this.BackColor;
|
||||||
|
var targetBackColor = ThemeManager.BackgroundColor;
|
||||||
|
var originalForeColor = this.ForeColor;
|
||||||
|
var targetForeColor = ThemeManager.TextColor;
|
||||||
|
|
||||||
|
timer.Tick += (s, e) => {
|
||||||
|
if (step >= animationSteps)
|
||||||
|
{
|
||||||
|
timer.Stop();
|
||||||
|
timer.Dispose();
|
||||||
|
// 确保最终颜色准确
|
||||||
|
ThemeManager.ApplyTheme(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算插值比例
|
||||||
|
float ratio = (float)step / animationSteps;
|
||||||
|
step++;
|
||||||
|
|
||||||
|
// 插值计算新颜色
|
||||||
|
var newBackColor = Color.FromArgb(
|
||||||
|
(int)(originalBackColor.R + (targetBackColor.R - originalBackColor.R) * ratio),
|
||||||
|
(int)(originalBackColor.G + (targetBackColor.G - originalBackColor.G) * ratio),
|
||||||
|
(int)(originalBackColor.B + (targetBackColor.B - originalBackColor.B) * ratio));
|
||||||
|
|
||||||
|
var newForeColor = Color.FromArgb(
|
||||||
|
(int)(originalForeColor.R + (targetForeColor.R - originalForeColor.R) * ratio),
|
||||||
|
(int)(originalForeColor.G + (targetForeColor.G - originalForeColor.G) * ratio),
|
||||||
|
(int)(originalForeColor.B + (targetForeColor.B - originalForeColor.B) * ratio));
|
||||||
|
|
||||||
|
// 应用新颜色
|
||||||
|
this.Invoke((MethodInvoker)delegate {
|
||||||
|
this.BackColor = newBackColor;
|
||||||
|
this.ForeColor = newForeColor;
|
||||||
|
foreach (Control control in this.Controls)
|
||||||
|
{
|
||||||
|
control.BackColor = newBackColor;
|
||||||
|
control.ForeColor = newForeColor;
|
||||||
|
|
||||||
|
// 特殊处理按钮的悬停状态
|
||||||
|
if (control is Button button)
|
||||||
|
{
|
||||||
|
button.FlatAppearance.MouseOverBackColor = ThemeManager.ButtonHoverColor;
|
||||||
|
button.FlatAppearance.MouseDownBackColor = ThemeManager.ButtonActiveColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -5,14 +5,12 @@
|
|||||||
## 项目开源行为
|
## 项目开源行为
|
||||||
|
|
||||||
1. 项目代码开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
|
1. 项目代码开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
|
||||||
2. 项目文档开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
|
2. 项目图标、截图等资源开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
|
||||||
3. 项目图标、截图等资源开源,允许任何人使用、修改、分发、商用,但必须注明原作者。
|
3. 项目的任何衍生品(包括但不限于网站、APP、插件等)必须遵循以上开源协议。
|
||||||
4. 项目的任何衍生品(包括但不限于网站、APP、插件等)必须遵循以上开源协议。
|
4. 项目不接受任何形式的广告,不得在任何地方投放广告。
|
||||||
5. 项目不接受任何形式的广告,不得在任何地方投放广告。
|
5. 项目不接受任何形式的捐赠、赞助
|
||||||
6. 项目不接受任何形式的捐赠。
|
6. 项目可以进行PR,欢迎任何形式的PR,不提交issue也可以
|
||||||
7. 项目不接受任何形式的赞助。
|
7. 本项目可以PR一些你自己的项目,如果star数量不到1k,都会被删除
|
||||||
8. 项目可以进行PR,欢迎任何形式的PR,不提交issue也可以
|
|
||||||
9. 本项目可以PR一些你自己的项目,如果star数量不到1k,都会被删除
|
|
||||||
|
|
||||||
## 项目简介
|
## 项目简介
|
||||||
|
|
||||||
@@ -35,14 +33,15 @@
|
|||||||
|
|
||||||
### 打包指令
|
### 打包指令
|
||||||
|
|
||||||
|
|
||||||
#### 32位版本
|
#### 32位版本
|
||||||
```bash
|
```bash
|
||||||
dotnet publish -c Release -r win-x86 -p:PublishSingleFile=true
|
dotnet publish AppStore.csproj -c Release -r win-x86 --self-contained false /p:Optimize=true /p:DebugType=None
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 64位版本
|
#### 64位版本
|
||||||
```bash
|
```bash
|
||||||
dotnet publish -c Release -r win-x64 -p:PublishSingleFile=true
|
dotnet publish AppStore.csproj -c Release -r win-x64 --self-contained false /p:Optimize=true /p:DebugType=None
|
||||||
```
|
```
|
||||||
|
|
||||||
打包后的可执行文件将包含指定的应用程序图标,输出路径为:
|
打包后的可执行文件将包含指定的应用程序图标,输出路径为:
|
||||||
@@ -51,7 +50,9 @@ bin\Release\net8.0-windows\[platform]\publish
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 高级选项
|
### 高级选项
|
||||||
- 添加`--self-contained true`可生成独立包(体积较大)
|
- 使用`--self-contained false`生成框架依赖包(默认)
|
||||||
|
- 使用`/p:Optimize=true`启用代码优化(默认)
|
||||||
|
- 使用`/p:DebugType=None`禁用调试符号生成(默认)
|
||||||
- 添加`-p:PublishTrimmed=true`可减小包体积(实验性)
|
- 添加`-p:PublishTrimmed=true`可减小包体积(实验性)
|
||||||
|
|
||||||
## 项目结构
|
## 项目结构
|
||||||
|
|||||||
176
SettingsForm.cs
176
SettingsForm.cs
@@ -2,29 +2,101 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace AppStore
|
namespace AppStore
|
||||||
{
|
{
|
||||||
public class SettingsUserControl : UserControl
|
public class SettingsUserControl : UserControl
|
||||||
{
|
{
|
||||||
private Button btnCleanLogs;
|
private Button btnCleanLogs;
|
||||||
|
private Button btnLightTheme;
|
||||||
|
private Button btnDarkTheme;
|
||||||
|
|
||||||
public SettingsUserControl()
|
public SettingsUserControl()
|
||||||
{
|
{
|
||||||
this.Dock = DockStyle.Fill;
|
this.Dock = DockStyle.Fill;
|
||||||
this.BackColor = Color.White;
|
ThemeManager.ApplyTheme(this);
|
||||||
|
|
||||||
// 设置顶部内边距
|
// 设置顶部内边距
|
||||||
this.Padding = new Padding(0, 30, 0, 0);
|
this.Padding = new Padding(0, 30, 0, 0);
|
||||||
|
|
||||||
|
// 主题切换按钮
|
||||||
|
btnLightTheme = new Button();
|
||||||
|
btnLightTheme.Text = "浅色模式";
|
||||||
|
btnLightTheme.Size = new Size(150, 40);
|
||||||
|
btnLightTheme.Location = new Point((this.Width - 320) / 2, 50);
|
||||||
|
btnLightTheme.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
btnLightTheme.Anchor = AnchorStyles.Top;
|
||||||
|
btnLightTheme.Click += (s, e) => SwitchTheme(ThemeManager.ThemeMode.Light);
|
||||||
|
this.Controls.Add(btnLightTheme);
|
||||||
|
|
||||||
|
btnDarkTheme = new Button();
|
||||||
|
btnDarkTheme.Text = "深色模式";
|
||||||
|
btnDarkTheme.Size = new Size(150, 40);
|
||||||
|
btnDarkTheme.Location = new Point(btnLightTheme.Right + 20, 50);
|
||||||
|
btnDarkTheme.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
btnDarkTheme.Anchor = AnchorStyles.Top;
|
||||||
|
btnDarkTheme.Click += (s, e) => SwitchTheme(ThemeManager.ThemeMode.Dark);
|
||||||
|
this.Controls.Add(btnDarkTheme);
|
||||||
|
|
||||||
|
// 清理日志按钮
|
||||||
btnCleanLogs = new Button();
|
btnCleanLogs = new Button();
|
||||||
btnCleanLogs.Text = "清理日志";
|
btnCleanLogs.Text = "清理日志";
|
||||||
btnCleanLogs.Size = new Size(150, 40);
|
btnCleanLogs.Size = new Size(150, 40);
|
||||||
btnCleanLogs.Location = new Point((this.Width - 150) / 2, 50); // 调整Y坐标为50靠近顶部
|
btnCleanLogs.Location = new Point((this.Width - 150) / 2, 110);
|
||||||
btnCleanLogs.Font = new Font("Microsoft YaHei", 10);
|
btnCleanLogs.Font = new Font("Microsoft YaHei", 10);
|
||||||
btnCleanLogs.Anchor = AnchorStyles.Top; // 添加顶部锚点
|
btnCleanLogs.Anchor = AnchorStyles.Top;
|
||||||
btnCleanLogs.Click += (s, e) => CleanLogs();
|
btnCleanLogs.Click += (s, e) => CleanLogs();
|
||||||
this.Controls.Add(btnCleanLogs);
|
this.Controls.Add(btnCleanLogs);
|
||||||
|
|
||||||
|
// 下载路径设置
|
||||||
|
Label lblDownloadPath = new Label();
|
||||||
|
lblDownloadPath.Text = "下载路径:";
|
||||||
|
lblDownloadPath.AutoSize = true;
|
||||||
|
lblDownloadPath.Location = new Point((this.Width - 300) / 2, 170);
|
||||||
|
lblDownloadPath.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
lblDownloadPath.Anchor = AnchorStyles.Top;
|
||||||
|
this.Controls.Add(lblDownloadPath);
|
||||||
|
|
||||||
|
TextBox txtDownloadPath = new TextBox();
|
||||||
|
txtDownloadPath.Size = new Size(300, 30);
|
||||||
|
txtDownloadPath.Location = new Point((this.Width - 300) / 2, 200);
|
||||||
|
txtDownloadPath.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
txtDownloadPath.Anchor = AnchorStyles.Top;
|
||||||
|
txtDownloadPath.ReadOnly = true;
|
||||||
|
this.Controls.Add(txtDownloadPath);
|
||||||
|
|
||||||
|
Button btnBrowse = new Button();
|
||||||
|
btnBrowse.Text = "浏览...";
|
||||||
|
btnBrowse.Size = new Size(80, 30);
|
||||||
|
btnBrowse.Location = new Point(txtDownloadPath.Right + 10, 200);
|
||||||
|
btnBrowse.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
btnBrowse.Anchor = AnchorStyles.Top;
|
||||||
|
btnBrowse.Click += (s, e) => BrowseDownloadPath(txtDownloadPath);
|
||||||
|
this.Controls.Add(btnBrowse);
|
||||||
|
|
||||||
|
Button btnSavePath = new Button();
|
||||||
|
btnSavePath.Text = "保存路径";
|
||||||
|
btnSavePath.Size = new Size(100, 30);
|
||||||
|
btnSavePath.Location = new Point((this.Width - 100) / 2, 240);
|
||||||
|
btnSavePath.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
btnSavePath.Anchor = AnchorStyles.Top;
|
||||||
|
btnSavePath.Click += (s, e) => SaveDownloadPath(txtDownloadPath.Text);
|
||||||
|
this.Controls.Add(btnSavePath);
|
||||||
|
|
||||||
|
ThemeManager.ThemeChanged += OnThemeChanged;
|
||||||
|
LoadDownloadPath(txtDownloadPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SwitchTheme(ThemeManager.ThemeMode theme)
|
||||||
|
{
|
||||||
|
ThemeManager.CurrentTheme = theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnThemeChanged(ThemeManager.ThemeMode theme)
|
||||||
|
{
|
||||||
|
ThemeManager.ApplyTheme(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CleanLogs()
|
private void CleanLogs()
|
||||||
@@ -49,5 +121,103 @@ namespace AppStore
|
|||||||
MessageBox.Show($"清理日志时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show($"清理日志时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BrowseDownloadPath(TextBox txtBox)
|
||||||
|
{
|
||||||
|
using (FolderBrowserDialog dialog = new FolderBrowserDialog())
|
||||||
|
{
|
||||||
|
dialog.Description = "选择下载路径";
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
txtBox.Text = dialog.SelectedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveDownloadPath(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 验证路径
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
MessageBox.Show("下载路径不能为空", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试创建目录(如果不存在)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
|
||||||
|
// 验证目录是否可写
|
||||||
|
string testFile = Path.Combine(path, "write_test.tmp");
|
||||||
|
File.WriteAllText(testFile, "test");
|
||||||
|
File.Delete(testFile);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MessageBox.Show($"无法访问路径: {path}\n请确保路径存在且有写入权限", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存路径
|
||||||
|
string dlPathDir = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"zsyg", "kortapp-z", ".date", "dl_path");
|
||||||
|
|
||||||
|
if (!Directory.Exists(dlPathDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dlPathDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
string jsonPath = Path.Combine(dlPathDir, "download_path.json");
|
||||||
|
var jsonData = new { DownloadPath = path };
|
||||||
|
string jsonString = JsonSerializer.Serialize(jsonData);
|
||||||
|
|
||||||
|
File.WriteAllText(jsonPath, jsonString);
|
||||||
|
|
||||||
|
MessageBox.Show($"下载路径已保存到:\n{path}", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("保存下载路径时出错", ex);
|
||||||
|
MessageBox.Show($"保存下载路径时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadDownloadPath(TextBox txtBox)
|
||||||
|
{
|
||||||
|
// 默认下载路径为用户文件夹下的Downloads
|
||||||
|
string defaultPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||||
|
"Downloads");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string jsonPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"zsyg", "kortapp-z", ".date", "dl_path", "download_path.json");
|
||||||
|
|
||||||
|
if (File.Exists(jsonPath))
|
||||||
|
{
|
||||||
|
string jsonString = File.ReadAllText(jsonPath);
|
||||||
|
var jsonData = JsonSerializer.Deserialize<JsonElement>(jsonString);
|
||||||
|
string customPath = jsonData.GetProperty("DownloadPath").GetString();
|
||||||
|
|
||||||
|
// 如果自定义路径有效则显示,否则显示默认路径
|
||||||
|
txtBox.Text = !string.IsNullOrWhiteSpace(customPath) ? customPath : defaultPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txtBox.Text = defaultPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("加载下载路径时出错", ex);
|
||||||
|
txtBox.Text = defaultPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
TXT/Build.txt
Normal file
12
TXT/Build.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
首先,如果希望编译程序,那么必须安装.NET8.0 SDK
|
||||||
|
下载链接:https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer
|
||||||
|
|
||||||
|
使用一下指令编译
|
||||||
|
|
||||||
|
x86:
|
||||||
|
|
||||||
|
dotnet publish AppStore.csproj -c Release -r win-x86 --self-contained false /p:Optimize=true /p:DebugType=None
|
||||||
|
|
||||||
|
x64:
|
||||||
|
|
||||||
|
dotnet publish AppStore.csproj -c Release -r win-x64 --self-contained false /p:Optimize=true /p:DebugType=None
|
||||||
7
TXT/Run.txt
Normal file
7
TXT/Run.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
如果希望运行,那么必须安装.NET8.0 SDK
|
||||||
|
|
||||||
|
下载链接:https://dotnet.microsoft.com/zh-cn/download/dotnet/thank-you/sdk-8.0.411-windows-x64-installer
|
||||||
|
|
||||||
|
使用一下指令运行:
|
||||||
|
|
||||||
|
dotnet run
|
||||||
129
ThemeManager.cs
Normal file
129
ThemeManager.cs
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace AppStore
|
||||||
|
{
|
||||||
|
public static class ThemeManager
|
||||||
|
{
|
||||||
|
public enum ThemeMode
|
||||||
|
{
|
||||||
|
Light,
|
||||||
|
Dark
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string ThemeConfigPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"zsyg", "kortapp-z", ".date", "theme.json");
|
||||||
|
|
||||||
|
private static ThemeMode _currentTheme = LoadTheme();
|
||||||
|
|
||||||
|
private static ThemeMode LoadTheme()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(ThemeConfigPath))
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(ThemeConfigPath);
|
||||||
|
return JsonSerializer.Deserialize<ThemeMode>(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 忽略错误,使用默认主题
|
||||||
|
}
|
||||||
|
return ThemeMode.Light;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SaveTheme(ThemeMode theme)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dir = Path.GetDirectoryName(ThemeConfigPath);
|
||||||
|
if (dir == null) return;
|
||||||
|
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
|
var json = JsonSerializer.Serialize(theme);
|
||||||
|
File.WriteAllText(ThemeConfigPath, json);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// 忽略错误
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 浅色主题颜色
|
||||||
|
private static readonly Color LightBackground = Color.FromArgb(255, 255, 255);
|
||||||
|
private static readonly Color LightControlBackground = Color.FromArgb(240, 240, 240);
|
||||||
|
private static readonly Color LightText = Color.FromArgb(30, 30, 30);
|
||||||
|
private static readonly Color LightButtonHover = Color.FromArgb(230, 230, 230);
|
||||||
|
private static readonly Color LightButtonActive = Color.FromArgb(220, 220, 220);
|
||||||
|
|
||||||
|
// 深色主题颜色
|
||||||
|
private static readonly Color DarkBackground = Color.FromArgb(30, 30, 30);
|
||||||
|
private static readonly Color DarkControlBackground = Color.FromArgb(45, 45, 45);
|
||||||
|
private static readonly Color DarkText = Color.FromArgb(240, 240, 240);
|
||||||
|
private static readonly Color DarkButtonHover = Color.FromArgb(60, 60, 60);
|
||||||
|
private static readonly Color DarkButtonActive = Color.FromArgb(70, 70, 70);
|
||||||
|
|
||||||
|
public static event Action<ThemeMode> ThemeChanged = delegate {};
|
||||||
|
|
||||||
|
public static ThemeMode CurrentTheme
|
||||||
|
{
|
||||||
|
get => _currentTheme;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_currentTheme != value)
|
||||||
|
{
|
||||||
|
_currentTheme = value;
|
||||||
|
ThemeChanged?.Invoke(value);
|
||||||
|
SaveTheme(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color BackgroundColor =>
|
||||||
|
_currentTheme == ThemeMode.Light ? LightBackground : DarkBackground;
|
||||||
|
|
||||||
|
public static Color ControlBackgroundColor =>
|
||||||
|
_currentTheme == ThemeMode.Light ? LightControlBackground : DarkControlBackground;
|
||||||
|
|
||||||
|
public static Color TextColor =>
|
||||||
|
_currentTheme == ThemeMode.Light ? LightText : DarkText;
|
||||||
|
|
||||||
|
public static Color ButtonHoverColor =>
|
||||||
|
_currentTheme == ThemeMode.Light ? LightButtonHover : DarkButtonHover;
|
||||||
|
|
||||||
|
public static Color ButtonActiveColor =>
|
||||||
|
_currentTheme == ThemeMode.Light ? LightButtonActive : DarkButtonActive;
|
||||||
|
|
||||||
|
public static void ApplyTheme(Control control)
|
||||||
|
{
|
||||||
|
ApplyThemeToControl(control);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyThemeToControl(Control control)
|
||||||
|
{
|
||||||
|
control.BackColor = BackgroundColor;
|
||||||
|
control.ForeColor = TextColor;
|
||||||
|
|
||||||
|
if (control is Button button)
|
||||||
|
{
|
||||||
|
button.FlatStyle = FlatStyle.Flat;
|
||||||
|
button.FlatAppearance.BorderSize = 0;
|
||||||
|
button.FlatAppearance.MouseOverBackColor = ButtonHoverColor;
|
||||||
|
button.FlatAppearance.MouseDownBackColor = ButtonActiveColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Control childControl in control.Controls)
|
||||||
|
{
|
||||||
|
ApplyThemeToControl(childControl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
ToolCard.cs
46
ToolCard.cs
@@ -8,6 +8,8 @@ namespace AppStore
|
|||||||
{
|
{
|
||||||
private PictureBox iconBox = new PictureBox();
|
private PictureBox iconBox = new PictureBox();
|
||||||
private Label nameLabel = new Label();
|
private Label nameLabel = new Label();
|
||||||
|
private Panel namePanel = new Panel();
|
||||||
|
private Color borderColor = SystemColors.ControlDark;
|
||||||
|
|
||||||
public string ToolName { get; set; } = string.Empty;
|
public string ToolName { get; set; } = string.Empty;
|
||||||
public Image ToolIcon { get; set; } = SystemIcons.Shield.ToBitmap();
|
public Image ToolIcon { get; set; } = SystemIcons.Shield.ToBitmap();
|
||||||
@@ -37,14 +39,28 @@ namespace AppStore
|
|||||||
iconBox.SizeMode = PictureBoxSizeMode.StretchImage;
|
iconBox.SizeMode = PictureBoxSizeMode.StretchImage;
|
||||||
this.Controls.Add(iconBox);
|
this.Controls.Add(iconBox);
|
||||||
|
|
||||||
// 工具名称
|
// 工具名称 - 使用Panel包裹Label实现边框颜色
|
||||||
|
namePanel = new Panel();
|
||||||
|
namePanel.Size = new Size(Width - 20, 30);
|
||||||
|
namePanel.Location = new Point(10, 100);
|
||||||
|
namePanel.Paint += (sender, e) => {
|
||||||
|
ControlPaint.DrawBorder(e.Graphics, namePanel.ClientRectangle,
|
||||||
|
borderColor, ButtonBorderStyle.Solid);
|
||||||
|
};
|
||||||
|
|
||||||
nameLabel = new Label();
|
nameLabel = new Label();
|
||||||
nameLabel.AutoSize = false;
|
nameLabel.Dock = DockStyle.Fill;
|
||||||
nameLabel.Size = new Size(Width - 20, 30);
|
|
||||||
nameLabel.Location = new Point(10, 100);
|
|
||||||
nameLabel.Font = new Font("Microsoft YaHei", 10, FontStyle.Bold);
|
nameLabel.Font = new Font("Microsoft YaHei", 10, FontStyle.Bold);
|
||||||
nameLabel.TextAlign = ContentAlignment.MiddleCenter;
|
nameLabel.TextAlign = ContentAlignment.MiddleCenter;
|
||||||
this.Controls.Add(nameLabel);
|
namePanel.Controls.Add(nameLabel);
|
||||||
|
|
||||||
|
// 初始主题设置
|
||||||
|
UpdateLabelTheme();
|
||||||
|
|
||||||
|
// 订阅主题变化事件
|
||||||
|
ThemeManager.ThemeChanged += (theme) => UpdateLabelTheme();
|
||||||
|
|
||||||
|
this.Controls.Add(namePanel);
|
||||||
|
|
||||||
// 打开按钮
|
// 打开按钮
|
||||||
var openButton = new Button();
|
var openButton = new Button();
|
||||||
@@ -68,10 +84,30 @@ namespace AppStore
|
|||||||
openButton.FlatAppearance.MouseDownBackColor = Color.FromArgb(0, 80, 160);
|
openButton.FlatAppearance.MouseDownBackColor = Color.FromArgb(0, 80, 160);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateLabelTheme()
|
||||||
|
{
|
||||||
|
if (ThemeManager.CurrentTheme == ThemeManager.ThemeMode.Dark)
|
||||||
|
{
|
||||||
|
nameLabel.BackColor = Color.Black;
|
||||||
|
nameLabel.ForeColor = Color.White;
|
||||||
|
namePanel.BackColor = Color.Black;
|
||||||
|
borderColor = Color.White;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nameLabel.BackColor = Color.White;
|
||||||
|
nameLabel.ForeColor = Color.Black;
|
||||||
|
namePanel.BackColor = Color.White;
|
||||||
|
borderColor = SystemColors.ControlDark;
|
||||||
|
}
|
||||||
|
namePanel.Invalidate(); // 触发重绘
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateDisplay()
|
public void UpdateDisplay()
|
||||||
{
|
{
|
||||||
nameLabel.Text = ToolName;
|
nameLabel.Text = ToolName;
|
||||||
iconBox.Image = ToolIcon;
|
iconBox.Image = ToolIcon;
|
||||||
|
UpdateLabelTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
img/resource/png/password_generator.png
Normal file
BIN
img/resource/png/password_generator.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 410 KiB |
@@ -2,7 +2,7 @@
|
|||||||
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
|
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
|
||||||
|
|
||||||
#define MyAppName "kortapp-z"
|
#define MyAppName "kortapp-z"
|
||||||
#define MyAppVersion "1.0.8"
|
#define MyAppVersion "1.1.3"
|
||||||
#define MyAppPublisher "zsyg"
|
#define MyAppPublisher "zsyg"
|
||||||
#define MyAppURL "https://github.com/zs-yg/kortapp-z"
|
#define MyAppURL "https://github.com/zs-yg/kortapp-z"
|
||||||
#define MyAppExeName "kortapp.exe"
|
#define MyAppExeName "kortapp.exe"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
|
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
|
||||||
|
|
||||||
#define MyAppName "kortapp-z"
|
#define MyAppName "kortapp-z"
|
||||||
#define MyAppVersion "1.0.8"
|
#define MyAppVersion "1.1.3"
|
||||||
#define MyAppPublisher "zsyg"
|
#define MyAppPublisher "zsyg"
|
||||||
#define MyAppURL "https://github.com/zs-yg/kortapp-z"
|
#define MyAppURL "https://github.com/zs-yg/kortapp-z"
|
||||||
#define MyAppExeName "kortapp.exe"
|
#define MyAppExeName "kortapp.exe"
|
||||||
|
|||||||
20
others/C++/password_generator/Makefile
Normal file
20
others/C++/password_generator/Makefile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
CXX = g++
|
||||||
|
CXXFLAGS = -std=c++11 -Iinclude
|
||||||
|
LDFLAGS = -static -mwindows -lfltk -lole32 -luuid -lcomctl32 -lgdi32 -lwsock32 -lcomdlg32 -lwinspool
|
||||||
|
|
||||||
|
SRC = $(wildcard src/*.cpp)
|
||||||
|
OBJ = $(patsubst src/%.cpp,obj/%.o,$(SRC))
|
||||||
|
TARGET = password_generator
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(OBJ)
|
||||||
|
$(CXX) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
obj/%.o: src/%.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ) $(TARGET)
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
27
others/C++/password_generator/include/password_generator.hpp
Normal file
27
others/C++/password_generator/include/password_generator.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef PASSWORD_GENERATOR_HPP
|
||||||
|
#define PASSWORD_GENERATOR_HPP
|
||||||
|
|
||||||
|
#include "string.hpp"
|
||||||
|
|
||||||
|
class PasswordGenerator {
|
||||||
|
public:
|
||||||
|
enum Mode {
|
||||||
|
DIGITS, // 纯数字
|
||||||
|
ENGLISH, // 纯英文
|
||||||
|
SYMBOLS, // 纯符号
|
||||||
|
DIGITS_ENGLISH, // 数字+英文
|
||||||
|
DIGITS_SYMBOLS, // 数字+符号
|
||||||
|
ENGLISH_SYMBOLS // 英文+符号
|
||||||
|
};
|
||||||
|
|
||||||
|
PasswordGenerator();
|
||||||
|
String generate(int length, Mode mode = DIGITS);
|
||||||
|
|
||||||
|
private:
|
||||||
|
String generateDigits(int length);
|
||||||
|
String generateEnglish(int length);
|
||||||
|
String generateSymbols(int length);
|
||||||
|
String generateMixed(int length, const String& charSet);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PASSWORD_GENERATOR_HPP
|
||||||
28
others/C++/password_generator/include/password_gui.hpp
Normal file
28
others/C++/password_generator/include/password_gui.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef PASSWORD_GUI_HPP
|
||||||
|
#define PASSWORD_GUI_HPP
|
||||||
|
|
||||||
|
#include <FL/Fl.H>
|
||||||
|
#include <FL/Fl_Window.H>
|
||||||
|
#include <FL/Fl_Input.H>
|
||||||
|
#include <FL/Fl_Choice.H>
|
||||||
|
#include <FL/Fl_Button.H>
|
||||||
|
#include <FL/Fl_Output.H>
|
||||||
|
#include "password_generator.hpp"
|
||||||
|
|
||||||
|
class PasswordGUI {
|
||||||
|
public:
|
||||||
|
PasswordGUI();
|
||||||
|
void show();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Fl_Window* window;
|
||||||
|
Fl_Input* lengthInput;
|
||||||
|
Fl_Choice* modeChoice;
|
||||||
|
Fl_Button* generateButton;
|
||||||
|
Fl_Output* passwordOutput;
|
||||||
|
PasswordGenerator generator;
|
||||||
|
|
||||||
|
static void onGenerate(Fl_Widget* widget, void* data);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PASSWORD_GUI_HPP
|
||||||
25
others/C++/password_generator/include/string.hpp
Normal file
25
others/C++/password_generator/include/string.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef STRING_HPP
|
||||||
|
#define STRING_HPP
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
class String {
|
||||||
|
public:
|
||||||
|
String();
|
||||||
|
String(const char* str);
|
||||||
|
String(const String& other);
|
||||||
|
~String();
|
||||||
|
|
||||||
|
size_t length() const;
|
||||||
|
const char* c_str() const;
|
||||||
|
|
||||||
|
String& operator=(const String& other);
|
||||||
|
String operator+(const String& other) const;
|
||||||
|
bool operator==(const String& other) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* data;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STRING_HPP
|
||||||
7
others/C++/password_generator/src/main.cpp
Normal file
7
others/C++/password_generator/src/main.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "password_gui.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
PasswordGUI gui;
|
||||||
|
gui.show();
|
||||||
|
return Fl::run();
|
||||||
|
}
|
||||||
96
others/C++/password_generator/src/password_generator.cpp
Normal file
96
others/C++/password_generator/src/password_generator.cpp
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#include "password_generator.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
PasswordGenerator::PasswordGenerator() {
|
||||||
|
srand(time(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
String PasswordGenerator::generate(int length, Mode mode) {
|
||||||
|
if (length < 1 || length > 100) {
|
||||||
|
return String("无效长度(1-100)");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case DIGITS:
|
||||||
|
return generateDigits(length);
|
||||||
|
case ENGLISH:
|
||||||
|
return generateEnglish(length);
|
||||||
|
case SYMBOLS:
|
||||||
|
return generateSymbols(length);
|
||||||
|
case DIGITS_ENGLISH: {
|
||||||
|
String charSet = String("0123456789") +
|
||||||
|
String("abcdefghijklmnopqrstuvwxyz") +
|
||||||
|
String("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
|
return generateMixed(length, charSet);
|
||||||
|
}
|
||||||
|
case DIGITS_SYMBOLS: {
|
||||||
|
String charSet = String("0123456789") + String("!@#$%^&*()_+-=[]{}|;:,.<>?");
|
||||||
|
return generateMixed(length, charSet);
|
||||||
|
}
|
||||||
|
case ENGLISH_SYMBOLS: {
|
||||||
|
String charSet = String("abcdefghijklmnopqrstuvwxyz") +
|
||||||
|
String("ABCDEFGHIJKLMNOPQRSTUVWXYZ") +
|
||||||
|
String("!@#$%^&*()_+-=[]{}|;:,.<>?");
|
||||||
|
return generateMixed(length, charSet);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return String("不支持的模式");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String PasswordGenerator::generateDigits(int length) {
|
||||||
|
char* buffer = new char[length + 1];
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
buffer[i] = '0' + (rand() % 10);
|
||||||
|
}
|
||||||
|
buffer[length] = '\0';
|
||||||
|
|
||||||
|
String result(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String PasswordGenerator::generateEnglish(int length) {
|
||||||
|
char* buffer = new char[length + 1];
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
int choice = rand() % 2;
|
||||||
|
if (choice == 0) {
|
||||||
|
buffer[i] = 'a' + (rand() % 26); // 小写字母
|
||||||
|
} else {
|
||||||
|
buffer[i] = 'A' + (rand() % 26); // 大写字母
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer[length] = '\0';
|
||||||
|
|
||||||
|
String result(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String PasswordGenerator::generateSymbols(int length) {
|
||||||
|
const char symbols[] = "!@#$%^&*()_+-=[]{}|;:,.<>?";
|
||||||
|
const int symbolCount = sizeof(symbols) - 1; // 减去末尾的\0
|
||||||
|
|
||||||
|
char* buffer = new char[length + 1];
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
buffer[i] = symbols[rand() % symbolCount];
|
||||||
|
}
|
||||||
|
buffer[length] = '\0';
|
||||||
|
|
||||||
|
String result(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String PasswordGenerator::generateMixed(int length, const String& charSet) {
|
||||||
|
char* buffer = new char[length + 1];
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
buffer[i] = charSet.c_str()[rand() % charSet.length()];
|
||||||
|
}
|
||||||
|
buffer[length] = '\0';
|
||||||
|
|
||||||
|
String result(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
36
others/C++/password_generator/src/password_gui.cpp
Normal file
36
others/C++/password_generator/src/password_gui.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include "password_gui.hpp"
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
PasswordGUI::PasswordGUI() {
|
||||||
|
window = new Fl_Window(400, 350, "密码生成器");
|
||||||
|
|
||||||
|
lengthInput = new Fl_Input(150, 50, 200, 30, "密码长度:");
|
||||||
|
modeChoice = new Fl_Choice(150, 90, 200, 30, "密码模式:");
|
||||||
|
modeChoice->add("纯数字");
|
||||||
|
modeChoice->add("纯英文");
|
||||||
|
modeChoice->add("纯符号");
|
||||||
|
modeChoice->add("数字+英文");
|
||||||
|
modeChoice->add("数字+符号");
|
||||||
|
modeChoice->add("英文+符号");
|
||||||
|
modeChoice->value(0); // 默认选择纯数字模式
|
||||||
|
|
||||||
|
generateButton = new Fl_Button(150, 140, 100, 40, "生成密码");
|
||||||
|
passwordOutput = new Fl_Output(100, 210, 250, 40, "生成结果:");
|
||||||
|
|
||||||
|
generateButton->callback(onGenerate, this);
|
||||||
|
window->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PasswordGUI::show() {
|
||||||
|
window->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PasswordGUI::onGenerate(Fl_Widget* widget, void* data) {
|
||||||
|
PasswordGUI* gui = static_cast<PasswordGUI*>(data);
|
||||||
|
const char* lengthStr = gui->lengthInput->value();
|
||||||
|
int length = atoi(lengthStr);
|
||||||
|
|
||||||
|
PasswordGenerator::Mode mode = static_cast<PasswordGenerator::Mode>(gui->modeChoice->value());
|
||||||
|
String password = gui->generator.generate(length, mode);
|
||||||
|
gui->passwordOutput->value(password.c_str());
|
||||||
|
}
|
||||||
51
others/C++/password_generator/src/string.cpp
Normal file
51
others/C++/password_generator/src/string.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "string.hpp"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
String::String() : data(nullptr), len(0) {}
|
||||||
|
|
||||||
|
String::String(const char* str) {
|
||||||
|
len = strlen(str);
|
||||||
|
data = new char[len + 1];
|
||||||
|
strcpy(data, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String(const String& other) {
|
||||||
|
len = other.len;
|
||||||
|
data = new char[len + 1];
|
||||||
|
strcpy(data, other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::~String() {
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t String::length() const {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* String::c_str() const {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
String& String::operator=(const String& other) {
|
||||||
|
if (this != &other) {
|
||||||
|
delete[] data;
|
||||||
|
len = other.len;
|
||||||
|
data = new char[len + 1];
|
||||||
|
strcpy(data, other.data);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::operator+(const String& other) const {
|
||||||
|
String result;
|
||||||
|
result.len = len + other.len;
|
||||||
|
result.data = new char[result.len + 1];
|
||||||
|
strcpy(result.data, data);
|
||||||
|
strcat(result.data, other.data);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String::operator==(const String& other) const {
|
||||||
|
return strcmp(data, other.data) == 0;
|
||||||
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
ren bin\Release\net8.0-windows\win-x86\publish\AppStore.exe kortapp.exe
|
ren bin\Release\net8.0-windows\win-x86\publish\AppStore.exe kortapp-z.exe
|
||||||
ren bin\Release\net8.0-windows\win-x64\publish\AppStore.exe kortapp.exe
|
ren bin\Release\net8.0-windows\win-x64\publish\AppStore.exe kortapp-z.exe
|
||||||
BIN
resource/password_generator.exe
Normal file
BIN
resource/password_generator.exe
Normal file
Binary file not shown.
21
tools/viewer/IImageViewer.cs
Normal file
21
tools/viewer/IImageViewer.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace KortAppZ.Tools.Viewer
|
||||||
|
{
|
||||||
|
public interface IImageViewer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 加载图片文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">图片文件路径</param>
|
||||||
|
void LoadImage(string filePath);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 显示图片
|
||||||
|
/// </summary>
|
||||||
|
void ShowImage();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 关闭图片查看器
|
||||||
|
/// </summary>
|
||||||
|
void CloseViewer();
|
||||||
|
}
|
||||||
|
}
|
||||||
75
tools/viewer/ImageDisplayForm.cs
Normal file
75
tools/viewer/ImageDisplayForm.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace KortAppZ.Tools.Viewer
|
||||||
|
{
|
||||||
|
public class ImageDisplayForm : Form
|
||||||
|
{
|
||||||
|
private PictureBox? pictureBox;
|
||||||
|
private Image? currentImage;
|
||||||
|
|
||||||
|
public ImageDisplayForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.pictureBox = new PictureBox();
|
||||||
|
//
|
||||||
|
// pictureBox
|
||||||
|
//
|
||||||
|
this.pictureBox.Dock = DockStyle.Fill;
|
||||||
|
this.pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
|
||||||
|
this.pictureBox.BackColor = Color.Black;
|
||||||
|
//
|
||||||
|
// ImageDisplayForm
|
||||||
|
//
|
||||||
|
this.Text = "图片查看";
|
||||||
|
this.ClientSize = new Size(800, 600);
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = true;
|
||||||
|
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
this.ControlBox = true;
|
||||||
|
this.ShowIcon = true;
|
||||||
|
this.MaximizedBounds = Screen.FromHandle(this.Handle).WorkingArea;
|
||||||
|
this.Controls.Add(this.pictureBox);
|
||||||
|
this.FormClosing += new FormClosingEventHandler(ImageDisplayForm_FormClosing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadImage(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (currentImage != null)
|
||||||
|
{
|
||||||
|
currentImage.Dispose();
|
||||||
|
currentImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentImage = ImageFileHandler.LoadImage(filePath);
|
||||||
|
if (pictureBox != null)
|
||||||
|
{
|
||||||
|
pictureBox.Image = currentImage;
|
||||||
|
}
|
||||||
|
this.Text = $"图片查看 - {Path.GetFileName(filePath)}";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"无法加载图片: {ex.Message}", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ImageDisplayForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
|
{
|
||||||
|
if (currentImage != null)
|
||||||
|
{
|
||||||
|
currentImage.Dispose();
|
||||||
|
currentImage = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
tools/viewer/ImageFileHandler.cs
Normal file
41
tools/viewer/ImageFileHandler.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace KortAppZ.Tools.Viewer
|
||||||
|
{
|
||||||
|
public static class ImageFileHandler
|
||||||
|
{
|
||||||
|
private static readonly string[] SupportedExtensions =
|
||||||
|
{
|
||||||
|
".jpg", ".jpeg", ".png", ".bmp", ".gif", ".tiff", ".tif"
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool IsImageFile(string filePath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(filePath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string extension = Path.GetExtension(filePath).ToLower();
|
||||||
|
return Array.Exists(SupportedExtensions, ext => ext == extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Image LoadImage(string filePath)
|
||||||
|
{
|
||||||
|
if (!IsImageFile(filePath))
|
||||||
|
throw new ArgumentException("不支持的图片格式");
|
||||||
|
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
throw new FileNotFoundException("图片文件不存在", filePath);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Image.FromFile(filePath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"无法加载图片: {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
tools/viewer/ImageViewerForm.cs
Normal file
93
tools/viewer/ImageViewerForm.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
using KortAppZ.Tools.Viewer;
|
||||||
|
|
||||||
|
namespace KortAppZ.Tools.Viewer
|
||||||
|
{
|
||||||
|
public class ImageViewerForm : Form
|
||||||
|
{
|
||||||
|
private Button? openButton;
|
||||||
|
|
||||||
|
public ImageViewerForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.openButton = new Button();
|
||||||
|
//
|
||||||
|
// openButton
|
||||||
|
//
|
||||||
|
this.openButton.Text = "打开图片";
|
||||||
|
this.openButton.Size = new Size(120, 40);
|
||||||
|
this.openButton.Font = new Font("Microsoft YaHei", 10);
|
||||||
|
this.openButton.Anchor = AnchorStyles.None;
|
||||||
|
this.openButton.Click += new EventHandler(OpenButton_Click);
|
||||||
|
|
||||||
|
// 初始位置
|
||||||
|
CenterOpenButton();
|
||||||
|
|
||||||
|
// 窗体大小变化时重新居中按钮
|
||||||
|
this.Resize += (s, e) => CenterOpenButton();
|
||||||
|
|
||||||
|
//
|
||||||
|
// ImageViewerForm
|
||||||
|
//
|
||||||
|
this.Text = "图片查看器";
|
||||||
|
this.ClientSize = new Size(400, 300);
|
||||||
|
this.StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
this.MinimumSize = new Size(300, 200);
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
this.MaximizedBounds = Screen.FromHandle(this.Handle).WorkingArea;
|
||||||
|
this.Controls.Add(this.openButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CenterOpenButton()
|
||||||
|
{
|
||||||
|
if (openButton != null)
|
||||||
|
{
|
||||||
|
openButton.Location = new Point(
|
||||||
|
(this.ClientSize.Width - openButton.Width) / 2,
|
||||||
|
(this.ClientSize.Height - openButton.Height) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenButton_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||||
|
openFileDialog.Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff;*.tif|所有文件|*.*";
|
||||||
|
|
||||||
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
string filePath = openFileDialog.FileName;
|
||||||
|
ShowImage(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowImage(string filePath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!ImageFileHandler.IsImageFile(filePath))
|
||||||
|
{
|
||||||
|
MessageBox.Show("不支持的图片格式", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageDisplayForm displayForm = new ImageDisplayForm();
|
||||||
|
displayForm.LoadImage(filePath);
|
||||||
|
displayForm.Show();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"无法加载图片: {ex.Message}", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
tools/viewer/ImageViewerToolCard.cs
Normal file
48
tools/viewer/ImageViewerToolCard.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
using AppStore;
|
||||||
|
|
||||||
|
namespace KortAppZ.Tools.Viewer
|
||||||
|
{
|
||||||
|
public class ImageViewerToolCard : ToolCard
|
||||||
|
{
|
||||||
|
public ImageViewerToolCard()
|
||||||
|
{
|
||||||
|
this.ToolName = "图片查看";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string iconPath = Path.Combine(Application.StartupPath, "img", "resource", "png", "ImageCompressor.png");
|
||||||
|
if (File.Exists(iconPath))
|
||||||
|
{
|
||||||
|
this.ToolIcon = Image.FromFile(iconPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.ToolIcon = SystemIcons.Application.ToBitmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
this.ToolIcon = SystemIcons.Application.ToBitmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ToolCardClicked += (s, e) => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ImageViewerForm viewerForm = new ImageViewerForm();
|
||||||
|
viewerForm.Show();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"打开图片查看器失败: {ex.Message}", "错误",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.UpdateDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user