From 0dbcd2acbc9816af62995db67346f921f9942b2b Mon Sep 17 00:00:00 2001 From: Andreas Kueffel Date: Thu, 16 Jan 2025 11:09:03 +0100 Subject: [PATCH 1/7] Stop jobs on exit and clear job list --- FileSyncApp/Program.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/FileSyncApp/Program.cs b/FileSyncApp/Program.cs index ab27a16..b9a5ec8 100644 --- a/FileSyncApp/Program.cs +++ b/FileSyncApp/Program.cs @@ -129,6 +129,11 @@ static void RunProgram() { Thread.Sleep(500); } + foreach(var job in Jobs) + { + job.Value.StopJob(); + } + Jobs.Clear(); } From 090ae06e757cb6bf9552d771a1aab9290de3b05b Mon Sep 17 00:00:00 2001 From: Andreas Kueffel Date: Thu, 16 Jan 2025 11:09:25 +0100 Subject: [PATCH 2/7] add StopJob method to IFileJob --- FileSyncLibNet/Commons/IFileJob.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/FileSyncLibNet/Commons/IFileJob.cs b/FileSyncLibNet/Commons/IFileJob.cs index bb29a1b..3c21e5e 100644 --- a/FileSyncLibNet/Commons/IFileJob.cs +++ b/FileSyncLibNet/Commons/IFileJob.cs @@ -8,6 +8,7 @@ namespace FileSyncLibNet.Commons { public interface IFileJob { + void StopJob(); void StartJob(); void ExecuteNow(); Task ExecuteNowASync(); From 80ef3d879ee27789319ab71cfe0eb916b44afb24 Mon Sep 17 00:00:00 2001 From: Andreas Kueffel Date: Thu, 16 Jan 2025 11:09:55 +0100 Subject: [PATCH 3/7] add FileSyncAppConfigEditor --- .../FileSyncAppConfigEditor.csproj | 25 +++ .../IgnorePropertyResolver.cs | 28 +++ .../JobsEditForm.Designer.cs | 166 ++++++++++++++++ FileSyncAppConfigEditor/JobsEditForm.cs | 186 ++++++++++++++++++ FileSyncAppConfigEditor/JobsEditForm.resx | 126 ++++++++++++ FileSyncAppConfigEditor/Program.cs | 17 ++ 6 files changed, 548 insertions(+) create mode 100644 FileSyncAppConfigEditor/FileSyncAppConfigEditor.csproj create mode 100644 FileSyncAppConfigEditor/IgnorePropertyResolver.cs create mode 100644 FileSyncAppConfigEditor/JobsEditForm.Designer.cs create mode 100644 FileSyncAppConfigEditor/JobsEditForm.cs create mode 100644 FileSyncAppConfigEditor/JobsEditForm.resx create mode 100644 FileSyncAppConfigEditor/Program.cs diff --git a/FileSyncAppConfigEditor/FileSyncAppConfigEditor.csproj b/FileSyncAppConfigEditor/FileSyncAppConfigEditor.csproj new file mode 100644 index 0000000..5c8aafa --- /dev/null +++ b/FileSyncAppConfigEditor/FileSyncAppConfigEditor.csproj @@ -0,0 +1,25 @@ + + + + WinExe + net8.0-windows + enable + true + enable + + + + + + + + + + + + + PreserveNewest + + + + \ No newline at end of file diff --git a/FileSyncAppConfigEditor/IgnorePropertyResolver.cs b/FileSyncAppConfigEditor/IgnorePropertyResolver.cs new file mode 100644 index 0000000..b6aea31 --- /dev/null +++ b/FileSyncAppConfigEditor/IgnorePropertyResolver.cs @@ -0,0 +1,28 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System.Collections.Generic; +using System.Reflection; + +namespace FileSyncAppConfigEditor +{ + //short helper class to ignore some properties from serialization + public class IgnorePropertyResolver: DefaultContractResolver + { + private readonly HashSet ignoreProps; + public IgnorePropertyResolver(params string[] propNamesToIgnore) + { + this.ignoreProps = new HashSet(propNamesToIgnore); + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + if (this.ignoreProps.Contains(property.PropertyName)) + { + property.ShouldSerialize = _ => false; + } + return property; + } + } +} + diff --git a/FileSyncAppConfigEditor/JobsEditForm.Designer.cs b/FileSyncAppConfigEditor/JobsEditForm.Designer.cs new file mode 100644 index 0000000..e13e6d1 --- /dev/null +++ b/FileSyncAppConfigEditor/JobsEditForm.Designer.cs @@ -0,0 +1,166 @@ +namespace FileSyncAppConfigEditor +{ + partial class JobsEditForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + pg_JobEdit = new PropertyGrid(); + lb_Jobs = new ListBox(); + btn_Add = new Button(); + btn_Remove = new Button(); + btn_Save = new Button(); + btn_Load = new Button(); + openFileDialog1 = new OpenFileDialog(); + tb_JobName = new TextBox(); + btn_Rename = new Button(); + btn_AddCleanJob = new Button(); + saveFileDialog1 = new SaveFileDialog(); + SuspendLayout(); + // + // pg_JobEdit + // + pg_JobEdit.Location = new Point(270, 12); + pg_JobEdit.Name = "pg_JobEdit"; + pg_JobEdit.Size = new Size(518, 426); + pg_JobEdit.TabIndex = 0; + // + // lb_Jobs + // + lb_Jobs.FormattingEnabled = true; + lb_Jobs.ItemHeight = 15; + lb_Jobs.Location = new Point(12, 12); + lb_Jobs.Name = "lb_Jobs"; + lb_Jobs.Size = new Size(252, 319); + lb_Jobs.TabIndex = 1; + lb_Jobs.SelectedIndexChanged += ListBoxJobs_SelectedIndexChanged; + // + // btn_Add + // + btn_Add.Location = new Point(12, 382); + btn_Add.Name = "btn_Add"; + btn_Add.Size = new Size(75, 23); + btn_Add.TabIndex = 2; + btn_Add.Text = "Add Sync Job"; + btn_Add.UseVisualStyleBackColor = true; + btn_Add.Click += ButtonAddJob_Click; + // + // btn_Remove + // + btn_Remove.Location = new Point(189, 382); + btn_Remove.Name = "btn_Remove"; + btn_Remove.Size = new Size(75, 23); + btn_Remove.TabIndex = 3; + btn_Remove.Text = "Remove"; + btn_Remove.UseVisualStyleBackColor = true; + btn_Remove.Click += ButtonRemoveJob_Click; + // + // btn_Save + // + btn_Save.Location = new Point(189, 415); + btn_Save.Name = "btn_Save"; + btn_Save.Size = new Size(75, 23); + btn_Save.TabIndex = 4; + btn_Save.Text = "Save"; + btn_Save.UseVisualStyleBackColor = true; + btn_Save.Click += ButtonSaveConfig_Click; + // + // btn_Load + // + btn_Load.Location = new Point(108, 415); + btn_Load.Name = "btn_Load"; + btn_Load.Size = new Size(75, 23); + btn_Load.TabIndex = 5; + btn_Load.Text = "Load"; + btn_Load.UseVisualStyleBackColor = true; + btn_Load.Click += ButtonLoadJobs_Click; + // + // openFileDialog1 + // + openFileDialog1.FileName = "openFileDialog1"; + // + // tb_JobName + // + tb_JobName.Location = new Point(12, 338); + tb_JobName.Name = "tb_JobName"; + tb_JobName.Size = new Size(171, 23); + tb_JobName.TabIndex = 6; + // + // btn_Rename + // + btn_Rename.Location = new Point(189, 337); + btn_Rename.Name = "btn_Rename"; + btn_Rename.Size = new Size(75, 23); + btn_Rename.TabIndex = 7; + btn_Rename.Text = "Rename"; + btn_Rename.UseVisualStyleBackColor = true; + btn_Rename.Click += ButtonRenameJob_Click; + // + // btn_AddCleanJob + // + btn_AddCleanJob.Location = new Point(93, 382); + btn_AddCleanJob.Name = "btn_AddCleanJob"; + btn_AddCleanJob.Size = new Size(75, 23); + btn_AddCleanJob.TabIndex = 8; + btn_AddCleanJob.Text = "Add Clean Job"; + btn_AddCleanJob.UseVisualStyleBackColor = true; + btn_AddCleanJob.Click += ButtonAddJob_Click; + // + // JobsEditForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 450); + Controls.Add(btn_AddCleanJob); + Controls.Add(btn_Rename); + Controls.Add(tb_JobName); + Controls.Add(btn_Load); + Controls.Add(btn_Save); + Controls.Add(btn_Remove); + Controls.Add(btn_Add); + Controls.Add(lb_Jobs); + Controls.Add(pg_JobEdit); + Name = "JobsEditForm"; + Text = "JobsEditForm"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private PropertyGrid pg_JobEdit; + private ListBox lb_Jobs; + private Button btn_Add; + private Button btn_Remove; + private Button btn_Save; + private Button btn_Load; + private OpenFileDialog openFileDialog1; + private TextBox tb_JobName; + private Button btn_Rename; + private Button btn_AddCleanJob; + private SaveFileDialog saveFileDialog1; + } +} diff --git a/FileSyncAppConfigEditor/JobsEditForm.cs b/FileSyncAppConfigEditor/JobsEditForm.cs new file mode 100644 index 0000000..36a167e --- /dev/null +++ b/FileSyncAppConfigEditor/JobsEditForm.cs @@ -0,0 +1,186 @@ +using FileSyncLibNet.Commons; +using FileSyncLibNet.FileCleanJob; +using FileSyncLibNet.FileSyncJob; +using Newtonsoft.Json; +using RoboSharp.Interfaces; +using System.Text.Json; + +namespace FileSyncAppConfigEditor +{ + public partial class JobsEditForm : Form + { + private string configFilePath = "config.json"; + private Dictionary jobs; + JsonSerializerSettings jsonSettings; + + public JobsEditForm(string initialFile=null) + { + InitializeComponent(); + Init(); + if(!string.IsNullOrEmpty(initialFile) && File.Exists(initialFile)) + { + configFilePath = initialFile; + LoadJobsFromFile(initialFile); + } + } + + void Init() + { + jsonSettings = new JsonSerializerSettings + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + ContractResolver = new IgnorePropertyResolver(new string[] { "Logger" }), + TypeNameHandling = TypeNameHandling.Auto, + Formatting = Formatting.Indented + }; + openFileDialog1.FileName = configFilePath; + saveFileDialog1.FileName = configFilePath; + pg_JobEdit.SelectedGridItemChanged += (s, ev) => + { + if (ev.NewSelection != null) + { + //var prop = ev.NewSelection.PropertyDescriptor; + //if (prop != null) + //{ + // var propValue = prop.GetValue(jobs[selectedJob]); + // if (propValue != null) + // { + // if (prop.PropertyType == typeof(System.Net.NetworkCredential)) + // { + // var cred = propValue as System.Net.NetworkCredential; + // if (cred != null) + // { + // cred.Password = ""; + // } + // } + // } + //} + } + }; + } + + private void ButtonLoadJobs_Click(object sender, EventArgs e) + { + openFileDialog1.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*"; + var result = openFileDialog1.ShowDialog(); + if (result != DialogResult.OK) + return; + configFilePath = openFileDialog1.FileName; + if (File.Exists(configFilePath)) + { + LoadJobsFromFile(configFilePath); + } + else + { + jobs = new Dictionary(); + } + } + + private void LoadJobsFromFile(string configFilePath) + { + string json = File.ReadAllText(configFilePath); + jobs = JsonConvert.DeserializeObject>(json, jsonSettings); + lb_Jobs.Items.Clear(); + foreach (var job in jobs.Keys) + { + lb_Jobs.Items.Add(job); + } + } + + private void ListBoxJobs_SelectedIndexChanged(object sender, EventArgs e) + { + if (lb_Jobs.SelectedItem != null) + { + string selectedJob = lb_Jobs.SelectedItem.ToString(); + pg_JobEdit.SelectedObject = jobs[selectedJob]; + + tb_JobName.Text = selectedJob; // Set the text box to the selected job name + } + } + + private void ButtonAddJob_Click(object sender, EventArgs e) + { + string newJobName = "NewJob_" + DateTime.Now.Ticks; + IFileJobOptions newJob = null; + if (sender == btn_Add) + { + newJob = new FileSyncJobOptions() + { + SourcePath = "C:\\Source", + SyncDeleted = false, + DeleteSourceAfterBackup = false, + RememberLastSync = true, + MaxAge = TimeSpan.FromDays(10), + Credentials = new System.Net.NetworkCredential { UserName = "", Password = "", Domain = "" }, + DestinationPath = "D:\\Destination", + Interval = TimeSpan.FromMinutes(5), + SearchPattern = "*.*", + Subfolders = new List(), + Recursive = true, + FileSyncProvider = FileSyncLibNet.SyncProviders.SyncProvider.Abstract + }; + } + if (sender == btn_AddCleanJob) + { + newJob = new FileCleanJobOptions() + { + DestinationPath = "C:\\temp", + Credentials = new System.Net.NetworkCredential { UserName = "", Password = "", Domain = "" }, + MaxAge = TimeSpan.FromDays(10), + Interval = TimeSpan.FromMinutes(5), + FileSyncProvider = FileSyncLibNet.SyncProviders.SyncProvider.Abstract + }; + } + + jobs.Add(newJobName, newJob); + lb_Jobs.Items.Add(newJobName); + } + + private void ButtonRemoveJob_Click(object sender, EventArgs e) + { + if (lb_Jobs.SelectedItem != null) + { + string selectedJob = lb_Jobs.SelectedItem.ToString(); + jobs.Remove(selectedJob); + lb_Jobs.Items.Remove(selectedJob); + pg_JobEdit.SelectedObject = null; + tb_JobName.Text = ""; // Clear the text box + } + } + + private void ButtonSaveConfig_Click(object sender, EventArgs e) + { + saveFileDialog1.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*"; + var result = saveFileDialog1.ShowDialog(); + if (result != DialogResult.OK) + return; + configFilePath = saveFileDialog1.FileName; + string json = JsonConvert.SerializeObject(jobs, jsonSettings); + File.WriteAllText(configFilePath, json); + MessageBox.Show("Configuration saved successfully.", "Save Config", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void ButtonRenameJob_Click(object sender, EventArgs e) + { + if (lb_Jobs.SelectedItem != null && !string.IsNullOrWhiteSpace(tb_JobName.Text)) + { + string oldJobName = lb_Jobs.SelectedItem.ToString(); + string newJobName = tb_JobName.Text; + + if (jobs.ContainsKey(newJobName)) + { + MessageBox.Show("A job with this name already exists.", "Rename Job", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + var job = jobs[oldJobName]; + jobs.Remove(oldJobName); + jobs.Add(newJobName, job); + + int selectedIndex = lb_Jobs.SelectedIndex; + lb_Jobs.Items[selectedIndex] = newJobName; + lb_Jobs.SelectedIndex = selectedIndex; + } + } + } +} diff --git a/FileSyncAppConfigEditor/JobsEditForm.resx b/FileSyncAppConfigEditor/JobsEditForm.resx new file mode 100644 index 0000000..9e0824f --- /dev/null +++ b/FileSyncAppConfigEditor/JobsEditForm.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 156, 17 + + \ No newline at end of file diff --git a/FileSyncAppConfigEditor/Program.cs b/FileSyncAppConfigEditor/Program.cs new file mode 100644 index 0000000..e91d8bd --- /dev/null +++ b/FileSyncAppConfigEditor/Program.cs @@ -0,0 +1,17 @@ +namespace FileSyncAppConfigEditor +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new JobsEditForm()); + } + } +} \ No newline at end of file From 61fdb53f9887f27803718e84e7906822b1b17602 Mon Sep 17 00:00:00 2001 From: Andreas Kueffel Date: Thu, 16 Jan 2025 11:10:19 +0100 Subject: [PATCH 4/7] use net8 and add config Editor reference --- FileSyncAppWin/FileSyncAppWin.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/FileSyncAppWin/FileSyncAppWin.csproj b/FileSyncAppWin/FileSyncAppWin.csproj index aedd9ba..82030c1 100644 --- a/FileSyncAppWin/FileSyncAppWin.csproj +++ b/FileSyncAppWin/FileSyncAppWin.csproj @@ -2,13 +2,14 @@ WinExe - net6.0-windows + net8.0-windows true enable + From fd7283709747f56afc746b0fee57e21f878b36ff Mon Sep 17 00:00:00 2001 From: Andreas Kueffel Date: Thu, 16 Jan 2025 11:10:53 +0100 Subject: [PATCH 5/7] implement edit config and restart in FileSyncAppWin --- FileSyncAppWin/MainForm.Designer.cs | 49 ++++++++++++++++++++++++++--- FileSyncAppWin/MainForm.cs | 38 +++++++++++++++++----- FileSyncAppWin/MainForm.resx | 4 +-- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/FileSyncAppWin/MainForm.Designer.cs b/FileSyncAppWin/MainForm.Designer.cs index d4a7921..1a061e9 100644 --- a/FileSyncAppWin/MainForm.Designer.cs +++ b/FileSyncAppWin/MainForm.Designer.cs @@ -32,6 +32,10 @@ private void InitializeComponent() System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); textBox1 = new TextBox(); notifyIcon1 = new NotifyIcon(components); + panel1 = new Panel(); + btn_Config = new Button(); + btn_Restart = new Button(); + panel1.SuspendLayout(); SuspendLayout(); // // textBox1 @@ -42,7 +46,7 @@ private void InitializeComponent() textBox1.Name = "textBox1"; textBox1.ReadOnly = true; textBox1.ScrollBars = ScrollBars.Vertical; - textBox1.Size = new Size(800, 450); + textBox1.Size = new Size(732, 299); textBox1.TabIndex = 0; // // notifyIcon1 @@ -50,21 +54,58 @@ private void InitializeComponent() notifyIcon1.Icon = (Icon)resources.GetObject("notifyIcon1.Icon"); notifyIcon1.Text = "FileSyncAppWin"; // + // panel1 + // + panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + panel1.Controls.Add(textBox1); + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(732, 299); + panel1.TabIndex = 1; + // + // btn_Config + // + btn_Config.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + btn_Config.Location = new Point(562, 326); + btn_Config.Name = "btn_Config"; + btn_Config.Size = new Size(75, 23); + btn_Config.TabIndex = 2; + btn_Config.Text = "Config"; + btn_Config.UseVisualStyleBackColor = true; + btn_Config.Click += btn_Config_Click; + // + // btn_Restart + // + btn_Restart.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + btn_Restart.Location = new Point(647, 326); + btn_Restart.Name = "btn_Restart"; + btn_Restart.Size = new Size(75, 23); + btn_Restart.TabIndex = 3; + btn_Restart.Text = "Restart"; + btn_Restart.UseVisualStyleBackColor = true; + btn_Restart.Click += btn_Restart_Click; + // // MainForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(800, 450); - Controls.Add(textBox1); + ClientSize = new Size(734, 361); + Controls.Add(btn_Restart); + Controls.Add(btn_Config); + Controls.Add(panel1); Name = "MainForm"; Text = "FileSyncAppWin"; + panel1.ResumeLayout(false); + panel1.PerformLayout(); ResumeLayout(false); - PerformLayout(); } #endregion private TextBox textBox1; private NotifyIcon notifyIcon1; + private Panel panel1; + private Button btn_Config; + private Button btn_Restart; } } \ No newline at end of file diff --git a/FileSyncAppWin/MainForm.cs b/FileSyncAppWin/MainForm.cs index faec8ca..5f2ab66 100644 --- a/FileSyncAppWin/MainForm.cs +++ b/FileSyncAppWin/MainForm.cs @@ -3,15 +3,14 @@ namespace FileSyncAppWin public partial class MainForm : Form { Thread consoleThread; + string[] Args; public MainForm(string[] args) { InitializeComponent(); + Args = args; this.FormClosing += (s, e) => { FileSyncApp.Program.keepRunning = false; consoleThread?.Join(10_000); }; - consoleThread = new Thread(() => - { - FileSyncApp.Program.Main(args); - }); + FileSyncApp.Program.JobsReady += (s, e) => { foreach (var job in FileSyncApp.Program.Jobs) @@ -33,8 +32,7 @@ public MainForm(string[] args) }; - consoleThread.Start(); - + this.Resize += ((s, e) => { this.SuspendLayout(); @@ -57,11 +55,26 @@ public MainForm(string[] args) }; notifyIcon1.BalloonTipClicked += (s, e) => { this.BeginInvoke(() => { WindowState = FormWindowState.Normal; ShowInTaskbar = true; }); }; //notifyIcon1.BalloonTipShown += (s, e) => { ShowInTaskbar = false; }; - + StartConsoleThread(); //this.WindowState = FormWindowState.Minimized; } + void StartConsoleThread() + { + consoleThread = new Thread(() => + { + FileSyncApp.Program.Main(Args); + }); + consoleThread.Start(); + } + void Restart() + { + FileSyncApp.Program.keepRunning = false; + consoleThread?.Join(10_000); + FileSyncApp.Program.keepRunning = true; + StartConsoleThread(); + } private void NewLogOutput(string e) @@ -70,5 +83,16 @@ private void NewLogOutput(string e) this.BeginInvoke(() => { textBox1.Text = string.Join(Environment.NewLine, (new string[] { $"{DateTime.Now.ToString("HH:mm:ss.fff")} {e}" }).Concat(textBox1.Text.Split(Environment.NewLine).Take(1000))); }); } + + private void btn_Config_Click(object sender, EventArgs e) + { + FileSyncAppConfigEditor.JobsEditForm jobsEditForm = new FileSyncAppConfigEditor.JobsEditForm("config.json"); + jobsEditForm.ShowDialog(); + } + + private void btn_Restart_Click(object sender, EventArgs e) + { + Restart(); + } } } \ No newline at end of file diff --git a/FileSyncAppWin/MainForm.resx b/FileSyncAppWin/MainForm.resx index 692f1df..e46894b 100644 --- a/FileSyncAppWin/MainForm.resx +++ b/FileSyncAppWin/MainForm.resx @@ -1,7 +1,7 @@