diff --git a/installer/Installer/MainWindow.xaml b/installer/Installer/MainWindow.xaml
index 48625cc..c298ff1 100644
--- a/installer/Installer/MainWindow.xaml
+++ b/installer/Installer/MainWindow.xaml
@@ -38,17 +38,19 @@
-
+
+
+
-
+
-
-
+
+
@@ -72,13 +74,14 @@
-
+ 记住我
-
+
+
diff --git a/installer/Installer/Model.cs b/installer/Installer/Model.cs
index 36cccdc..35ab9e0 100644
--- a/installer/Installer/Model.cs
+++ b/installer/Installer/Model.cs
@@ -21,10 +21,13 @@ using System.Net.Http;
using System.Windows;
using System.Windows.Shapes;
//using System.Windows.Forms;
+using System.Threading.Tasks;
+using System.Threading;
using MessageBox = System.Windows.MessageBox;
using Downloader;
using COSXML.Transfer;
+using WebConnect;
using System.IO.Compression;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.GZip;
@@ -55,6 +58,7 @@ namespace starter.viewmodel.settings
PlayerNum = "nSelect";
UploadReady = false;
LoginFailed = false;
+ launchLanguage = LaunchLanguage.cpp;
}
///
@@ -121,7 +125,7 @@ namespace starter.viewmodel.settings
{
if (updateInfo.changedFileCount != 0 || updateInfo.newFileCount != 0)
{
- Updates = "发现新版本";
+ Updates = $"{updateInfo.newFileCount}个新文件,{updateInfo.changedFileCount}个文件变化";
}
return Status.menu;
}
@@ -131,6 +135,38 @@ namespace starter.viewmodel.settings
{
return await web.LoginToEEsast(client, Username, Password);
}
+
+ public bool RememberUser()
+ {
+ int result = 0;
+ result |= Web.WriteUserEmail(Username);
+ result |= Web.WriteUserPassword(Password);
+ return result == 0;
+ }
+ public bool RecallUser()
+ {
+ Username = Web.ReadUserEmail();
+ if (Username == null || Username.Equals(""))
+ {
+ Username = "";
+ return false;
+ }
+ Password = Web.ReadUserPassword();
+ if (Password == null || Username.Equals(""))
+ {
+ Password = "";
+ return false;
+ }
+ return true;
+ }
+ public bool ForgetUser()
+ {
+ int result = 0;
+ result |= Web.WriteUserEmail("");
+ result |= Web.WriteUserPassword("");
+ return result == 0;
+ }
+
public bool Update()
{
return Tencent_cos_download.Update();
@@ -257,6 +293,15 @@ namespace starter.viewmodel.settings
{
get; set;
}
+ public bool RememberMe
+ {
+ get; set;
+ }
+ public enum LaunchLanguage { cpp, python };
+ public LaunchLanguage launchLanguage
+ {
+ get; set;
+ }
}
}
namespace Downloader
@@ -422,7 +467,7 @@ namespace Downloader
Dictionary test = request.GetRequestHeaders();
request.SetCosProgressCallback(delegate (long completed, long total)
{
- Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
+ //Console.WriteLine(String.Format("progress = {0:##.##}%", completed * 100.0 / total));
});
// 执行请求
GetObjectResult result = cosXml.GetObject(request);
@@ -466,6 +511,8 @@ namespace Downloader
{
if (fst != null)
fst.Close();
+ if (File.Exists(strFileFullPath))
+ return "conflict";
return "";
}
finally
@@ -524,6 +571,8 @@ namespace Downloader
MD5 = GetFileMd5Hash(System.IO.Path.Combine(Data.FilePath, pair.Key));
if (MD5.Length == 0) // 文档不存在
newFileName.Add(pair.Key);
+ else if (MD5.Equals("conflict"))
+ MessageBox.Show($"文件{pair.Key}已打开,无法检查是否为最新,若需要,请关闭文件稍后手动检查更新", "文件正在使用", MessageBoxButton.OK, MessageBoxImage.Warning);
else if (MD5 != pair.Value) // MD5不匹配
updateFileName.Add(pair.Key);
}
@@ -584,7 +633,6 @@ namespace Downloader
private static void Download()
{
Tencent_cos_download Downloader = new Tencent_cos_download();
-
int newFile = 0, updateFile = 0;
int totalnew = newFileName.Count, totalupdate = updateFileName.Count;
filenum = totalnew + totalupdate;
@@ -595,17 +643,17 @@ namespace Downloader
{
foreach (string filename in newFileName)
{
- Console.WriteLine(newFile + 1 + "/" + totalnew + ":开始下载" + filename);
+ //Console.WriteLine(newFile + 1 + "/" + totalnew + ":开始下载" + filename);
Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename);
- Console.WriteLine(filename + "下载完毕!" + Environment.NewLine);
+ //Console.WriteLine(filename + "下载完毕!" + Environment.NewLine);
newFile++;
}
foreach (string filename in updateFileName)
{
- Console.WriteLine(updateFile + 1 + "/" + totalupdate + ":开始下载" + filename);
+ //Console.WriteLine(updateFile + 1 + "/" + totalupdate + ":开始下载" + filename);
File.Delete(System.IO.Path.Combine(@Data.FilePath, filename));
Downloader.download(System.IO.Path.Combine(@Data.FilePath, filename), filename);
- Console.WriteLine(filename + "下载完毕!" + Environment.NewLine);
+ //Console.WriteLine(filename + "下载完毕!" + Environment.NewLine);
updateFile++;
}
}
@@ -771,7 +819,7 @@ namespace Downloader
foreach (FileInfo NextFile in theFolder.GetFiles())
{
string filepath = topDir + @"/" + NextFile.Name; // 文件路径
- Console.WriteLine(filepath);
+ //Console.WriteLine(filepath);
foreach (KeyValuePair pair in jsonDict)
{
if (System.IO.Path.Equals(filepath, System.IO.Path.Combine(Data.FilePath, pair.Key).Replace('\\', '/')))
@@ -921,7 +969,6 @@ namespace Downloader
Console.WriteLine("文件已经打开,请关闭后再删除");
return -1;
}
- Console.WriteLine($"删除成功!player文件夹中的文件已经放在{ProgramName}的根目录下");
return 0;
}
@@ -1101,7 +1148,7 @@ namespace WebConnect
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.OK:
- Console.WriteLine("Success login");
+ //Console.WriteLine("Success login");
token = (System.Text.Json.JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), typeof(LoginResponse), new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
@@ -1117,7 +1164,7 @@ namespace WebConnect
default:
int code = ((int)response.StatusCode);
- Console.WriteLine(code);
+ //Console.WriteLine(code);
if (code == 401)
{
//Console.WriteLine("邮箱或密码错误!");
@@ -1201,13 +1248,13 @@ namespace WebConnect
uploadTask.progressCallback = delegate (long completed, long total)
{
- Console.WriteLine(string.Format("progress = {0:##.##}%", completed * 100.0 / total));
+ //Console.WriteLine(string.Format("progress = {0:##.##}%", completed * 100.0 / total));
};
try
{
COSXMLUploadTask.UploadTaskResult result = await transferManager.UploadAsync(uploadTask);
- Console.WriteLine(result.GetResultInfo());
+ //Console.WriteLine(result.GetResultInfo());
string eTag = result.eTag;
//到这里应该是成功了,但是因为我没有试过,也不知道具体情况,可能还要根据result的内容判断
}
diff --git a/installer/Installer/ViewModel.cs b/installer/Installer/ViewModel.cs
index 3aabff0..115286c 100644
--- a/installer/Installer/ViewModel.cs
+++ b/installer/Installer/ViewModel.cs
@@ -7,11 +7,19 @@ using Downloader;
using MessageBox = System.Windows.MessageBox;
using System.Configuration;
using System.Drawing.Design;
+using Application = System.Windows.Application;
+using System.ComponentModel;
+using Installer;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement;
+using System.IO;
namespace starter.viewmodel.settings
{
public class SettingsViewModel : NotificationObject
{
+ //定义BackgroundWorker
+ BackgroundWorker asyncDownloader;
+ BackgroundWorker asyncUpdater;
///
/// Model object
///
@@ -22,17 +30,40 @@ namespace starter.viewmodel.settings
public SettingsViewModel()
{
+
//Program.Tencent_cos_download.UpdateHash();
- //WebConnect.Web.WriteUserEmail("wangsk21@mails.tsinghua.edu.cn");
+
+ //实例化BackgroundWorker
+ asyncDownloader = new BackgroundWorker();
+ asyncUpdater = new BackgroundWorker();
+ //指示BackgroundWorker是否可以报告进度更新
+ //当该属性值为True是,将可以成功调用ReportProgress方法,否则将引发InvalidOperationException异常。
+ asyncDownloader.WorkerReportsProgress = true;
+ asyncUpdater.WorkerReportsProgress = true;
+ //挂载方法:
+ asyncDownloader.DoWork += AsyncDownloader_DoWork;
+ asyncUpdater.DoWork += AsyncUpdater_DoWork;
+ //完成通知器:
+ asyncDownloader.RunWorkerCompleted += AsyncDownloader_RunWorkerCompleted;
+ asyncUpdater.RunWorkerCompleted += AsyncUpdater_RunWorkerCompleted;
+
+ UpdateInfoVis = Visibility.Collapsed;
+
if (Downloader.Program.Tencent_cos_download.CheckAlreadyDownload())
{
obj.checkUpdate();
Status = SettingsModel.Status.login;
this.RaisePropertyChanged("WindowWidth");
- //TODO:在启动时立刻检查更新,确保选手启动最新版选手包
- //TODO:若有更新,将启动键改为更新键;
- //TODO:相应地,使用login界面启动;
- //TODO:结构:上方为登录框架,下方有“修改选手包”按钮
+ this.RaisePropertyChanged("LaunchVis");
+ if (obj.RecallUser())
+ RememberMe = true;
+ else
+ RememberMe = false;
+ this.RaisePropertyChanged("RememberMe");
+ //在启动时立刻检查更新,确保选手启动最新版选手包
+ //若有更新,将启动键改为更新键;
+ //相应地,使用login界面启动;
+ //结构:上方为登录框架,下方有“修改选手包”按钮
}
else
{
@@ -42,6 +73,85 @@ namespace starter.viewmodel.settings
}
}
+ private void AsyncDownloader_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
+ {
+ if (e.Result == null)
+ {
+ Status = SettingsModel.Status.error;
+ }
+ else if ((bool)e.Result)
+ {
+ Status = SettingsModel.Status.successful;
+ }
+ else
+ {
+ Status = SettingsModel.Status.newUser;
+ }
+ }
+
+ private void AsyncUpdater_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
+ {
+ if (e.Result == null)
+ {
+ Status = SettingsModel.Status.error;
+ }
+ else
+ {
+ this.RaisePropertyChanged("LaunchVis");
+ if ((int)e.Result == 1)
+ {
+ Status = SettingsModel.Status.successful;
+ this.RaisePropertyChanged("UpdateBtnCont");
+ this.RaisePropertyChanged("UpdateInfo");
+ this.RaisePropertyChanged("LaunchBtnCont");
+ }
+ else if ((int)e.Result == 2)
+ {
+ Status = SettingsModel.Status.login;
+ this.RaisePropertyChanged("UpdateBtnCont");
+ this.RaisePropertyChanged("LaunchBtnCont");
+ this.RaisePropertyChanged("UpdateInfo");
+ }
+ }
+ }
+
+ private void AsyncUpdater_DoWork(object? sender, DoWorkEventArgs e)
+ {
+ if (asyncUpdater.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+ else
+ {
+ if (obj.Update())
+ if (e.Argument.ToString().Equals("Manual"))
+ {
+ e.Result = 1;
+ }
+ else
+ e.Result = 2;
+ else
+ e.Result = -1;
+ }
+ }
+
+ private void AsyncDownloader_DoWork(object? sender, DoWorkEventArgs e)
+ {
+ if (asyncDownloader.CancellationPending)
+ {
+ e.Cancel = true;
+ return;
+ }
+ else
+ {
+ if (obj.install())
+ e.Result = true;
+ else
+ e.Result = false;
+ }
+ }
+
//TODO:参赛界面:包括上传参赛代码、申请对战
//TODO:界面中应包含上次对战完成提示及下载回放按钮
@@ -95,6 +205,10 @@ namespace starter.viewmodel.settings
this.RaisePropertyChanged("CompleteVis");
this.RaisePropertyChanged("WindowWidth");
this.RaisePropertyChanged("WebVis");
+ this.RaisePropertyChanged("CoverVis");
+ this.RaisePropertyChanged("LaunchVis");
+ this.RaisePropertyChanged("NewUserVis");
+ this.RaisePropertyChanged("ConfirmBtnCont");
}
}
public string Intro
@@ -128,9 +242,9 @@ namespace starter.viewmodel.settings
{
case SettingsModel.Status.newUser:
- return "将主体程序安装在:";
+ return "将选手包安装在(将创建THUAI6文件夹):";
case SettingsModel.Status.move:
- return "将主体程序移动到:";
+ return "将选手包移动到(THUAI6文件夹将会被整体移动):";
default:
return "";
}
@@ -179,7 +293,10 @@ namespace starter.viewmodel.settings
public string Route
{
- get => obj.Route;
+ get
+ {
+ return obj.Route;
+ }
set
{
obj.Route = value;
@@ -211,6 +328,27 @@ namespace starter.viewmodel.settings
return obj.CodeRoute.Substring(obj.CodeRoute.LastIndexOf('/') == -1 ? obj.CodeRoute.LastIndexOf('\\') + 1 : obj.CodeRoute.LastIndexOf('/') + 1);
}
}
+
+ public bool RememberMe
+ {
+ get
+ {
+ return obj.RememberMe;
+ }
+ set
+ {
+ obj.RememberMe = value;
+ this.RaisePropertyChanged("RememberMe");
+ }
+ }
+
+ public Visibility NewUserVis
+ {
+ get
+ {
+ return Status == SettingsModel.Status.newUser ? Visibility.Visible : Visibility.Collapsed;
+ }
+ }
public Visibility MenuVis
{
get
@@ -279,6 +417,19 @@ namespace starter.viewmodel.settings
get { return obj.UploadReady ? Visibility.Visible : Visibility.Collapsed; }
}
+ public Visibility UpdateInfoVis
+ {
+ get; set;
+ }
+
+ public Visibility LaunchVis
+ {
+ get
+ {
+ return obj.status == SettingsModel.Status.login && (!obj.UpdatePlanned) ? Visibility.Visible : Visibility.Collapsed;
+ }
+ }
+
public string UpdateBtnCont
{
get
@@ -293,14 +444,21 @@ namespace starter.viewmodel.settings
if (obj.UpdatePlanned)
return obj.Updates;
else
- return "";
+ return "已是最新版本";
}
}
public string LaunchBtnCont
{
get
{
- return obj.UpdatePlanned ? "更新" : "启动";
+ string ans;
+ if (obj.UpdatePlanned)
+ ans = "更新";
+ else if (obj.launchLanguage == SettingsModel.LaunchLanguage.cpp)
+ ans = "启动c++包";
+ else
+ ans = "启动python包";
+ return ans;
}
}
public string UploadBtnCont
@@ -310,6 +468,28 @@ namespace starter.viewmodel.settings
return obj.UploadReady ? "上传代码" : "选择代码上传";
}
}
+ public string ShiftLanguageBtnCont
+ {
+ get
+ {
+ return obj.launchLanguage == SettingsModel.LaunchLanguage.cpp ? "改为python" : "改为c++";
+ }
+ }
+ public string ConfirmBtnCont
+ {
+ get
+ {
+ switch (Status)
+ {
+ case SettingsModel.Status.newUser:
+ return "确认并安装";
+ case SettingsModel.Status.move:
+ return "确认并移动";
+ default:
+ return "";
+ }
+ }
+ }
public string RouteSelectWindow(string type)
{
@@ -365,16 +545,22 @@ namespace starter.viewmodel.settings
{
Status = SettingsModel.Status.working;
this.RaisePropertyChanged("ProgressVis");
- if (obj.install())
+ /*if (obj.install())
{
Status = SettingsModel.Status.successful;
+ }*/
+ if (asyncDownloader.IsBusy)
+ return;
+ else
+ {
+ asyncDownloader.RunWorkerAsync();
}
}
else if (Status == SettingsModel.Status.move)
{
- Status = SettingsModel.Status.working;
- this.RaisePropertyChanged("ProgressVis");
+ //Status = SettingsModel.Status.working;
+ //this.RaisePropertyChanged("ProgressVis");
switch (obj.move())
{
case -1:
@@ -400,11 +586,14 @@ namespace starter.viewmodel.settings
{
clickUpdateCommand = new BaseCommand(new Action