diff --git a/.vs/OpenSaveCloudClient/DesignTimeBuild/.dtbcache.v2 b/.vs/OpenSaveCloudClient/DesignTimeBuild/.dtbcache.v2 index a20f03c..d53476e 100644 Binary files a/.vs/OpenSaveCloudClient/DesignTimeBuild/.dtbcache.v2 and b/.vs/OpenSaveCloudClient/DesignTimeBuild/.dtbcache.v2 differ diff --git a/.vs/OpenSaveCloudClient/FileContentIndex/2fdb10f0-c092-457e-811a-f86feed3ee73.vsidx b/.vs/OpenSaveCloudClient/FileContentIndex/2fdb10f0-c092-457e-811a-f86feed3ee73.vsidx deleted file mode 100644 index bc1ef51..0000000 Binary files a/.vs/OpenSaveCloudClient/FileContentIndex/2fdb10f0-c092-457e-811a-f86feed3ee73.vsidx and /dev/null differ diff --git a/.vs/OpenSaveCloudClient/FileContentIndex/a88899ca-f8a7-4ee2-9553-45fb0f140234.vsidx b/.vs/OpenSaveCloudClient/FileContentIndex/a88899ca-f8a7-4ee2-9553-45fb0f140234.vsidx new file mode 100644 index 0000000..ce53b78 Binary files /dev/null and b/.vs/OpenSaveCloudClient/FileContentIndex/a88899ca-f8a7-4ee2-9553-45fb0f140234.vsidx differ diff --git a/OpenSaveCloudClient/AddGameForm.Designer.cs b/OpenSaveCloudClient/AddGameForm.Designer.cs index ae1a7fa..31f28fc 100644 --- a/OpenSaveCloudClient/AddGameForm.Designer.cs +++ b/OpenSaveCloudClient/AddGameForm.Designer.cs @@ -32,6 +32,7 @@ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AddGameForm)); this.label1 = new System.Windows.Forms.Label(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.NameWarningLabel = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.pathButton = new System.Windows.Forms.Button(); @@ -40,8 +41,9 @@ this.groupBox2 = new System.Windows.Forms.GroupBox(); this.NoCoverLabel = new System.Windows.Forms.Label(); this.CoverPicture = new System.Windows.Forms.PictureBox(); - this.button1 = new System.Windows.Forms.Button(); + this.AddButton = new System.Windows.Forms.Button(); this.timer1 = new System.Windows.Forms.Timer(this.components); + this.PathErrorLabel = new System.Windows.Forms.Label(); this.groupBox1.SuspendLayout(); this.groupBox2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.CoverPicture)).BeginInit(); @@ -63,6 +65,7 @@ this.groupBox1.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.groupBox1.Controls.Add(this.NameWarningLabel); this.groupBox1.Controls.Add(this.label3); this.groupBox1.Controls.Add(this.label2); this.groupBox1.Controls.Add(this.pathButton); @@ -75,10 +78,21 @@ this.groupBox1.TabStop = false; this.groupBox1.Text = "Game information"; // + // NameWarningLabel + // + this.NameWarningLabel.AutoSize = true; + this.NameWarningLabel.ForeColor = System.Drawing.Color.Coral; + this.NameWarningLabel.Location = new System.Drawing.Point(15, 113); + this.NameWarningLabel.Name = "NameWarningLabel"; + this.NameWarningLabel.Size = new System.Drawing.Size(421, 25); + this.NameWarningLabel.TabIndex = 5; + this.NameWarningLabel.Text = "There is already a game with this name in the library"; + this.NameWarningLabel.Visible = false; + // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(15, 132); + this.label3.Location = new System.Drawing.Point(15, 161); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(169, 25); this.label3.TabIndex = 4; @@ -96,7 +110,7 @@ // pathButton // this.pathButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.pathButton.Location = new System.Drawing.Point(571, 157); + this.pathButton.Location = new System.Drawing.Point(571, 186); this.pathButton.Name = "pathButton"; this.pathButton.Size = new System.Drawing.Size(47, 34); this.pathButton.TabIndex = 2; @@ -108,7 +122,7 @@ // this.LocationBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.LocationBox.Location = new System.Drawing.Point(15, 160); + this.LocationBox.Location = new System.Drawing.Point(15, 189); this.LocationBox.Name = "LocationBox"; this.LocationBox.ReadOnly = true; this.LocationBox.Size = new System.Drawing.Size(550, 31); @@ -162,29 +176,41 @@ this.CoverPicture.TabStop = false; this.CoverPicture.Visible = false; // - // button1 + // AddButton // - this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button1.Location = new System.Drawing.Point(943, 508); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(112, 34); - this.button1.TabIndex = 3; - this.button1.Text = "Add"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); + this.AddButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.AddButton.Location = new System.Drawing.Point(943, 508); + this.AddButton.Name = "AddButton"; + this.AddButton.Size = new System.Drawing.Size(112, 34); + this.AddButton.TabIndex = 3; + this.AddButton.Text = "Add"; + this.AddButton.UseVisualStyleBackColor = true; + this.AddButton.Click += new System.EventHandler(this.button1_Click); // // timer1 // this.timer1.Interval = 350; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // + // PathErrorLabel + // + this.PathErrorLabel.AutoSize = true; + this.PathErrorLabel.ForeColor = System.Drawing.Color.IndianRed; + this.PathErrorLabel.Location = new System.Drawing.Point(483, 513); + this.PathErrorLabel.Name = "PathErrorLabel"; + this.PathErrorLabel.Size = new System.Drawing.Size(454, 25); + this.PathErrorLabel.TabIndex = 4; + this.PathErrorLabel.Text = "There is already a game following this path in the library"; + this.PathErrorLabel.Visible = false; + // // AddGameForm // this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.SystemColors.Window; this.ClientSize = new System.Drawing.Size(1067, 554); - this.Controls.Add(this.button1); + this.Controls.Add(this.PathErrorLabel); + this.Controls.Add(this.AddButton); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); this.Controls.Add(this.label1); @@ -209,7 +235,7 @@ private Label label1; private GroupBox groupBox1; private GroupBox groupBox2; - private Button button1; + private Button AddButton; private TextBox LocationBox; private TextBox NameBox; private Button pathButton; @@ -218,5 +244,7 @@ private Label NoCoverLabel; private PictureBox CoverPicture; private System.Windows.Forms.Timer timer1; + private Label NameWarningLabel; + private Label PathErrorLabel; } } \ No newline at end of file diff --git a/OpenSaveCloudClient/AddGameForm.cs b/OpenSaveCloudClient/AddGameForm.cs index 068f5e4..5c81478 100644 --- a/OpenSaveCloudClient/AddGameForm.cs +++ b/OpenSaveCloudClient/AddGameForm.cs @@ -1,5 +1,6 @@ using IGDB; using IGDB.Models; +using OpenSaveCloudClient.Core; using OpenSaveCloudClient.Models; using System; using System.Collections.Generic; @@ -18,6 +19,7 @@ namespace OpenSaveCloudClient private readonly IGDBClient? _client; private GameSave result; + private SaveManager saveManager; public GameSave Result { get { return result; } } @@ -25,6 +27,7 @@ namespace OpenSaveCloudClient { InitializeComponent(); _client = iGDBClient; + saveManager = SaveManager.GetInstance(); if (_client == null) { NoCoverLabel.Text = "IGDB is not configured"; @@ -73,6 +76,7 @@ namespace OpenSaveCloudClient private void NameBox_TextChanged(object sender, EventArgs e) { + NameWarningLabel.Visible = saveManager.Saves.Exists(g => g.Name == NameBox.Text); if (_client != null) { timer1.Stop(); @@ -91,6 +95,16 @@ namespace OpenSaveCloudClient { NameBox.Text = path.Split(Path.DirectorySeparatorChar).Last(); } + bool exist = saveManager.Saves.Exists(g => g.FolderPath == path); + if (exist) + { + AddButton.Enabled = false; + PathErrorLabel.Visible = true; + } else + { + AddButton.Enabled = true; + PathErrorLabel.Visible = false; + } } } @@ -113,6 +127,16 @@ namespace OpenSaveCloudClient { NameBox.Text = LocationBox.Text.Split(Path.DirectorySeparatorChar).Last(); } + if (NameWarningLabel.Enabled) + { + if (MessageBox.Show( + "There is already a game with this name in the library. Would you like to add it anyway?", + "This name already exist", + MessageBoxButtons.YesNo, + MessageBoxIcon.Question) == DialogResult.No) { + return; + } + } result = new GameSave(NameBox.Text, "", LocationBox.Text, null, 0); DialogResult = DialogResult.OK; Close(); @@ -125,7 +149,7 @@ namespace OpenSaveCloudClient private void LockControls(bool value) { value = !value; - button1.Enabled = value; + AddButton.Enabled = value; NameBox.Enabled = value; LocationBox.Enabled = value; pathButton.Enabled = value; diff --git a/OpenSaveCloudClient/Core/LogManager.cs b/OpenSaveCloudClient/Core/LogManager.cs index b06db50..cc162af 100644 --- a/OpenSaveCloudClient/Core/LogManager.cs +++ b/OpenSaveCloudClient/Core/LogManager.cs @@ -58,6 +58,22 @@ namespace OpenSaveCloudClient.Core OnNewMessage(args); } + public void AddWarning(string message) + { + Log log = new() + { + Message = message, + Severity = LogSeverity.Warning, + }; + messages.Add(log); + NewMessageEventArgs args = new() + { + Message = message, + Severity = LogSeverity.Warning, + }; + OnNewMessage(args); + } + public void Clear() { messages.Clear(); diff --git a/OpenSaveCloudClient/Core/SaveManager.cs b/OpenSaveCloudClient/Core/SaveManager.cs index 32bdc52..2eba9fc 100644 --- a/OpenSaveCloudClient/Core/SaveManager.cs +++ b/OpenSaveCloudClient/Core/SaveManager.cs @@ -38,6 +38,21 @@ namespace OpenSaveCloudClient.Core return gameSave; } + /*public GameSave? GetByUuid(string uuid) + { + return saves.FirstOrDefault(g => g.Uuid == uuid); + } + + public void Set(GameSave gameSave) + { + GameSave? g = saves.FirstOrDefault(g => g.Uuid == gameSave.Uuid); + if (g != null) + { + saves.Remove(g); + } + saves.Add(gameSave); + }*/ + private void Load() { string appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "osc"); diff --git a/OpenSaveCloudClient/Core/ServerConnector.cs b/OpenSaveCloudClient/Core/ServerConnector.cs index 71e40e8..cba8511 100644 --- a/OpenSaveCloudClient/Core/ServerConnector.cs +++ b/OpenSaveCloudClient/Core/ServerConnector.cs @@ -7,6 +7,7 @@ using System.Text.Json; using OpenSaveCloudClient.Models.Remote; using OpenSaveCloudClient.Models; using System.Net.Http.Headers; +using System.IO.Compression; namespace OpenSaveCloudClient.Core { @@ -189,55 +190,46 @@ namespace OpenSaveCloudClient.Core return null; } - public void Synchronize() + public async void Synchronize() { string appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "osc"); string cachePath = Path.Combine(appdata, "cache"); logManager.AddInformation("Starting synchronization"); List games = saveManager.Saves; string uuidTask = taskManager.StartTask("Synchronizing games", true, games.Count); + List toUpload = new(); + List toDownload = new(); foreach (GameSave game in games) { try { + game.Archive(); Game? g = GetGameInfoByID(game.Id); if (g != null) { if (g.Available) { - if (g.Hash != game.Hash) + if (g.Revision > game.Revision) { - if (g.Revision != game.Revision) - { - logManager.AddInformation(String.Format("'{0}' was updated from another computer", game.Name)); - } else - { - logManager.AddInformation(String.Format("'{0} need to be updated'", game.Name)); - GameUploadToken? gut = LockGameToUpload(game.Id); - if (gut != null) - { - string archivePath = Path.Combine(cachePath, game.Uuid + ".bin"); - UploadSave(gut.UploadToken, archivePath); - } - } - } + toDownload.Add(game); + } + else if (g.Revision < game.Revision) + { + logManager.AddWarning(String.Format("Revision are the same, maybe uploaded by another computer ({0})", game.Name)); + logManager.AddInformation("To resolve this conflict, force download or force upload from the game detail screen"); + } else { - logManager.AddInformation(String.Format("'{0}' is up to date", game.Name)); + toUpload.Add(game); } } else { logManager.AddInformation(String.Format("First upload of '{0}'", game.Name)); - GameUploadToken? gut = LockGameToUpload(game.Id); - if (gut != null) - { - string archivePath = Path.Combine(cachePath, game.Uuid + ".bin"); - UploadSave(gut.UploadToken, archivePath); - } + toUpload.Add(game); } } else { - logManager.AddError(new Exception("Failed to get game information, the save will not be synchronized")); + logManager.AddWarning(String.Format("'{0}' is not found on this server, force upload it from the game detail screen", game.Name)); } } catch (Exception ex) { @@ -245,6 +237,29 @@ namespace OpenSaveCloudClient.Core } taskManager.UpdateTaskProgress(uuidTask, 1); } + foreach (GameSave game in toUpload) + { + GameUploadToken? gut = LockGameToUpload(game.Id); + if (gut != null) + { + string archivePath = Path.Combine(cachePath, game.Uuid + ".bin"); + UploadSave(gut.UploadToken, archivePath); + UpdateCache(game.Id, game); + } + } + foreach (GameSave game in toDownload) + { + GameUploadToken? gut = LockGameToUpload(game.Id); + if (gut != null) + { + string archivePath = Path.Combine(cachePath, game.Uuid + ".bin"); + if (await DownloadSaveAsync(gut.UploadToken, archivePath, game.FolderPath)) + { + UpdateCache(game.Id, game); + } + } + } + saveManager.Save(); taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended); } @@ -256,7 +271,7 @@ namespace OpenSaveCloudClient.Core { HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "bearer " + token); - HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/{2}", host, port, gameId)).Result; + HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/info/{2}", host, port, gameId)).Result; if (response.IsSuccessStatusCode) { string responseText = response.Content.ReadAsStringAsync().Result; @@ -281,16 +296,17 @@ namespace OpenSaveCloudClient.Core { logManager.AddInformation("Uploading save"); string uuidTask = taskManager.StartTask("Uploading", true, 1); + FileStream stream = File.OpenRead(filePath); try { MultipartFormDataContent multipartFormContent = new(); - var fileStreamContent = new StreamContent(File.OpenRead(filePath)); + var fileStreamContent = new StreamContent(stream); fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); multipartFormContent.Add(fileStreamContent, name: "file", fileName: "file.bin"); HttpClient client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", "bearer " + token); - client.DefaultRequestHeaders.Add("X-UPLOAD-KEY", uploadToken); + client.DefaultRequestHeaders.Add("X-Upload-Key", uploadToken); HttpResponseMessage response = client.PostAsync(string.Format("{0}:{1}/api/v1/game/upload", host, port), multipartFormContent).Result; if (response.IsSuccessStatusCode) { @@ -307,6 +323,65 @@ namespace OpenSaveCloudClient.Core { logManager.AddError(ex); taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed); + } finally + { + stream.Close(); + } + } + + public async Task DownloadSaveAsync(string uploadToken, string filePath, string unzipPath) + { + logManager.AddInformation("Downloading save"); + string uuidTask = taskManager.StartTask("Downloading", true, 1); + try + { + HttpClient client = new HttpClient(); + client.DefaultRequestHeaders.Add("Authorization", "bearer " + token); + client.DefaultRequestHeaders.Add("X-Upload-Key", uploadToken); + HttpResponseMessage response = client.GetAsync(string.Format("{0}:{1}/api/v1/game/download", host, port)).Result; + if (response.IsSuccessStatusCode) + { + using (var fs = new FileStream(filePath, FileMode.Create)) + { + await response.Content.CopyToAsync(fs); + } + if (Directory.Exists(unzipPath)) + { + Directory.Delete(unzipPath, true); + } + ZipFile.ExtractToDirectory(filePath, unzipPath); + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended); + return true; + } + else + { + logManager.AddError(new Exception(String.Format("Received HTTP Status {0} from the server", response.StatusCode.ToString()))); + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed); + } + } + catch (Exception ex) + { + logManager.AddError(ex); + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed); + } + return false; + } + + private void UpdateCache(int gameId, GameSave gameSave) + { + string uuidTask = taskManager.StartTask("Updating cache", true, 1); + Game? game = GetGameInfoByID(gameId); + if (game != null) + { + gameSave.Revision = game.Revision; + gameSave.LocalOnly = false; + gameSave.Synced = true; + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended); + } + else + { + logManager.AddError(new Exception("Failed to get game information")); + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed); } } @@ -375,6 +450,7 @@ namespace OpenSaveCloudClient.Core private void GetServerInformation() { logManager.AddInformation("Getting server information"); + string uuidTask = taskManager.StartTask("Getting server information", true, 1); try { HttpClient client = new(); @@ -387,6 +463,8 @@ namespace OpenSaveCloudClient.Core { logManager.AddInformation("Server is connected"); bind = true; + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Ended); + return; } } } @@ -394,6 +472,7 @@ namespace OpenSaveCloudClient.Core { logManager.AddError(ex); } + taskManager.UpdateTaskStatus(uuidTask, AsyncTaskStatus.Failed); } private void SaveToConfig() diff --git a/OpenSaveCloudClient/GameLibraryForm.Designer.cs b/OpenSaveCloudClient/GameLibraryForm.Designer.cs index 1b95c6c..7334d43 100644 --- a/OpenSaveCloudClient/GameLibraryForm.Designer.cs +++ b/OpenSaveCloudClient/GameLibraryForm.Designer.cs @@ -100,6 +100,7 @@ // AddButton // this.AddButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.AddButton.Enabled = false; this.AddButton.Image = ((System.Drawing.Image)(resources.GetObject("AddButton.Image"))); this.AddButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.AddButton.Name = "AddButton"; @@ -110,6 +111,7 @@ // SyncButton // this.SyncButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.SyncButton.Enabled = false; this.SyncButton.Image = ((System.Drawing.Image)(resources.GetObject("SyncButton.Image"))); this.SyncButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.SyncButton.Name = "SyncButton"; @@ -140,6 +142,7 @@ // LogoutButton // this.LogoutButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.LogoutButton.Enabled = false; this.LogoutButton.Image = ((System.Drawing.Image)(resources.GetObject("LogoutButton.Image"))); this.LogoutButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.LogoutButton.Name = "LogoutButton"; @@ -160,6 +163,7 @@ // AboutButton // this.AboutButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.AboutButton.Enabled = false; this.AboutButton.Image = ((System.Drawing.Image)(resources.GetObject("AboutButton.Image"))); this.AboutButton.ImageTransparentColor = System.Drawing.Color.Magenta; this.AboutButton.Name = "AboutButton"; diff --git a/OpenSaveCloudClient/GameLibraryForm.cs b/OpenSaveCloudClient/GameLibraryForm.cs index 353f7e8..caa8576 100644 --- a/OpenSaveCloudClient/GameLibraryForm.cs +++ b/OpenSaveCloudClient/GameLibraryForm.cs @@ -21,20 +21,22 @@ namespace OpenSaveCloudClient InitializeComponent(); saveManager = SaveManager.GetInstance(); taskManager = TaskManager.GetInstance(); - taskManager.TaskChanged += taskManager_TaskChanged; serverConnector = ServerConnector.GetInstance(); _configuration = Configuration.GetInstance(); logManager = LogManager.GetInstance(); - if (_configuration.GetBoolean("igdb.enabled", false)) + /*if (_configuration.GetBoolean("igdb.enabled", false)) { string clientId = _configuration.GetString("igdb.client_id", ""); string clientSecret = _configuration.GetString("igdb.client_secret", ""); _client = new IGDBClient(clientId, clientSecret); - } + }*/ } private void GameLibrary_Load(object sender, EventArgs e) { + taskManager.TaskChanged += taskManager_TaskChanged; + logManager.Cleared += LogManager_LogCleared; + logManager.NewMessage += LogManager_NewMessage; new Thread(() => { serverConnector.Reconnect(); @@ -44,8 +46,22 @@ namespace OpenSaveCloudClient ShowLoginForm(); }); } + else + { + this.Invoke((MethodInvoker)delegate { + AddButton.Enabled = true; + LogoutButton.Enabled = true; + AboutButton.Enabled = true; + if (_configuration.GetBoolean("synchronization.at_login", true)) + { + SyncButton_Click(sender, e); + } else + { + SyncButton.Enabled = true; + } + }); + } }).Start(); - RefreshList(); } @@ -65,6 +81,17 @@ namespace OpenSaveCloudClient } else { Enabled = true; + AddButton.Enabled = true; + LogoutButton.Enabled = true; + AboutButton.Enabled = true; + if (_configuration.GetBoolean("synchronization.at_login", true)) + { + SyncButton_Click(sender, e); + } + else + { + SyncButton.Enabled = true; + } } } @@ -93,6 +120,10 @@ namespace OpenSaveCloudClient SetTaskEnded(taskUuid); this.Invoke((MethodInvoker)delegate { RefreshList(); + if (_configuration.GetBoolean("synchronization.at_game_creation", true)) + { + SyncButton_Click(null, null); + } }); } else { @@ -170,12 +201,26 @@ namespace OpenSaveCloudClient text = String.Format("Ended: {0}", e.TaskInformation.Label); break; } - toolStripStatusLabel1.Text = text; + if (taskManager.TasksInformation.Count > 1) + { + this.Invoke((MethodInvoker)delegate { + toolStripStatusLabel1.Text = String.Format("{0} (and {1} more)", text, taskManager.TasksInformation.Count); + }); + } + else + { + this.Invoke((MethodInvoker)delegate { + toolStripStatusLabel1.Text = text; + }); + } } private void LogoutButton_Click(object sender, EventArgs e) { serverConnector.Logout(); + AddButton.Enabled = false; + LogoutButton.Enabled = false; + AboutButton.Enabled = false; ShowLoginForm(); } @@ -191,6 +236,40 @@ namespace OpenSaveCloudClient form.Show(); } + private void LogManager_NewMessage(object? sender, NewMessageEventArgs e) + { + int errors = logManager.Messages.Count(m => m.Severity == LogSeverity.Error); + int warnings = logManager.Messages.Count(m => m.Severity == LogSeverity.Warning); + string label = ""; + if (errors > 0) + { + label = String.Format("({0} errors)", errors); + } + if (warnings > 0) + { + if (errors > 0) + { + label += " "; + } + label = String.Format("({0} warnings)", warnings); + } + if (errors > 0 || warnings > 0) + { + this.Invoke((MethodInvoker)delegate { + ErrorLogButton.Text = label; + ErrorLogButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + }); + } + } + + private void LogManager_LogCleared(object? sender, ClearEventArgs e) + { + this.Invoke((MethodInvoker)delegate { + ErrorLogButton.Text = "Show logs"; + ErrorLogButton.DisplayStyle = ToolStripItemDisplayStyle.Image; + }); + } + private void toolStripDropDownButton1_Click(object sender, EventArgs e) { TasksForm form = new(); @@ -199,7 +278,13 @@ namespace OpenSaveCloudClient private void SyncButton_Click(object sender, EventArgs e) { - new Thread(() => serverConnector.Synchronize()).Start(); + SyncButton.Enabled = false; + new Thread(() => { + serverConnector.Synchronize(); + this.Invoke((MethodInvoker)delegate { + SyncButton.Enabled = true; + }); + }).Start(); } } } \ No newline at end of file diff --git a/OpenSaveCloudClient/GameLibraryForm.resx b/OpenSaveCloudClient/GameLibraryForm.resx index 44ceae3..d7db186 100644 --- a/OpenSaveCloudClient/GameLibraryForm.resx +++ b/OpenSaveCloudClient/GameLibraryForm.resx @@ -64,19 +64,16 @@ iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAALLSURBVGhD7ZgLTQRBEERPAhKQgAQkIAEJOEACEpCABCQg - AQlIgH7kmgyz1fPfuwuhkgqBnemp/u4sh3/8EVwZb42Pxlfjm/Hd+GH8PP7k9xfjk/HOyJ6zwkU/G11o - L3H23nhyIJwoK1GjJDO7Yw/hKbF9Y8xBtqcz9WAcLZUecsa10YF4eodnQ1nCABvzgxRpVNZCHKZZIdHz - Blf7nIhnvSMV7+T3ZigDOTkUcSr1ERCJs7mdmngngWhCKfIcSJQ5aBTuSI942FRKiFObIRFI63QWafaW - iCcaRCUyMBP1EpaIB1GzNRsYwDLxRF8ZYEZffOQxpF5UlNPFiwdR9BmTe6BXPIOl+EZWxhhze0R/RDyV - wB4JDKrJs0f0R8X7cxnQqHxWznswKx7KMiLS6SJIQ69Er3iQXzmgLCNlWBkcxYh4wAdTvnaJAwji+6AF - o+KBqgyysoFKVWlkeWRqHxoz4oHqTXpiA+UAmxXytEZOzIoH0XDB9i+oEaocUDUJcydWiAeUqdq/gbpC - MMJSIEqtc7oTq8QDbOb7ZQ+oG6h6idWcwOlV4gH2chtyvDePK0PNiYi94gF7cjvyk1ItlN1+RK8TI+KB - qgyCvcHIVaLViVHx2Ff25HSMFueNnKPmxKh4oBqYqgiDqvqgVEaOyIkZ8ZHNqC+/oTyGLVfq/MAZ8UBN - H1jUggj1Ri6mLYE7MSs+0sHfeFZElAWEnQIIjN4jtX78gfIeyvm7GGRPnd0UfUc0UmGxiSaAuEg8lKOz - hOjSBimn5mg0oFQ2cLinov/QOf3yNgqEYyMqWSjfuq3gADWLU3I4zdWTEdZSEjXbSzKNgVomnKwj3cxq - IstdHqEQJ3lWE+3E1rT4FKUGW03OWireQSRL9TpLbM/2VRMoh5WO8Kbv7aMl4NDW/siJaPaeRbgC5UXt - Igp6hhAKaV5mPWORMrkI0f+Yw+HwBfyyJB+LA9gZAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAIBSURBVGhD7ZgLTQUxEEVXAhKQgAQkIAUHSEACEpCABCQg + AQkwJ9mSpplOp7v9LXk3uXnJ27bz2flttxv+Oe7230vgUfgi/BB+Cr93/uy//PcufBWydgmgCAqhHIrW + kr33wuFAKMKDh8/yTTjEEGK6peIpObsbUJ4Y1gS3JOHYPPkfhF9CTWAPIguZTcBBvULGIjJPG8GrHOn5 + lBhxOJxGxXyJ9JVDoClpB84gZbYK1OQZcW+xqk9gsXbITBLOLjAeaAesQFdVWin2U7pyYWbZLJG8NMEr + 0jauxCdhFiuHT6AZRis0rhLNxsZDbVNK1nlyxbuO2PbKNvOgJIzNcSmzQi6OVas08w0Q5h1PDpoG8FDb + FJh+cCBYW8dMn0JzDvLSYc3TRLMDXsmANIE4SNuDsim0ENG86Skk2bGiZADP483PQm0djEONcNLWQBQO + yDkkZRbe2wWqlWctXvesYw1nepTX3u4fLl9GSVJt00o0by4uP0oAT+OZRXIkW0IDVg4j10fNymHkvhRe + sRq5vB9As9IOmcnqK/mVPuzN0pkD2e7tzD2JDsXKk8Ps+yFkxzPVIcy6ZkH5YtPyYrQRTZUPIJxG5AQy + svN+C/SqTnidWn84YWtAYrU0hBH5dLIewRlDgserG1QvkHQ0HLyZTrQoG766WIPhQ0KlBS6j6A312LZf + a0cxhaBwZhAAAAAASUVORK5CYII= @@ -170,7 +167,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAA7OMCAAJNU0Z0AUkBTAMBAQAB - eAEAAXgBAAEIAQEBdgEBBP8BGQEACP8BQgFNATYHAAE2AwABKAMAASABBAIAAXYBAQIAAQEBAAEYBQAB + iAEAAYgBAAEIAQEBdgEBBP8BGQEACP8BQgFNATYHAAE2AwABKAMAASABBAIAAXYBAQIAAQEBAAEYBQAB QAEUARIRAANSA1EBUgFRBVICUQNSAlEDUgJRAVIEUQFSBVEBUg1RAVAIUQFQAlEBUAFRAVADUQFQAVEE UAFRAVABUQJQAVECUAFRAVABUQ5QAU8BUAFPAlADTwZQAU8BUAFPAVADTwNQAU8CUAZPAVABTwFQBU8B UAZPAU4ETwFOBE8BTgVPAU4DTwJOBE8CTgJPAU4BTwFOAU8HTgFPCE4BTwdOAU0GTgJNBE4BTQNOAk0B diff --git a/OpenSaveCloudClient/LogsForm.cs b/OpenSaveCloudClient/LogsForm.cs index 6d40aac..bff610c 100644 --- a/OpenSaveCloudClient/LogsForm.cs +++ b/OpenSaveCloudClient/LogsForm.cs @@ -33,20 +33,11 @@ namespace OpenSaveCloudClient { this.Invoke((MethodInvoker)delegate { - UpdateList(); + ListViewItem lvi = listView1.Items.Add(e.Message); + lvi.SubItems.Add(e.Severity.ToString()); }); } - private void UpdateList() - { - listView1.Items.Clear(); - foreach (Log l in logManager.Messages) - { - ListViewItem lvi = listView1.Items.Add(l.Message); - lvi.SubItems.Add(l.Severity.ToString()); - } - } - private void LogForm_FormClosed(object sender, FormClosedEventArgs e) { logManager.NewMessage -= logManager_NewError; @@ -54,7 +45,11 @@ namespace OpenSaveCloudClient private void LogsForm_Load(object sender, EventArgs e) { - UpdateList(); + foreach (Log l in logManager.Messages) + { + ListViewItem lvi = listView1.Items.Add(l.Message); + lvi.SubItems.Add(l.Severity.ToString()); + } } } } diff --git a/OpenSaveCloudClient/Models/GameSave.cs b/OpenSaveCloudClient/Models/GameSave.cs index 8d1acaa..207b631 100644 --- a/OpenSaveCloudClient/Models/GameSave.cs +++ b/OpenSaveCloudClient/Models/GameSave.cs @@ -19,7 +19,7 @@ namespace OpenSaveCloudClient.Models private readonly string description; private string hash; private readonly string? coverPath; - private readonly int revision; + private int revision; private bool synced; private bool localOnly; @@ -30,7 +30,7 @@ namespace OpenSaveCloudClient.Models public string FolderPath { get { return folderPath; } } public string Hash { get { return hash; } } public string? CoverPath { get { return coverPath; } } - public int Revision { get { return revision; } } + public int Revision { get { return revision; } set { revision = value; } } public bool Synced { get { return synced; } set { synced = value; } } public bool LocalOnly { get { return localOnly; } set { localOnly = value; } } @@ -76,10 +76,14 @@ namespace OpenSaveCloudClient.Models { Directory.CreateDirectory(cachePath); } - ZipFile.CreateFromDirectory(folderPath, archivePath, CompressionLevel.SmallestSize, true); + if (File.Exists(archivePath)) + { + File.Delete(archivePath); + } + ZipFile.CreateFromDirectory(folderPath, archivePath, CompressionLevel.SmallestSize, false); using (var md5 = MD5.Create()) { - using (var stream = File.OpenRead(archivePath)) + using (FileStream stream = File.OpenRead(archivePath)) { var h = md5.ComputeHash(stream); hash = BitConverter.ToString(h).Replace("-", "").ToLowerInvariant(); diff --git a/OpenSaveCloudClient/Models/Remote/Game.cs b/OpenSaveCloudClient/Models/Remote/Game.cs index d1fc96f..e07b8e5 100644 --- a/OpenSaveCloudClient/Models/Remote/Game.cs +++ b/OpenSaveCloudClient/Models/Remote/Game.cs @@ -16,7 +16,7 @@ namespace OpenSaveCloudClient.Models.Remote [JsonPropertyName("name")] public string Name { get; set; } - [JsonPropertyName("revision")] + [JsonPropertyName("rev")] public int Revision { get; set; } [JsonPropertyName("hash")] diff --git a/OpenSaveCloudClient/SettingsForm.Designer.cs b/OpenSaveCloudClient/SettingsForm.Designer.cs index 8f259df..b09e719 100644 --- a/OpenSaveCloudClient/SettingsForm.Designer.cs +++ b/OpenSaveCloudClient/SettingsForm.Designer.cs @@ -40,7 +40,11 @@ this.linkLabel1 = new System.Windows.Forms.LinkLabel(); this.label2 = new System.Windows.Forms.Label(); this.button1 = new System.Windows.Forms.Button(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.AtCreationCheckBox = new System.Windows.Forms.CheckBox(); + this.AtLoginCheckBox = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); this.SuspendLayout(); // // label1 @@ -108,6 +112,7 @@ // IgdbCheckBox // this.IgdbCheckBox.AutoSize = true; + this.IgdbCheckBox.Enabled = false; this.IgdbCheckBox.Location = new System.Drawing.Point(6, 293); this.IgdbCheckBox.Name = "IgdbCheckBox"; this.IgdbCheckBox.Size = new System.Drawing.Size(135, 29); @@ -146,7 +151,7 @@ // // button1 // - this.button1.Location = new System.Drawing.Point(383, 582); + this.button1.Location = new System.Drawing.Point(383, 767); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(112, 34); this.button1.TabIndex = 2; @@ -154,27 +159,64 @@ this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // - // Settings + // groupBox2 + // + this.groupBox2.Controls.Add(this.AtCreationCheckBox); + this.groupBox2.Controls.Add(this.AtLoginCheckBox); + this.groupBox2.Location = new System.Drawing.Point(12, 564); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(483, 122); + this.groupBox2.TabIndex = 3; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Auto synchronization"; + // + // AtCreationCheckBox + // + this.AtCreationCheckBox.AutoSize = true; + this.AtCreationCheckBox.Checked = true; + this.AtCreationCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.AtCreationCheckBox.Location = new System.Drawing.Point(6, 80); + this.AtCreationCheckBox.Name = "AtCreationCheckBox"; + this.AtCreationCheckBox.Size = new System.Drawing.Size(254, 29); + this.AtCreationCheckBox.TabIndex = 1; + this.AtCreationCheckBox.Text = "After creating a game entry"; + this.AtCreationCheckBox.UseVisualStyleBackColor = true; + // + // AtLoginCheckBox + // + this.AtLoginCheckBox.AutoSize = true; + this.AtLoginCheckBox.Checked = true; + this.AtLoginCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.AtLoginCheckBox.Location = new System.Drawing.Point(6, 45); + this.AtLoginCheckBox.Name = "AtLoginCheckBox"; + this.AtLoginCheckBox.Size = new System.Drawing.Size(122, 29); + this.AtLoginCheckBox.TabIndex = 0; + this.AtLoginCheckBox.Text = "After login"; + this.AtLoginCheckBox.UseVisualStyleBackColor = true; + // + // SettingsForm // this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.SystemColors.Window; - this.ClientSize = new System.Drawing.Size(507, 628); + this.ClientSize = new System.Drawing.Size(507, 813); + this.Controls.Add(this.groupBox2); this.Controls.Add(this.button1); this.Controls.Add(this.groupBox1); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; - this.MaximumSize = new System.Drawing.Size(529, 684); this.MinimumSize = new System.Drawing.Size(529, 684); - this.Name = "Settings"; + this.Name = "SettingsForm"; this.ShowInTaskbar = false; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Settings"; this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -193,5 +235,8 @@ private Label label3; private LinkLabel linkLabel1; private Button button1; + private GroupBox groupBox2; + private CheckBox AtCreationCheckBox; + private CheckBox AtLoginCheckBox; } } \ No newline at end of file diff --git a/OpenSaveCloudClient/SettingsForm.cs b/OpenSaveCloudClient/SettingsForm.cs index 2f8aaa8..103059a 100644 --- a/OpenSaveCloudClient/SettingsForm.cs +++ b/OpenSaveCloudClient/SettingsForm.cs @@ -25,9 +25,11 @@ namespace OpenSaveCloudClient private void InitAndFillFields() { - IgdbCheckBox.Checked = _configuration.GetBoolean("igdb.enabled", false); + IgdbCheckBox.Checked = false; //_configuration.GetBoolean("igdb.enabled", false); IgdbClientID.Text = _configuration.GetString("igdb.client_id", ""); IgdbClientSecret.Text = _configuration.GetString("igdb.client_secret", ""); + AtLoginCheckBox.Checked = _configuration.GetBoolean("synchronization.at_login", true); + AtCreationCheckBox.Checked = _configuration.GetBoolean("synchronization.at_game_creation", true); } private void IgdbCheckBox_CheckedChanged(object sender, EventArgs e) @@ -41,6 +43,8 @@ namespace OpenSaveCloudClient _configuration.SetValue("igdb.enabled", IgdbCheckBox.Checked); _configuration.SetValue("igdb.client_id", IgdbClientID.Text); _configuration.SetValue("igdb.client_secret", IgdbClientSecret.Text); + _configuration.SetValue("synchronization.at_login", AtLoginCheckBox.Checked); + _configuration.SetValue("synchronization.at_game_creation", AtCreationCheckBox.Checked); _configuration.Flush(); } diff --git a/OpenSaveCloudClient/TasksForm.Designer.cs b/OpenSaveCloudClient/TasksForm.Designer.cs index b5a2773..d7fec56 100644 --- a/OpenSaveCloudClient/TasksForm.Designer.cs +++ b/OpenSaveCloudClient/TasksForm.Designer.cs @@ -33,7 +33,6 @@ this.Task = new System.Windows.Forms.ColumnHeader(); this.Status = new System.Windows.Forms.ColumnHeader(); this.Progress = new System.Windows.Forms.ColumnHeader(); - this.uuid = new System.Windows.Forms.ColumnHeader(); this.SuspendLayout(); // // listView1 @@ -41,8 +40,7 @@ this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.Task, this.Status, - this.Progress, - this.uuid}); + this.Progress}); this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; this.listView1.Location = new System.Drawing.Point(0, 0); this.listView1.MultiSelect = false; @@ -67,11 +65,6 @@ this.Progress.Text = "Progress"; this.Progress.Width = 200; // - // uuid - // - this.uuid.Text = "UUID"; - this.uuid.Width = 0; - // // TasksForm // this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F); @@ -93,7 +86,6 @@ private ListView listView1; private ColumnHeader Task; private ColumnHeader Progress; - private ColumnHeader uuid; private ColumnHeader Status; } } \ No newline at end of file