diff --git a/Update/Update/MainForm.cs b/Update/Update/MainForm.cs index d13581f..91a0f6f 100644 --- a/Update/Update/MainForm.cs +++ b/Update/Update/MainForm.cs @@ -1,8 +1,10 @@ -using System; +using COSXML.Network; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; +using System.Drawing.Drawing2D; using System.IO; using System.IO.Compression; using System.Linq; @@ -12,307 +14,597 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using static Update.ChangelogTheme; namespace Update { - public partial class MainForm : Form - { - public string Title { get { return Text; } set { Text = value; } } - private Point mouseOffset; // 记录鼠标指针的坐标 - private bool isMouseDown; // 记录鼠标左键是否按下 + public partial class MainForm : Form + { + public string Title { get { return Text; } set { Text = value; } } + private Point mouseOffset; // 记录鼠标指针的坐标 + private bool isMouseDown; // 记录鼠标左键是否按下 - public MainForm() - { - InitializeComponent(); + public MainForm() + { + InitializeComponent(); - this.TopMost = true; - } + this.TopMost = true; + lb_title.Text = "更新日志"; - private void MessageForm_Paint(object sender, PaintEventArgs e) - { - SetFormRoundRectRgn(this, 7); - SetFormRoundRectRgn(panel2, 7); - SetFormRoundRectRgn(this.btnOk, 7); - SetFormRoundRectRgn(this.btnCancel, 7); - } + var changelogItems = GetChangeInfos(); + if (changelogItems != null) + { - private void btnOk_Click(object sender, EventArgs e) - { - if (lblMessage.Text == "升级完成,点击确定重启程序") - { - string extPath = System.Environment.CurrentDirectory + "\\" + Program.softName.Replace(".exe", "") + ".exe"; - System.Diagnostics.Process.Start(extPath); - Application.Exit(); - return; - } + string fromVersion = (Program.oldVersion / 100m).ToString(); + string toVersion = (Program.newVersion / 100m).ToString(); + ShowChangelog(fromVersion, toVersion, changelogItems); + } - btnOk.Enabled = false; + //// 演示数据:v1.0.0 升级到 v1.3.0,展示 1.1.0 ~ 1.3.0(新的在上) + //ShowChangelog("1.0.0", "1.3.0", new[] + //{ + // new ChangelogItem { Version = "1.3.0", PublishedAt = "2026-10-10", Notes = "新增深色模式,支持跟随系统\n新增快捷键面板(Ctrl + /)\n启动速度提升 40%" }, + // new ChangelogItem { Version = "1.2.0", PublishedAt = "2026-09-05", Notes = "支持导出数据为 Excel 格式\n优化列表滚动性能\n修复偶发的保存失败问题" }, + // new ChangelogItem { Version = "1.1.0", PublishedAt = "2026-08-01", Notes = "新增自动更新功能\n修复高分屏下界面模糊的问题" }, + //}); + } + private List GetChangeInfos() + { + string paidanUrl = $"https://update-wx-order.e57.cn"; + string shanghuoUrl = $"https://update.e57.cn"; + using (WebClient c = new WebClient()) + { + c.Encoding = Encoding.UTF8; + string url = $"/api/releases/since?version={(Program.oldVersion / 100m)}&channel=stable"; + if (Program.softName == "29WxFindOrder") + { + url = paidanUrl + url; + } + else if (Program.softName == "29供应链.exe") + url = shanghuoUrl + url; + string json = c.DownloadString(url); + var root = MiniJson.Json.Deserialize(json) as Dictionary; + if (root["ok"].ToString() == "True") + { + var data = (Dictionary)root["data"]; + var versionsRaw = (List)data["versions"]; - CloseMainProgram(); + var list = new List(); + foreach (Dictionary item in versionsRaw) + { + var ci = new ChangelogItem + { + Version = item["version"]?.ToString(), + Notes = item["notes"]?.ToString(), + }; - if (!System.IO.Directory.Exists("upBak")) - System.IO.Directory.CreateDirectory("upBak"); - var upBakPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upBak"; - if (!System.IO.Directory.Exists("upTemp")) - System.IO.Directory.CreateDirectory("upTemp"); - var upTempPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upTemp"; + if (DateTime.TryParse(item["publishedAt"]?.ToString(), out DateTime v)) + { + ci.PublishedAt = v.ToString("yyyy-MM-dd"); + } + list.Add(ci); + } + return list; + } + } + return null; + } - // 清空文件夹准备下载 - foreach (string filePath in Directory.GetFiles(upTempPath)) - { - File.Delete(filePath); // 删除文件 - } - foreach (string dirPath in Directory.GetDirectories(upTempPath)) - { - Directory.Delete(dirPath, true); // 删除子文件夹及其内容 - } + /// + /// 渲染更新日志:头部展示版本区间,中间按版本分组列出更新条目 + /// + private void ShowChangelog(string fromVersion, string toVersion, IEnumerable entries) + { + int length = entries.Count(); + lblHeroTitle.Text = "v" + fromVersion + " → v" + toVersion; + lblHeroMeta.Text = length > 1 ? "共包含 " + length + " 个版本的更新内容" : "本次更新内容"; - this.lblMessage.Text = "升级中请稍候..."; - progressBar1.Visible = true; - progressBar1.Maximum = 100;//fileNameArr.Count(); - progressBar1.Value = 0; - Task.Run(async() => - { - string tempFile = upTempPath + "\\" + Program.updateUrl.Substring(Program.updateUrl.LastIndexOf("/") + 1); - //bool result = Program.DownloadFile(Program.updateUrl, tempFile); + panelChangelog.SuspendLayout(); + panelChangelog.Controls.Clear(); - //while (true) - //{ - // Invoke(new Action(() => - // { - // progressBar1.Value = Program.progress; - // })); - // if (Program.progress == 100) - // break; - //} + var blocks = entries.Select((entry, i) => new ChangelogBlock(entry, i == 0, panelChangelog.Width)).ToList(); + int contentHeight = blocks.Sum(b => b.Height); - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - using (var downloadClient = new WebClient()) - { - downloadClient.Proxy = null; + // 内容超出可视区时预留垂直滚动条宽度,避免出现横向滚动条 + int width = panelChangelog.ClientSize.Width; + if (contentHeight > panelChangelog.ClientSize.Height) + width -= SystemInformation.VerticalScrollBarWidth; - downloadClient.DownloadProgressChanged += (s, args) => - { - Invoke(new Action(() => { progressBar1.Value = args.ProgressPercentage; })); - - }; + int y = 6; + foreach (var block in blocks) + { + block.Width = width; + block.Location = new Point(0, y); + y += block.Height; + panelChangelog.Controls.Add(block); + } + panelChangelog.ResumeLayout(true); + } - await downloadClient.DownloadFileTaskAsync(new Uri(Program.updateUrl), tempFile); - } + private void heroPanel_Paint(object sender, PaintEventArgs e) + { + var panel = (Panel)sender; + if (panel.Width <= 0 || panel.Height <= 0) + return; - if (1 == 1) - //if (result) - { - ZipFile.ExtractToDirectory(tempFile, upTempPath); - File.Delete(tempFile); + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + using (var brush = new LinearGradientBrush(panel.ClientRectangle, AccentBg, Color.White, 40F)) + e.Graphics.FillRectangle(brush, panel.ClientRectangle); - string mainPath = System.Environment.CurrentDirectory; - // 备份旧文件 - foreach (string filePath in Directory.GetFiles(upTempPath)) - { - try - { - string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1); - File.Copy(mainPath + "\\" + fileName, upBakPath + "\\" + fileName, true); - Thread.Sleep(10); - } - catch - { - } - } - foreach (string dirPath in Directory.GetDirectories(upTempPath)) - { - try - { - string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1); - CopyDirectory(mainPath + "\\" + fileName, upBakPath + "\\" + fileName); - Thread.Sleep(10); - } - catch - { - } - } + using (var pen = new Pen(LineColor)) + { + e.Graphics.DrawLine(pen, 0, 0, panel.Width, 0); + e.Graphics.DrawLine(pen, 0, panel.Height - 1, panel.Width, panel.Height - 1); + } + } - string error = ""; - // 替换旧文件 - foreach (string filePath in Directory.GetFiles(upTempPath)) - { - if (!string.IsNullOrEmpty(error)) - { - error = "发生错误:\r\n" + error + "\r\n请关闭升级窗口重试!"; - break; - } - try - { - string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1); - File.Copy(upTempPath + "\\" + fileName, mainPath + "\\" + fileName, true); - Thread.Sleep(10); - } - catch (Exception ex) - { - error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!"; - Invoke(new Action(() => - { - lblMessage.Text = error; - })); - } - } - foreach (string dirPath in Directory.GetDirectories(upTempPath)) - { - if (!string.IsNullOrEmpty(error)) - break; - try - { - string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1); - CopyDirectory(upTempPath + "\\" + fileName, mainPath + "\\" + fileName); - Thread.Sleep(10); - } - catch (Exception ex) - { - error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!"; - Invoke(new Action(() => - { - lblMessage.Text = error; - })); - } - } - Thread.Sleep(50); - Invoke(new Action(() => - { - if (string.IsNullOrEmpty(error)) - { - progressBar1.Value = 100; - lblMessage.Text = "升级完成,点击确定重启程序"; - btnOk.Enabled = true; - } - })); - } - else - { - Invoke(new Action(() => - { - progressBar1.Value = 100; - this.lblMessage.Text = "升级失败,未获取到升级文件"; - btnOk.Enabled = true; - })); - } - }); - } + private void btnOk_Click(object sender, EventArgs e) + { + if (lblMessage.Text == "升级完成,点击确定重启程序") + { + string extPath = System.Environment.CurrentDirectory + "\\" + Program.softName.Replace(".exe", "") + ".exe"; + System.Diagnostics.Process.Start(extPath); + Application.Exit(); + return; + } - /// - /// 拷贝文档目录 - /// - /// - /// - public static void CopyDirectory(string srcPath, string destPath) - { - try - { - DirectoryInfo dir = new DirectoryInfo(srcPath); - FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录 - foreach (FileSystemInfo i in fileinfo) - { - if (i is DirectoryInfo) //判断是否文件夹 - { - if (!Directory.Exists(destPath + "\\" + i.Name)) - { - Directory.CreateDirectory(destPath + "\\" + i.Name); //目标目录下不存在此文件夹即创建子文件夹 - } - CopyDirectory(i.FullName, destPath + "\\" + i.Name); //递归调用复制子文件夹 - } - else - { - File.Copy(i.FullName, destPath + "\\" + i.Name, true); //不是文件夹即复制文件,true表示可以覆盖同名文件 - } - } - } - catch (Exception e) - { - throw; - } - } + btnOk.Enabled = false; - private void btnCancel_Click(object sender, EventArgs e) - { - this.Close(); - } + CloseMainProgram(); - private void panel1_MouseDown(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - mouseOffset = new Point(-e.X, -e.Y); - isMouseDown = true; - } - } + if (!System.IO.Directory.Exists("upBak")) + System.IO.Directory.CreateDirectory("upBak"); + var upBakPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upBak"; + if (!System.IO.Directory.Exists("upTemp")) + System.IO.Directory.CreateDirectory("upTemp"); + var upTempPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "upTemp"; - private void panel1_MouseUp(object sender, MouseEventArgs e) - { - isMouseDown = false; - } + // 清空文件夹准备下载 + foreach (string filePath in Directory.GetFiles(upTempPath)) + { + File.Delete(filePath); // 删除文件 + } + foreach (string dirPath in Directory.GetDirectories(upTempPath)) + { + Directory.Delete(dirPath, true); // 删除子文件夹及其内容 + } - private void panel1_MouseMove(object sender, MouseEventArgs e) - { - if (isMouseDown) - { - // 获取鼠标的位置 - Point mousePos = MousePosition; - mousePos.Offset(mouseOffset.X, mouseOffset.Y); - Location = mousePos; - } - } + this.lblMessage.Text = "升级中请稍候..."; + progressBar1.Visible = true; + progressBar1.Maximum = 100;//fileNameArr.Count(); + progressBar1.Value = 0; + Task.Run(async () => + { + string tempFile = upTempPath + "\\" + Program.updateUrl.Substring(Program.updateUrl.LastIndexOf("/") + 1); + //bool result = Program.DownloadFile(Program.updateUrl, tempFile); - public static void SetFormRoundRectRgn(Control c, int rgnRadius) - { - int hRgn = 0; - hRgn = Win32.CreateRoundRectRgn(0, 0, c.Width + 1, c.Height + 1, rgnRadius, rgnRadius); - Win32.SetWindowRgn(c.Handle, hRgn, true); - Win32.DeleteObject(hRgn); - } + //while (true) + //{ + // Invoke(new Action(() => + // { + // progressBar1.Value = Program.progress; + // })); + // if (Program.progress == 100) + // break; + //} - private void btnClose_Click(object sender, EventArgs e) - { - Application.Exit(); - } + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + using (var downloadClient = new WebClient()) + { + downloadClient.Proxy = null; - private void CloseMainProgram() - { - string in_sAppName = Program.softName; //(一个word文档程序) - in_sAppName = in_sAppName.Replace(".exe", ""); + downloadClient.DownloadProgressChanged += (s, args) => + { + Invoke(new Action(() => { progressBar1.Value = args.ProgressPercentage; })); - try - { - System.Diagnostics.Process[] psiNewcas = System.Diagnostics.Process.GetProcessesByName(in_sAppName); - //System.Diagnostics.Process.GetProcessesByName(""); + }; - //var pro = System.Diagnostics.Process.GetProcesses(); - //foreach(var p in pro) - //{ - // Console.WriteLine(p.ProcessName); - //} + await downloadClient.DownloadFileTaskAsync(new Uri(Program.updateUrl), tempFile); + } - foreach (System.Diagnostics.Process p in psiNewcas) - { - p.Kill(); - //p.WaitForExit(); - //p.Close(); - //Console.WriteLine(in_sAppName + "已经停止了"); - } - } - catch - { - Console.WriteLine(in_sAppName + "停止失败"); - } - } - } + if (1 == 1) + //if (result) + { + ZipFile.ExtractToDirectory(tempFile, upTempPath); + File.Delete(tempFile); - public enum FormLevel - { - SMALL, - MEDIUM, - LARGE = 500 - } + string mainPath = System.Environment.CurrentDirectory; + // 备份旧文件 + foreach (string filePath in Directory.GetFiles(upTempPath)) + { + try + { + string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1); + File.Copy(mainPath + "\\" + fileName, upBakPath + "\\" + fileName, true); + Thread.Sleep(10); + } + catch + { + } + } + foreach (string dirPath in Directory.GetDirectories(upTempPath)) + { + try + { + string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1); + CopyDirectory(mainPath + "\\" + fileName, upBakPath + "\\" + fileName); + Thread.Sleep(10); + } + catch + { + } + } + + string error = ""; + // 替换旧文件 + foreach (string filePath in Directory.GetFiles(upTempPath)) + { + if (!string.IsNullOrEmpty(error)) + { + error = "发生错误:\r\n" + error + "\r\n请关闭升级窗口重试!"; + break; + } + try + { + string fileName = filePath.Substring(filePath.LastIndexOf("\\") + 1); + File.Copy(upTempPath + "\\" + fileName, mainPath + "\\" + fileName, true); + Thread.Sleep(10); + } + catch (Exception ex) + { + error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!"; + Invoke(new Action(() => + { + lblMessage.Text = error; + })); + } + } + foreach (string dirPath in Directory.GetDirectories(upTempPath)) + { + if (!string.IsNullOrEmpty(error)) + break; + try + { + string fileName = dirPath.Substring(dirPath.LastIndexOf("\\") + 1); + CopyDirectory(upTempPath + "\\" + fileName, mainPath + "\\" + fileName); + Thread.Sleep(10); + } + catch (Exception ex) + { + error = "发生错误:\r\n" + ex.Message + "\r\n请关闭升级窗口重试!"; + Invoke(new Action(() => + { + lblMessage.Text = error; + })); + } + } + + Thread.Sleep(50); + Invoke(new Action(() => + { + if (string.IsNullOrEmpty(error)) + { + progressBar1.Value = 100; + lblMessage.Text = "升级完成,点击确定重启程序"; + btnOk.Enabled = true; + } + })); + } + else + { + Invoke(new Action(() => + { + progressBar1.Value = 100; + this.lblMessage.Text = "升级失败,未获取到升级文件"; + btnOk.Enabled = true; + })); + } + }); + } + + /// + /// 拷贝文档目录 + /// + /// + /// + public static void CopyDirectory(string srcPath, string destPath) + { + try + { + DirectoryInfo dir = new DirectoryInfo(srcPath); + FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录 + foreach (FileSystemInfo i in fileinfo) + { + if (i is DirectoryInfo) //判断是否文件夹 + { + if (!Directory.Exists(destPath + "\\" + i.Name)) + { + Directory.CreateDirectory(destPath + "\\" + i.Name); //目标目录下不存在此文件夹即创建子文件夹 + } + CopyDirectory(i.FullName, destPath + "\\" + i.Name); //递归调用复制子文件夹 + } + else + { + File.Copy(i.FullName, destPath + "\\" + i.Name, true); //不是文件夹即复制文件,true表示可以覆盖同名文件 + } + } + } + catch (Exception e) + { + throw; + } + } + + private void btnCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void panel1_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + mouseOffset = new Point(-e.X, -e.Y); + isMouseDown = true; + } + } + + private void panel1_MouseUp(object sender, MouseEventArgs e) + { + isMouseDown = false; + } + + private void panel1_MouseMove(object sender, MouseEventArgs e) + { + if (isMouseDown) + { + // 获取鼠标的位置 + Point mousePos = MousePosition; + mousePos.Offset(mouseOffset.X, mouseOffset.Y); + Location = mousePos; + } + } + + + + private void btnClose_Click(object sender, EventArgs e) + { + Application.Exit(); + } + + private void CloseMainProgram() + { + string in_sAppName = Program.softName; //(一个word文档程序) + in_sAppName = in_sAppName.Replace(".exe", ""); + + try + { + System.Diagnostics.Process[] psiNewcas = System.Diagnostics.Process.GetProcessesByName(in_sAppName); + //System.Diagnostics.Process.GetProcessesByName(""); + + //var pro = System.Diagnostics.Process.GetProcesses(); + //foreach(var p in pro) + //{ + // Console.WriteLine(p.ProcessName); + //} + + foreach (System.Diagnostics.Process p in psiNewcas) + { + p.Kill(); + //p.WaitForExit(); + //p.Close(); + //Console.WriteLine(in_sAppName + "已经停止了"); + } + } + catch + { + Console.WriteLine(in_sAppName + "停止失败"); + } + } + + private void panel2_Paint(object sender, PaintEventArgs e) + { + + } + } + public class Changelog + { + public bool Ok { get; set; } + public ChangelogData Data { get; set; } + } + public class ChangelogData + { + public List versions { get; set; } + } + /// + /// 单个版本的更新日志 + /// + public class ChangelogItem + { + public string Version { get; set; } + public string PublishedAt { get; set; } + public string Notes { get; set; } + + public string[] Items + { + get + { + string[] temp = new string[0]; + if (string.IsNullOrEmpty(Notes)) return temp; + return Notes.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + } + } + + } + + /// + /// 更新日志中的单个版本区块:版本标题行(色条 + 版本号 + 最新标记 + 日期)与条目列表 + /// + public class ChangelogBlock : Panel + { + private const int LeftPad = 28; + private const int RightPad = 28; + private const int BarWidth = 3; + private const int BarHeight = 16; + private const int TextLeft = 55; // 条目文字左边,留出圆点位置 + private const int ItemPadding = 5; // 条目上下内边距 + private const int BottomGap = 20; // 区块底部留白 + private const int HeaderHeight = 28; + + private readonly bool isNewest; + private readonly Font versionFont = new Font("微软雅黑", 12F, FontStyle.Bold); + private readonly Font dateFont = new Font("微软雅黑", 9F); + private readonly Font badgeFont = new Font("微软雅黑", 8.5F); + private readonly Font itemFont = new Font("微软雅黑", 10.5F); + private readonly Size versionSize; + private readonly Size dateSize; + private readonly List lblItems = new List(); + private readonly System.Windows.Forms.Label lblVersion = new System.Windows.Forms.Label(); + private readonly System.Windows.Forms.Label lblDate = new System.Windows.Forms.Label(); + private Rectangle badgeRect = Rectangle.Empty; + private Rectangle barRect = Rectangle.Empty; + private readonly List bulletPoints = new List(); + private int laidOutWidth = -1; + + public ChangelogBlock(ChangelogItem entry, bool isNewest, int width) + { + this.isNewest = isNewest; + BackColor = Color.White; + DoubleBuffered = true; + + versionSize = TextRenderer.MeasureText("v" + entry.Version, versionFont); + dateSize = TextRenderer.MeasureText(entry.PublishedAt, dateFont); + + lblVersion.Font = versionFont; + lblVersion.ForeColor = Accent; + lblVersion.BackColor = Color.White; + lblVersion.Text = "v" + entry.Version; + Controls.Add(lblVersion); + + lblDate.Font = dateFont; + lblDate.ForeColor = SubColor; + lblDate.BackColor = Color.White; + lblDate.Text = entry.PublishedAt; + Controls.Add(lblDate); + + foreach (string item in entry.Items) + { + var label = new System.Windows.Forms.Label + { + Font = itemFont, + ForeColor = TextColor, + BackColor = Color.White, + Padding = new Padding(0, ItemPadding, 0, ItemPadding), + Text = item + }; + lblItems.Add(label); + Controls.Add(label); + } + + Width = width; + } + + protected override void OnResize(EventArgs eventargs) + { + base.OnResize(eventargs); + LayoutContent(Width); + } + + private void LayoutContent(int width) + { + if (width <= 0 || width == laidOutWidth) + return; + laidOutWidth = width; + + SuspendLayout(); + + barRect = new Rectangle(LeftPad, (HeaderHeight - BarHeight) / 2, BarWidth, BarHeight); + lblVersion.SetBounds(LeftPad + BarWidth + 8, (HeaderHeight - versionSize.Height) / 2, versionSize.Width, versionSize.Height); + + badgeRect = Rectangle.Empty; + int headerRight = lblVersion.Right; + if (isNewest) + { + Size badgeSize = TextRenderer.MeasureText("最新", badgeFont, Size.Empty, TextFormatFlags.NoPadding); + badgeRect = new Rectangle(headerRight + 8, (HeaderHeight - 18) / 2, badgeSize.Width + 16, 18); + headerRight = badgeRect.Right; + } + + lblDate.SetBounds(Math.Max(headerRight + 8, width - RightPad - dateSize.Width), + (HeaderHeight - dateSize.Height) / 2, dateSize.Width, dateSize.Height); + + int lineHeight = TextRenderer.MeasureText("中", itemFont, Size.Empty, TextFormatFlags.NoPadding).Height; + int textWidth = Math.Max(60, width - TextLeft - RightPad); + bulletPoints.Clear(); + int y = HeaderHeight; + foreach (var label in lblItems) + { + int measured = TextRenderer.MeasureText(label.Text, itemFont, new Size(textWidth, 0), TextFormatFlags.WordBreak).Height; + label.SetBounds(TextLeft, y, textWidth, measured + ItemPadding * 2); + bulletPoints.Add(new Point(TextLeft - 14, y + ItemPadding + lineHeight / 2)); + y += label.Height; + } + + Height = y + BottomGap; + ResumeLayout(false); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + Graphics g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + + using (var path = RoundedRect(barRect, BarWidth / 2f)) + using (var brush = new SolidBrush(Accent)) + g.FillPath(brush, path); + + if (isNewest && badgeRect.Width > 0) + { + using (var path = RoundedRect(badgeRect, badgeRect.Height / 2f)) + using (var brush = new SolidBrush(Accent)) + g.FillPath(brush, path); + TextRenderer.DrawText(g, "最新", badgeFont, badgeRect, Color.White, + TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding); + } + + using (var dot = new SolidBrush(Accent)) + foreach (Point p in bulletPoints) + g.FillEllipse(dot, p.X - 3, p.Y - 3, 6, 6); + } + + private static GraphicsPath RoundedRect(Rectangle rect, float radius) + { + var path = new GraphicsPath(); + float d = radius * 2; + path.AddArc(rect.X, rect.Y, d, d, 180, 90); + path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90); + path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90); + path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90); + path.CloseFigure(); + return path; + } + } + + public enum FormLevel + { + SMALL, + MEDIUM, + LARGE = 500 + } + + /// + /// 更新日志窗口的配色,与设计稿保持一致 + /// + internal static class ChangelogTheme + { + public static readonly Color Accent = Color.FromArgb(152, 99, 143); + public static readonly Color AccentBg = Color.FromArgb(245, 237, 244); + public static readonly Color SubColor = Color.FromArgb(107, 114, 128); + public static readonly Color LineColor = Color.FromArgb(229, 231, 238); + public static readonly Color TextColor = Color.FromArgb(31, 36, 48); + } } diff --git a/Update/Update/MainForm.designer.cs b/Update/Update/MainForm.designer.cs index 5656c39..7430f82 100644 --- a/Update/Update/MainForm.designer.cs +++ b/Update/Update/MainForm.designer.cs @@ -29,135 +29,217 @@ namespace Update /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); - this.lblMessage = new System.Windows.Forms.Label(); - this.btnOk = new System.Windows.Forms.Button(); - this.btnCancel = new System.Windows.Forms.Button(); - this.panel1 = new System.Windows.Forms.Panel(); - this.btnClose = new System.Windows.Forms.Button(); - this.panel2 = new System.Windows.Forms.Panel(); - this.progressBar1 = new System.Windows.Forms.ProgressBar(); - this.panel1.SuspendLayout(); - this.panel2.SuspendLayout(); - this.SuspendLayout(); - // - // lblMessage - // - this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.lblMessage = new System.Windows.Forms.Label(); + this.btnOk = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.panel1 = new System.Windows.Forms.Panel(); + this.lb_title = new System.Windows.Forms.Label(); + this.btnClose = new System.Windows.Forms.Button(); + this.panel2 = new System.Windows.Forms.Panel(); + this.heroPanel = new System.Windows.Forms.Panel(); + this.lblHeroTitle = new System.Windows.Forms.Label(); + this.lblHeroMeta = new System.Windows.Forms.Label(); + this.panelChangelog = new System.Windows.Forms.Panel(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.panel3 = new System.Windows.Forms.Panel(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.heroPanel.SuspendLayout(); + this.SuspendLayout(); + // + // lblMessage + // + this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.lblMessage.Location = new System.Drawing.Point(14, 33); - this.lblMessage.Name = "lblMessage"; - this.lblMessage.Size = new System.Drawing.Size(327, 98); - this.lblMessage.TabIndex = 0; - this.lblMessage.Text = "发现新版本,即将为您升级!"; - this.lblMessage.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; - // - // btnOk - // - this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnOk.BackColor = System.Drawing.Color.Blue; - this.btnOk.Cursor = System.Windows.Forms.Cursors.Hand; - this.btnOk.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255))))); - this.btnOk.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnOk.Font = new System.Drawing.Font("微软雅黑", 11F); - this.btnOk.ForeColor = System.Drawing.Color.White; - this.btnOk.Location = new System.Drawing.Point(232, 177); - this.btnOk.Name = "btnOk"; - this.btnOk.Size = new System.Drawing.Size(109, 30); - this.btnOk.TabIndex = 9; - this.btnOk.TabStop = false; - this.btnOk.Text = "确 定"; - this.btnOk.UseVisualStyleBackColor = false; - this.btnOk.Click += new System.EventHandler(this.btnOk_Click); - // - // btnCancel - // - this.btnCancel.Cursor = System.Windows.Forms.Cursors.Hand; - this.btnCancel.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255))))); - this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 11F); - this.btnCancel.ForeColor = System.Drawing.Color.Blue; - this.btnCancel.Location = new System.Drawing.Point(14, 177); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(109, 30); - this.btnCancel.TabIndex = 10; - this.btnCancel.TabStop = false; - this.btnCancel.Text = "取 消"; - this.btnCancel.UseVisualStyleBackColor = false; - this.btnCancel.Visible = false; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // - // panel1 - // - this.panel1.BackColor = System.Drawing.Color.Blue; - this.panel1.Controls.Add(this.btnClose); - this.panel1.Dock = System.Windows.Forms.DockStyle.Top; - this.panel1.Location = new System.Drawing.Point(2, 2); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(355, 24); - this.panel1.TabIndex = 11; - this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown); - this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove); - this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp); - // - // btnClose - // - this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.btnClose.Cursor = System.Windows.Forms.Cursors.Hand; - this.btnClose.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255))))); - this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnClose.Font = new System.Drawing.Font("微软雅黑", 11F); - this.btnClose.ForeColor = System.Drawing.Color.White; - this.btnClose.Location = new System.Drawing.Point(339, -5); - this.btnClose.Name = "btnClose"; - this.btnClose.Size = new System.Drawing.Size(17, 28); - this.btnClose.TabIndex = 11; - this.btnClose.TabStop = false; - this.btnClose.Text = "x"; - this.btnClose.UseVisualStyleBackColor = false; - this.btnClose.Click += new System.EventHandler(this.btnClose_Click); - // - // panel2 - // - this.panel2.BackColor = System.Drawing.Color.White; - this.panel2.Controls.Add(this.progressBar1); - this.panel2.Controls.Add(this.lblMessage); - this.panel2.Controls.Add(this.btnOk); - this.panel2.Controls.Add(this.btnCancel); - this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; - this.panel2.Location = new System.Drawing.Point(2, 2); - this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(355, 221); - this.panel2.TabIndex = 12; - // - // progressBar1 - // - this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.lblMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(107)))), ((int)(((byte)(114)))), ((int)(((byte)(128))))); + this.lblMessage.Location = new System.Drawing.Point(20, 416); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(607, 45); + this.lblMessage.TabIndex = 0; + this.lblMessage.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // + // btnOk + // + this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnOk.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.btnOk.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnOk.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.btnOk.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btnOk.Font = new System.Drawing.Font("微软雅黑", 11F); + this.btnOk.ForeColor = System.Drawing.Color.White; + this.btnOk.Location = new System.Drawing.Point(522, 521); + this.btnOk.Name = "btnOk"; + this.btnOk.Size = new System.Drawing.Size(109, 30); + this.btnOk.TabIndex = 9; + this.btnOk.TabStop = false; + this.btnOk.Text = "确 定"; + this.btnOk.UseVisualStyleBackColor = false; + this.btnOk.Click += new System.EventHandler(this.btnOk_Click); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnCancel.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnCancel.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 11F); + this.btnCancel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.btnCancel.Location = new System.Drawing.Point(24, 521); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(109, 30); + this.btnCancel.TabIndex = 10; + this.btnCancel.TabStop = false; + this.btnCancel.Text = "取 消"; + this.btnCancel.UseVisualStyleBackColor = false; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.panel1.Controls.Add(this.lb_title); + this.panel1.Controls.Add(this.btnClose); + this.panel1.Dock = System.Windows.Forms.DockStyle.Top; + this.panel1.Location = new System.Drawing.Point(2, 2); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(663, 24); + this.panel1.TabIndex = 11; + this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseDown); + this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove); + this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseUp); + // + // lb_title + // + this.lb_title.AutoSize = true; + this.lb_title.ForeColor = System.Drawing.Color.White; + this.lb_title.Location = new System.Drawing.Point(3, 1); + this.lb_title.Name = "lb_title"; + this.lb_title.Size = new System.Drawing.Size(50, 20); + this.lb_title.TabIndex = 12; + this.lb_title.Text = "label1"; + // + // btnClose + // + this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnClose.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnClose.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btnClose.Font = new System.Drawing.Font("微软雅黑", 13F); + this.btnClose.ForeColor = System.Drawing.Color.White; + this.btnClose.Location = new System.Drawing.Point(629, -6); + this.btnClose.Margin = new System.Windows.Forms.Padding(0); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(35, 35); + this.btnClose.TabIndex = 11; + this.btnClose.TabStop = false; + this.btnClose.Text = "✕"; + this.btnClose.UseVisualStyleBackColor = false; + this.btnClose.Click += new System.EventHandler(this.btnClose_Click); + // + // panel2 + // + this.panel2.BackColor = System.Drawing.Color.White; + this.panel2.Controls.Add(this.panel3); + this.panel2.Controls.Add(this.heroPanel); + this.panel2.Controls.Add(this.panelChangelog); + this.panel2.Controls.Add(this.progressBar1); + this.panel2.Controls.Add(this.lblMessage); + this.panel2.Controls.Add(this.btnOk); + this.panel2.Controls.Add(this.btnCancel); + this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel2.Location = new System.Drawing.Point(2, 2); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(663, 583); + this.panel2.TabIndex = 12; + this.panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.panel2_Paint); + // + // heroPanel + // + this.heroPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.progressBar1.Location = new System.Drawing.Point(14, 139); - this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(327, 23); - this.progressBar1.TabIndex = 11; - this.progressBar1.Visible = false; - // - // MainForm - // - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; - this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(255))))); - this.ClientSize = new System.Drawing.Size(359, 225); - this.Controls.Add(this.panel1); - this.Controls.Add(this.panel2); - this.Font = new System.Drawing.Font("微软雅黑", 10F); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Name = "MainForm"; - this.Padding = new System.Windows.Forms.Padding(2); - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "MessageForm"; - this.Paint += new System.Windows.Forms.PaintEventHandler(this.MessageForm_Paint); - this.panel1.ResumeLayout(false); - this.panel2.ResumeLayout(false); - this.ResumeLayout(false); + this.heroPanel.Controls.Add(this.lblHeroTitle); + this.heroPanel.Controls.Add(this.lblHeroMeta); + this.heroPanel.Location = new System.Drawing.Point(0, 24); + this.heroPanel.Name = "heroPanel"; + this.heroPanel.Size = new System.Drawing.Size(663, 92); + this.heroPanel.TabIndex = 13; + this.heroPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.heroPanel_Paint); + // + // lblHeroTitle + // + this.lblHeroTitle.AutoSize = true; + this.lblHeroTitle.BackColor = System.Drawing.Color.Transparent; + this.lblHeroTitle.Font = new System.Drawing.Font("微软雅黑", 16F, System.Drawing.FontStyle.Bold); + this.lblHeroTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.lblHeroTitle.Location = new System.Drawing.Point(28, 18); + this.lblHeroTitle.Name = "lblHeroTitle"; + this.lblHeroTitle.Size = new System.Drawing.Size(183, 30); + this.lblHeroTitle.TabIndex = 0; + this.lblHeroTitle.Text = "v1.0.0 → v1.3.0"; + // + // lblHeroMeta + // + this.lblHeroMeta.AutoSize = true; + this.lblHeroMeta.BackColor = System.Drawing.Color.Transparent; + this.lblHeroMeta.Font = new System.Drawing.Font("微软雅黑", 9F); + this.lblHeroMeta.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(107)))), ((int)(((byte)(114)))), ((int)(((byte)(128))))); + this.lblHeroMeta.Location = new System.Drawing.Point(30, 58); + this.lblHeroMeta.Name = "lblHeroMeta"; + this.lblHeroMeta.Size = new System.Drawing.Size(155, 17); + this.lblHeroMeta.TabIndex = 1; + this.lblHeroMeta.Text = "共包含 3 个版本的更新内容"; + // + // panelChangelog + // + this.panelChangelog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelChangelog.AutoScroll = true; + this.panelChangelog.BackColor = System.Drawing.Color.White; + this.panelChangelog.Location = new System.Drawing.Point(0, 116); + this.panelChangelog.Name = "panelChangelog"; + this.panelChangelog.Size = new System.Drawing.Size(663, 291); + this.panelChangelog.TabIndex = 14; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(24, 468); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(607, 16); + this.progressBar1.TabIndex = 11; + this.progressBar1.Visible = false; + // + // panel3 + // + this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(229)))), ((int)(((byte)(231)))), ((int)(((byte)(238))))); + this.panel3.Location = new System.Drawing.Point(0, 496); + this.panel3.Margin = new System.Windows.Forms.Padding(1); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(664, 1); + this.panel3.TabIndex = 15; + // + // MainForm + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(152)))), ((int)(((byte)(99)))), ((int)(((byte)(143))))); + this.ClientSize = new System.Drawing.Size(667, 587); + this.Controls.Add(this.panel1); + this.Controls.Add(this.panel2); + this.Font = new System.Drawing.Font("微软雅黑", 10F); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "MainForm"; + this.Padding = new System.Windows.Forms.Padding(2); + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "MessageForm"; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.panel2.ResumeLayout(false); + this.heroPanel.ResumeLayout(false); + this.heroPanel.PerformLayout(); + this.ResumeLayout(false); } @@ -170,5 +252,11 @@ namespace Update private System.Windows.Forms.Panel panel2; private System.Windows.Forms.Button btnClose; private System.Windows.Forms.ProgressBar progressBar1; - } + private System.Windows.Forms.Panel heroPanel; + private System.Windows.Forms.Label lblHeroTitle; + private System.Windows.Forms.Label lblHeroMeta; + private System.Windows.Forms.Panel panelChangelog; + private System.Windows.Forms.Label lb_title; + private System.Windows.Forms.Panel panel3; + } } \ No newline at end of file diff --git a/Update/Update/MiniJson.cs b/Update/Update/MiniJson.cs new file mode 100644 index 0000000..52e674a --- /dev/null +++ b/Update/Update/MiniJson.cs @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2013 Calvin Rien + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + * + * Simplified it so that it doesn't throw exceptions + * and can be used in Unity iPhone with maximum code stripping. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; + +namespace MiniJson +{ + // Example usage: + // + // using UnityEngine; + // using System.Collections; + // using System.Collections.Generic; + // using MiniJSON; + // + // public class MiniJSONTest : MonoBehaviour { + // void Start () { + // var jsonString = "{ \"array\": [1.44,2,3], " + + // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + + // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + + // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + + // "\"int\": 65536, " + + // "\"float\": 3.1415926, " + + // "\"bool\": true, " + + // "\"null\": null }"; + // + // var dict = Json.Deserialize(jsonString) as Dictionary; + // + // Debug.Log("deserialized: " + dict.GetType()); + // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); + // Debug.Log("dict['string']: " + (string) dict["string"]); + // Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles + // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs + // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); + // + // var str = Json.Serialize(dict); + // + // Debug.Log("serialized: " + str); + // } + // } + + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. + /// All numbers are parsed to doubles. + /// + public static class Json + { + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false + public static object Deserialize(string json) + { + // save the string for debug information + if (json == null) + { + return null; + } + + return Parser.Parse(json); + } + + public static T Deserialize(string json) + where T:class,new() + { + T model =new T(); + Dictionary dic=Deserialize(json) as Dictionary; + if (dic != null) + { + var properties = model.GetType().GetProperties(); + foreach (var pro in properties) + { + if (dic.ContainsKey(pro.Name)) + { + object val; + if (dic[pro.Name]==null && pro.PropertyType.IsValueType) + { + val = null; + } + else + { + val = Convert.ChangeType(dic[pro.Name], pro.PropertyType); + } + pro.SetValue(model, val,null); + } + } + } + return model; + } + /// + /// Converts a Dictionary / List object or a simple type or a class type (string, int, etc.) into a JSON string + /// + /// A Dictionary<string, object> / List<object> + /// A JSON encoded string, or null if object 'json' is not serializable + //public static string Serialize(object obj) + //{ + // return Serializer.Serialize(obj); + //} + public static string Serialize(object obj) + { + if (obj.GetType() == typeof(Dictionary) || obj.GetType() == typeof(List)) + { + return Serializer.Serialize(obj); + } + else if (obj.GetType().IsClass) + { + var properties = obj.GetType().GetProperties(); + Dictionary dic = new Dictionary(); + + foreach (var pro in properties) + { + dic.Add(pro.Name, pro.GetValue(obj, null)); + } + return Serializer.Serialize(dic); + } + else + return null; + } + sealed class Parser : IDisposable + { + const string WORD_BREAK = "{}[],:\""; + + public static bool IsWordBreak(char c) + { + return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; + } + + const string HEX_DIGIT = "0123456789ABCDEFabcdef"; + + public static bool IsHexDigit(char c) + { + return HEX_DIGIT.IndexOf(c) != -1; + } + + enum TOKEN + { + NONE, + CURLY_OPEN, + CURLY_CLOSE, + SQUARED_OPEN, + SQUARED_CLOSE, + COLON, + COMMA, + STRING, + NUMBER, + TRUE, + FALSE, + NULL + }; + + StringReader json; + + Parser(string jsonString) + { + json = new StringReader(jsonString); + } + + public static object Parse(string jsonString) + { + using (var instance = new Parser(jsonString)) + { + return instance.ParseValue(); + } + } + + public void Dispose() + { + json.Dispose(); + json = null; + } + + Dictionary ParseObject() + { + Dictionary table = new Dictionary(); + + // ditch opening brace + json.Read(); + + // { + while (true) + { + switch (NextToken) + { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.CURLY_CLOSE: + return table; + case TOKEN.STRING: + // name + string name = ParseString(); + if (name == null) + { + return null; + } + + // : + if (NextToken != TOKEN.COLON) + { + return null; + } + // ditch the colon + json.Read(); + + // value + TOKEN valueToken = NextToken; + object value = ParseByToken(valueToken); + if (value == null && valueToken != TOKEN.NULL) + return null; + table[name] = value; + break; + default: + return null; + } + } + } + + List ParseArray() + { + List array = new List(); + + // ditch opening bracket + json.Read(); + + // [ + var parsing = true; + while (parsing) + { + TOKEN nextToken = NextToken; + + switch (nextToken) + { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.SQUARED_CLOSE: + parsing = false; + break; + default: + object value = ParseByToken(nextToken); + if (value == null && nextToken != TOKEN.NULL) + return null; + array.Add(value); + break; + } + } + + return array; + } + + object ParseValue() + { + TOKEN nextToken = NextToken; + return ParseByToken(nextToken); + } + + object ParseByToken(TOKEN token) + { + switch (token) + { + case TOKEN.STRING: + return ParseString(); + case TOKEN.NUMBER: + return ParseNumber(); + case TOKEN.CURLY_OPEN: + return ParseObject(); + case TOKEN.SQUARED_OPEN: + return ParseArray(); + case TOKEN.TRUE: + return true; + case TOKEN.FALSE: + return false; + case TOKEN.NULL: + return null; + default: + return null; + } + } + + string ParseString() + { + StringBuilder s = new StringBuilder(); + char c; + + // ditch opening quote + json.Read(); + + bool parsing = true; + while (parsing) + { + + if (json.Peek() == -1) + { + parsing = false; + break; + } + + c = NextChar; + switch (c) + { + case '"': + parsing = false; + break; + case '\\': + if (json.Peek() == -1) + { + parsing = false; + break; + } + + c = NextChar; + switch (c) + { + case '"': + case '\\': + case '/': + s.Append(c); + break; + case 'b': + s.Append('\b'); + break; + case 'f': + s.Append('\f'); + break; + case 'n': + s.Append('\n'); + break; + case 'r': + s.Append('\r'); + break; + case 't': + s.Append('\t'); + break; + case 'u': + var hex = new char[4]; + + for (int i = 0; i < 4; i++) + { + hex[i] = NextChar; + if (!IsHexDigit(hex[i])) + return null; + } + + s.Append((char)Convert.ToInt32(new string(hex), 16)); + break; + } + break; + default: + s.Append(c); + break; + } + } + + return s.ToString(); + } + + object ParseNumber() + { + string number = NextWord; + + if (number.IndexOf('.') == -1 && number.IndexOf('E') == -1 && number.IndexOf('e') == -1) + { + long parsedInt; + Int64.TryParse(number, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out parsedInt); + return parsedInt; + } + + double parsedDouble; + Double.TryParse(number, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out parsedDouble); + return parsedDouble; + } + + void EatWhitespace() + { + while (Char.IsWhiteSpace(PeekChar)) + { + json.Read(); + + if (json.Peek() == -1) + { + break; + } + } + } + + char PeekChar + { + get + { + return Convert.ToChar(json.Peek()); + } + } + + char NextChar + { + get + { + return Convert.ToChar(json.Read()); + } + } + + string NextWord + { + get + { + StringBuilder word = new StringBuilder(); + + while (!IsWordBreak(PeekChar)) + { + word.Append(NextChar); + + if (json.Peek() == -1) + { + break; + } + } + + return word.ToString(); + } + } + + TOKEN NextToken + { + get + { + EatWhitespace(); + + if (json.Peek() == -1) + { + return TOKEN.NONE; + } + + switch (PeekChar) + { + case '{': + return TOKEN.CURLY_OPEN; + case '}': + json.Read(); + return TOKEN.CURLY_CLOSE; + case '[': + return TOKEN.SQUARED_OPEN; + case ']': + json.Read(); + return TOKEN.SQUARED_CLOSE; + case ',': + json.Read(); + return TOKEN.COMMA; + case '"': + return TOKEN.STRING; + case ':': + return TOKEN.COLON; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN.NUMBER; + } + + switch (NextWord) + { + case "false": + return TOKEN.FALSE; + case "true": + return TOKEN.TRUE; + case "null": + return TOKEN.NULL; + } + + return TOKEN.NONE; + } + } + } + + + + sealed class Serializer + { + StringBuilder builder; + + Serializer() + { + builder = new StringBuilder(); + } + + public static string Serialize(object obj) + { + var instance = new Serializer(); + + instance.SerializeValue(obj); + + return instance.builder.ToString(); + } + + void SerializeValue(object value) + { + IList asList; + IDictionary asDict; + string asStr; + + if (value == null) + { + builder.Append("null"); + } + else if ((asStr = value as string) != null) + { + SerializeString(asStr); + } + else if (value is bool) + { + builder.Append((bool)value ? "true" : "false"); + } + else if ((asList = value as IList) != null) + { + SerializeArray(asList); + } + else if ((asDict = value as IDictionary) != null) + { + SerializeObject(asDict); + } + else if (value is char) + { + SerializeString(new string((char)value, 1)); + } + else + { + SerializeOther(value); + } + } + + void SerializeObject(IDictionary obj) + { + bool first = true; + + builder.Append('{'); + + foreach (object e in obj.Keys) + { + if (!first) + { + builder.Append(','); + } + + SerializeString(e.ToString()); + builder.Append(':'); + + SerializeValue(obj[e]); + + first = false; + } + + builder.Append('}'); + } + + void SerializeArray(IList anArray) + { + builder.Append('['); + + bool first = true; + + for (int i = 0; i < anArray.Count; i++) + { + object obj = anArray[i]; + if (!first) + { + builder.Append(','); + } + + SerializeValue(obj); + + first = false; + } + + builder.Append(']'); + } + + void SerializeString(string str) + { + builder.Append('\"'); + + char[] charArray = str.ToCharArray(); + for (int i = 0; i < charArray.Length; i++) + { + char c = charArray[i]; + switch (c) + { + case '"': + builder.Append("\\\""); + break; + case '\\': + builder.Append("\\\\"); + break; + case '\b': + builder.Append("\\b"); + break; + case '\f': + builder.Append("\\f"); + break; + case '\n': + builder.Append("\\n"); + break; + case '\r': + builder.Append("\\r"); + break; + case '\t': + builder.Append("\\t"); + break; + default: + int codepoint = Convert.ToInt32(c); + if ((codepoint >= 32) && (codepoint <= 126)) + { + builder.Append(c); + } + else + { + builder.Append("\\u"); + builder.Append(codepoint.ToString("x4")); + } + break; + } + } + + builder.Append('\"'); + } + + void SerializeOther(object value) + { + // NOTE: decimals lose precision during serialization. + // They always have, I'm just letting you know. + // Previously floats and doubles lost precision too. + if (value is float) + { + builder.Append(((float)value).ToString("R", System.Globalization.CultureInfo.InvariantCulture)); + } + else if (value is int + || value is uint + || value is long + || value is sbyte + || value is byte + || value is short + || value is ushort + || value is ulong) + { + builder.Append(value); + } + else if (value is double + || value is decimal) + { + builder.Append(Convert.ToDouble(value).ToString("R", System.Globalization.CultureInfo.InvariantCulture)); + } + else + { + SerializeString(value.ToString()); + } + } + } + } +} diff --git a/Update/Update/Program.cs b/Update/Update/Program.cs index 9804b08..f7a3686 100644 --- a/Update/Update/Program.cs +++ b/Update/Update/Program.cs @@ -25,7 +25,12 @@ namespace Update [STAThread] static void Main(string[] args) { - if (args.Length > 0) + //Program.oldVersion = 1332; + //Application.EnableVisualStyles(); + //Application.SetCompatibleTextRenderingDefault(false); + //Application.Run(new MainForm()); + //return; + if (args.Length > 0) { try { diff --git a/Update/Update/Properties/AssemblyInfo.cs b/Update/Update/Properties/AssemblyInfo.cs index 2866b10..d63c04a 100644 --- a/Update/Update/Properties/AssemblyInfo.cs +++ b/Update/Update/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/Update/Update/Update.csproj b/Update/Update/Update.csproj index eb549f9..7b440b6 100644 --- a/Update/Update/Update.csproj +++ b/Update/Update/Update.csproj @@ -62,6 +62,7 @@ MainForm.cs +