Compare commits

..

15 Commits

Author SHA1 Message Date
zsyg
d454ac0fdc 允许自定义下载路径 2025-07-02 10:10:02 +08:00
zsyg
d5c83d854c 删除没有必要的文件 2025-07-02 09:17:44 +08:00
zsyg
1c2bc713be 提高代码质量 2025-07-02 09:16:18 +08:00
zsyg
1539c665f0 提供代码质量 2025-07-02 09:15:43 +08:00
zsyg
074e55fbbc Add files via upload 2025-07-02 09:14:43 +08:00
zsyg
334fa56070 修复代码潜在问题 2025-07-02 09:12:49 +08:00
zsyg
0268e13b56 Add files via upload 2025-07-01 19:02:06 +08:00
zsyg
cba6c9eeca Update README.md 2025-07-01 11:31:02 +08:00
zsyg
70a776125a 修改密码生成器代码位置 2025-07-01 10:34:32 +08:00
zsyg
f7250dae08 修复主题系统带来的颜色 2025-07-01 10:26:26 +08:00
zsyg
ac93c8418f Add files via upload 2025-06-30 20:25:25 +08:00
zsyg
5a49714ed7 Add files via upload 2025-06-30 20:22:07 +08:00
zsyg
19056a1a8c Add files via upload 2025-06-30 20:21:19 +08:00
zsyg
7c4250f912 Add files via upload 2025-06-30 20:20:48 +08:00
zsyg
d056c24a1b Add files via upload 2025-06-30 20:20:21 +08:00
25 changed files with 2166 additions and 1466 deletions

View File

@@ -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.1.0\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);

View File

@@ -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++程序计算高性能边框路径并缓存结果
@@ -310,8 +347,14 @@ namespace AppStore
public void UpdateDisplay() public void UpdateDisplay()
{ {
nameLabel.Text = AppName; if (nameLabel != null)
iconBox.Image = AppIcon; {
nameLabel.Text = AppName;
}
if (iconBox != null && AppIcon != null)
{
iconBox.Image = AppIcon;
}
} }
private void DownloadBtn_Click(object sender, EventArgs e) private void DownloadBtn_Click(object sender, EventArgs e)

57
AppSearch.cs Normal file
View 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);
}
}
}

View File

@@ -33,4 +33,8 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="ZXing.Net" Version="0.16.9" />
</ItemGroup>
</Project> </Project>

View File

@@ -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);
} }

View File

@@ -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,36 +86,39 @@ 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("下载路径为空");
} }
// 尝试创建目录(如果不存在)
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");
downloadsDir = Marshal.PtrToStringUni(pathPtr); Logger.LogError($"下载路径{downloadsDir}不可用,将使用默认路径: {defaultPath}", ex);
downloadsDir = defaultPath;
Directory.CreateDirectory(downloadsDir);
} }
catch
{
throw new Exception("无法确定下载文件夹位置,请手动指定下载路径");
}
finally
{
if (pathPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pathPtr);
}
}
Directory.CreateDirectory(downloadsDir);
@@ -309,12 +313,20 @@ namespace AppStore
currentProcess.BeginErrorReadLine(); currentProcess.BeginErrorReadLine();
progressTimer.Start(); progressTimer.Start();
} }
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);
}
} }
public void CancelDownload(DownloadItem item) public void CancelDownload(DownloadItem item)
@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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都会被删除
## 项目简介 ## 项目简介

View File

@@ -1,53 +1,223 @@
using System; 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;
namespace AppStore using System.Text.Json;
{
public class SettingsUserControl : UserControl namespace AppStore
{ {
private Button btnCleanLogs; public class SettingsUserControl : UserControl
{
public SettingsUserControl() private Button btnCleanLogs;
{ private Button btnLightTheme;
this.Dock = DockStyle.Fill; private Button btnDarkTheme;
this.BackColor = Color.White;
public SettingsUserControl()
// 设置顶部内边距 {
this.Padding = new Padding(0, 30, 0, 0); this.Dock = DockStyle.Fill;
ThemeManager.ApplyTheme(this);
btnCleanLogs = new Button();
btnCleanLogs.Text = "清理日志"; // 设置顶部内边距
btnCleanLogs.Size = new Size(150, 40); this.Padding = new Padding(0, 30, 0, 0);
btnCleanLogs.Location = new Point((this.Width - 150) / 2, 50); // 调整Y坐标为50靠近顶部
btnCleanLogs.Font = new Font("Microsoft YaHei", 10); // 主题切换按钮
btnCleanLogs.Anchor = AnchorStyles.Top; // 添加顶部锚点 btnLightTheme = new Button();
btnCleanLogs.Click += (s, e) => CleanLogs(); btnLightTheme.Text = "浅色模式";
this.Controls.Add(btnCleanLogs); btnLightTheme.Size = new Size(150, 40);
} btnLightTheme.Location = new Point((this.Width - 320) / 2, 50);
btnLightTheme.Font = new Font("Microsoft YaHei", 10);
private void CleanLogs() btnLightTheme.Anchor = AnchorStyles.Top;
{ btnLightTheme.Click += (s, e) => SwitchTheme(ThemeManager.ThemeMode.Light);
try this.Controls.Add(btnLightTheme);
{
string logCleanerPath = Path.Combine("resource", "log_cleaner.exe"); btnDarkTheme = new Button();
btnDarkTheme.Text = "深色模式";
if (File.Exists(logCleanerPath)) btnDarkTheme.Size = new Size(150, 40);
{ btnDarkTheme.Location = new Point(btnLightTheme.Right + 20, 50);
Process.Start(logCleanerPath); btnDarkTheme.Font = new Font("Microsoft YaHei", 10);
MessageBox.Show("日志清理程序已启动", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); btnDarkTheme.Anchor = AnchorStyles.Top;
} btnDarkTheme.Click += (s, e) => SwitchTheme(ThemeManager.ThemeMode.Dark);
else this.Controls.Add(btnDarkTheme);
{
MessageBox.Show("日志清理程序未找到", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); // 清理日志按钮
} btnCleanLogs = new Button();
} btnCleanLogs.Text = "清理日志";
catch (Exception ex) btnCleanLogs.Size = new Size(150, 40);
{ btnCleanLogs.Location = new Point((this.Width - 150) / 2, 110);
Logger.LogError("清理日志时出错", ex); btnCleanLogs.Font = new Font("Microsoft YaHei", 10);
MessageBox.Show($"清理日志时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); btnCleanLogs.Anchor = AnchorStyles.Top;
} btnCleanLogs.Click += (s, e) => CleanLogs();
} 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()
{
try
{
string logCleanerPath = Path.Combine("resource", "log_cleaner.exe");
if (File.Exists(logCleanerPath))
{
Process.Start(logCleanerPath);
MessageBox.Show("日志清理程序已启动", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("日志清理程序未找到", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
Logger.LogError("清理日志时出错", ex);
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;
}
}
}
}

129
ThemeManager.cs Normal file
View 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);
}
}
}
}

View File

@@ -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();
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 KiB

View File

@@ -2,7 +2,7 @@
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档! ; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z" #define MyAppName "kortapp-z"
#define MyAppVersion "1.1.0" #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"

View File

@@ -2,7 +2,7 @@
; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档! ; 有关创建 Inno Setup 脚本文件的详细信息,请参阅帮助文档!
#define MyAppName "kortapp-z" #define MyAppName "kortapp-z"
#define MyAppVersion "1.1.0" #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"

View File

@@ -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

View File

@@ -50,7 +50,10 @@ namespace KortAppZ.Tools.Viewer
} }
currentImage = ImageFileHandler.LoadImage(filePath); currentImage = ImageFileHandler.LoadImage(filePath);
pictureBox.Image = currentImage; if (pictureBox != null)
{
pictureBox.Image = currentImage;
}
this.Text = $"图片查看 - {Path.GetFileName(filePath)}"; this.Text = $"图片查看 - {Path.GetFileName(filePath)}";
} }
catch (Exception ex) catch (Exception ex)