I18NCommander/I18N Commander/UI WinForms/Components/Setting.cs
Thorsten Sommer 0587af18f2
Added Git Export Feature
- Added import algorithm
- Added FromJsonX() methods to data models
- Added possibility to work with temp. database file
- Added export processor to handle export process & triggers
- Added something changed event e.g. as export trigger
- Added possibility to import a JSON export
- Updated Git icon
2023-01-22 19:35:57 +01:00

858 lines
39 KiB
C#

using System.Diagnostics;
using DataModel.Database;
using Processor;
using UI_WinForms.Resources;
namespace UI_WinForms.Components;
public sealed partial class Setting : UserControl
{
private readonly record struct SettingUIData(
Bitmap Icon,
Func<string> SettingName,
Func<string> SettingExplanation,
Func<(string URL, string TextPattern)> SettingExplanationLink,
Func<Action, Control> SetupDataControl,
bool ChangeNeedsRestart
);
private readonly SettingUIData data;
private bool needRestart = false;
public Setting()
{
this.InitializeComponent();
}
public bool NeedRestart => this.needRestart;
private Setting(SettingUIData settingMetaData)
{
this.InitializeComponent();
if(this.DesignMode)
return;
this.Dock = DockStyle.Top;
this.data = settingMetaData;
this.labelIcon.Image = settingMetaData.Icon;
this.labelSettingName.Text = settingMetaData.SettingName();
this.labelExplanation.Text = settingMetaData.SettingExplanation();
//
// Handle up to one link in the explanation:
//
var link = settingMetaData.SettingExplanationLink();
var startIdx = this.labelExplanation.Text.IndexOf(link.TextPattern, StringComparison.InvariantCulture);
this.labelExplanation.Links.Clear();
if (!string.IsNullOrWhiteSpace(link.TextPattern) && !string.IsNullOrWhiteSpace(link.URL) && startIdx > -1)
this.labelExplanation.Links.Add(startIdx, link.TextPattern.Length, link.URL);
this.labelExplanation.LinkClicked += (_, args) =>
{
if(args.Link.LinkData is string url && !string.IsNullOrWhiteSpace(url) && url.ToLowerInvariant().StartsWith("https://", StringComparison.InvariantCulture))
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
};
var dataControl = settingMetaData.SetupDataControl(this.ChangeTrigger);
this.tableLayout.Controls.Add(dataControl, 2, 0);
// Ensure, that this data control is vertical centered by calculating the needed margin, considering the outer size of the table layout:
var margin = (this.tableLayout.GetRowHeights().First() - dataControl.Height) / 2f;
dataControl.Margin = new Padding(0, (int) margin, 0, (int)margin);
// Calculate the needed height of the explanation label & centering of the data control when the parent window is resized:
this.tableLayout.Resize += (sender, args) =>
{
// Adjust the height of the parent controls (table & user control):
this.tableLayout.Height = Math.Max((int)this.labelExplanation.CreateGraphics().MeasureString(this.labelExplanation.Text, this.labelExplanation.Font, new SizeF(this.labelExplanation.Width, 1000)).Height, 66);
this.Height = this.tableLayout.Height + this.tableLayout.Margin.Vertical;
// Ensure, that this data control is vertical centered by calculating the needed margin, considering the outer size of the table layout:
var margin = (this.tableLayout.GetRowHeights().First() - dataControl.Height) / 2f;
dataControl.Margin = new Padding(0, (int) margin, 0, (int)margin);
};
}
private void ChangeTrigger()
{
if(this.data.ChangeNeedsRestart)
this.needRestart = true;
AppEvents.SettingsChanged();
}
private void UpdateExplanation() => this.labelExplanation.Text = this.data.SettingExplanation();
private static async Task<Setting> ShowDeepLModeSettingAsync()
{
var currentSetting = await AppSettings.GetDeepLMode();
var settingData = new SettingUIData(
Icon: Icons.deepl_logo_icon_170284,
SettingName: () => "DeepL Service",
ChangeNeedsRestart: true,
SettingExplanation: () => "DeepL is a translation service that offers a wide range of translation services. This setting allows you to choose between the free and pro version of DeepL.",
SettingExplanationLink: () => ("https://www.deepl.com/", "DeepL"),
SetupDataControl: (changeTrigger) =>
{
var dropdown = new ComboBox();
dropdown.Items.Add("Disabled");
dropdown.Items.Add("Free version");
dropdown.Items.Add("Pro version");
dropdown.SelectedIndex = currentSetting switch
{
SettingDeepLMode.DISABLED => 0,
SettingDeepLMode.USE_FREE_ACCOUNT => 1,
SettingDeepLMode.USE_PRO_ACCOUNT => 2,
_ => 0,
};
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetDeepLMode(dropdown.SelectedIndex switch
{
0 => SettingDeepLMode.DISABLED,
1 => SettingDeepLMode.USE_FREE_ACCOUNT,
2 => SettingDeepLMode.USE_PRO_ACCOUNT,
_ => SettingDeepLMode.DISABLED,
});
// Fires the change trigger:
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowDeepLAPIKeySettingAsync()
{
var currentSetting = await AppSettings.GetDeepLAPIKey();
var settingData = new SettingUIData(
Icon: Icons.icons8_key_512,
SettingName: () => "DeepL API Key",
ChangeNeedsRestart: true,
SettingExplanation: () => "The API key is required to use the DeepL translation service. You can find your API key on the DeepL website.",
SettingExplanationLink: () => ("https://www.deepl.com/", "DeepL"),
SetupDataControl: (changeTrigger) =>
{
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetDeepLAPIKey(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
return textbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowDeepLUsageSettingAsync()
{
var currentUsage = await Processor.DeepL.GetUsage();
var percent = currentUsage.Enabled ? currentUsage.CharacterCount / (float)currentUsage.CharacterLimit : 0;
// Local function to show & update the explanation text:
string GetUsageText() => currentUsage.Enabled ?
$"You used {currentUsage.CharacterCount:###,###,###,##0} characters out of {currentUsage.CharacterLimit:###,###,###,##0} ({percent:P2})." : currentUsage.AuthIssue ?
"Was not able to authorize with DeepL. Please check your API key." :
"DeepL is disabled or the API key is not set.";
var settingData = new SettingUIData(
Icon: Icons.icons8_increase_512,
SettingName: () => "DeepL Usage",
ChangeNeedsRestart: false,
SettingExplanation: GetUsageText,
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
var progressbar = new ProgressBar();
progressbar.Maximum = 100;
progressbar.Margin = new Padding(0, 16, 0, 16);
progressbar.Dock = DockStyle.Fill;
progressbar.Style = ProgressBarStyle.Continuous;
progressbar.Value = percent switch
{
< 0 => 0,
> 1 => 100,
_ => (int)(percent * 100)
};
var reloadButton = new Button();
reloadButton.Text = string.Empty;
reloadButton.Image = Icons.icons8_reload_512;
reloadButton.FlatStyle = FlatStyle.Flat;
reloadButton.FlatAppearance.BorderSize = 0;
reloadButton.BackColor = Color.Empty;
reloadButton.UseVisualStyleBackColor = true;
reloadButton.Size = new Size(60, 60);
reloadButton.Click += async (sender, args) =>
{
var usage = await Processor.DeepL.GetUsage();
// Update the outer variables:
percent = usage.Enabled ? usage.CharacterCount / (float)usage.CharacterLimit : 0;
currentUsage = usage;
// Update the progress bar:
progressbar.Value = percent switch
{
< 0 => 0,
> 1 => 100,
_ => (int)(percent * 100)
};
// Update the explanation text. Therefore, we need to get the setting object through the chain of parents:
var setting = (Setting) (((Control) sender!)!).Parent.Parent.Parent;
setting.UpdateExplanation();
};
// Setup the layout:
var layout = new TableLayoutPanel();
layout.ColumnCount = 2;
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66));
layout.RowCount = 1;
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
layout.Controls.Add(progressbar, 0, 0);
layout.Controls.Add(reloadButton, 1, 0);
layout.Dock = DockStyle.Fill;
return layout;
}
);
var setting = new Setting(settingData);
return setting;
}
private static async Task<Setting> ShowDeepLActionSettingAsync()
{
var currentSetting = await AppSettings.GetDeepLAction();
var settingData = new SettingUIData(
Icon: Icons.icons8_play_512__2_,
SettingName: () => "DeepL Operation",
ChangeNeedsRestart: true,
SettingExplanation: () => "Should the missing translations be automatically completed by DeepL? This can lead to higher costs. By default, DeepL is only applied manually.",
SettingExplanationLink: () => ("https://www.deepl.com/", "DeepL"),
SetupDataControl: (changeTrigger) =>
{
// We set up a combo box with the available actions:
var dropdown = new ComboBox();
dropdown.Items.Add("Manual");
dropdown.Items.Add("Automatic");
dropdown.SelectedIndex = currentSetting switch
{
SettingDeepLAction.MANUAL => 0,
SettingDeepLAction.AUTOMATIC_ALL => 1,
_ => 0,
};
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetDeepLAction(dropdown.SelectedIndex switch
{
0 => SettingDeepLAction.MANUAL,
1 => SettingDeepLAction.AUTOMATIC_ALL,
_ => SettingDeepLAction.MANUAL,
});
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
internal readonly record struct ComboBoxItem(string DisplayText, int CultureIndex)
{
public override string ToString() => this.DisplayText;
}
private static async Task<Setting> ShowDeepLSourceCultureSettingAsync()
{
var currentSourceCultureIndex = await AppSettings.GetDeepLSourceCultureIndex();
// We load the corresponding culture for that index. As dropdown items, we show
// all other available cultures:
var allCultures = await AppSettings.GetCultureInfos();
// Attention: We have to store the culture's index, because the index is not
// continuous and can change when the user adds or removes a culture!
var settingData = new SettingUIData(
Icon: Icons.icons8_chat_bubble_512,
SettingName: () => "DeepL Source Culture",
ChangeNeedsRestart: true,
SettingExplanation: () => "The source culture is used to translate the missing translations.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
var dropdown = new ComboBox();
var currentCultureDropdownIndex = 0;
for (var n = 0; n < allCultures.Count; n++)
{
var cultureInfo = allCultures[n];
if(cultureInfo.Index == currentSourceCultureIndex)
currentCultureDropdownIndex = n;
dropdown.Items.Add(new ComboBoxItem($"{cultureInfo.Index}.: {cultureInfo.Code}", cultureInfo.Index));
}
dropdown.SelectedIndex = currentCultureDropdownIndex;
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) =>
{
if(dropdown.SelectedItem is ComboBoxItem selectedItem)
await AppSettings.SetDeepLSourceCultureIndex(selectedItem.CultureIndex);
};
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
private static IEnumerable<Task<Setting>> ShowCultureSettingsAsync()
{
var isFirstCulture = true; // We need this flag to distinguish the first task from the others.
var cultureIndices = new List<int>(new []{ -1 });
while (cultureIndices.Count > 0)
{
var innerLoopIndex = cultureIndices.Last(); // needed to avoid closure issues.
yield return Task.Run(async () =>
{
var localCultureIndex = innerLoopIndex;
// Get a list of culture indices. Thus, we know the number of cultures. We cannot do this in the outer loop,
// because we cannot await there. The AppSettings is caching the answer, though. The list of indices is ordered
// ascending.
var localCultureIndices = await AppSettings.GetCultureIndices();
// Update the number of cultures in the outer loop for the first call:
if(isFirstCulture)
{
localCultureIndex = localCultureIndices.Last();
innerLoopIndex = localCultureIndices.Last();
cultureIndices.Clear();
cultureIndices.AddRange(localCultureIndices);
isFirstCulture = false;
}
// Get the current culture code:
var currentCultureCode = await AppSettings.GetCultureCode(localCultureIndex);
// Construct the setting:
return new Setting(new()
{
Icon = Icons.icons8_chat_bubble_512,
SettingName = () => $"{localCultureIndex}. Culture",
ChangeNeedsRestart = true,
SettingExplanation = () => "The culture according to RFC 4646: First comes the ISO 639-1 language code in lower case, followed by a hyphen, followed by the ISO 3166-1 alpha-2 country code in upper case. Example: en-US for English in the USA, de-DE for German in Germany.",
SettingExplanationLink = () => ("https://lonewolfonline.net/list-net-culture-country-codes/", "according to RFC 4646"),
SetupDataControl = (changeTrigger) =>
{
var textbox = new TextBox();
textbox.Text = currentCultureCode;
textbox.TextChanged += async (sender, args) =>
{
await AppSettings.SetCultureCode(localCultureIndex, textbox.Text);
changeTrigger();
};
textbox.Dock = DockStyle.Fill;
return textbox;
}
});
});
cultureIndices.Remove(innerLoopIndex);
}
}
private static async Task<Setting> ShowGeneratorModeSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorMode();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator Mode",
ChangeNeedsRestart: false,
SettingExplanation: () => "The generator mode determines how the translation files are generated.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// We set up a combo box with the available actions:
var dropdown = new ComboBox();
dropdown.Items.Add("Automatic generation");
dropdown.Items.Add("Manual generation");
dropdown.SelectedIndex = currentSetting switch
{
SettingGeneratorMode.AUTOMATIC => 0,
SettingGeneratorMode.MANUAL => 1,
_ => 0,
};
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetGeneratorMode(dropdown.SelectedIndex switch
{
0 => SettingGeneratorMode.AUTOMATIC,
1 => SettingGeneratorMode.MANUAL,
_ => SettingGeneratorMode.AUTOMATIC,
});
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetEnabledSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorDotnetEnabled();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET",
ChangeNeedsRestart: false,
SettingExplanation: () => "When enabled, .NET translation files are generated. Requires a .NET 6 or newer project.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up an checkbox:
var checkbox = new CheckBox();
checkbox.Checked = currentSetting;
checkbox.CheckedChanged += async (sender, args) => await AppSettings.SetGeneratorDotnetEnabled(checkbox.Checked);
checkbox.CheckedChanged += (sender, args) => changeTrigger();
checkbox.Text = "Enable .NET Generator";
// Apply the desired layout:
checkbox.Dock = DockStyle.Fill;
return checkbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetDestinationPathSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorDotnetDestinationPath();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET Destination Path",
ChangeNeedsRestart: false,
SettingExplanation: () => "The destination path for the .NET translation files. You might use environment variables like %USERPROFILE%.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a horizontal layout:
var layout = new TableLayoutPanel();
layout.ColumnCount = 2;
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66F));
layout.RowCount = 1;
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layout.Dock = DockStyle.Fill;
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetGeneratorDotnetDestinationPath(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
layout.Controls.Add(textbox, 0, 0);
// Set up a button:
var button = new Button();
button.Text = string.Empty;
button.Image = Icons.icons8_folder_tree_512;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
button.BackColor = Color.Empty;
button.UseVisualStyleBackColor = true;
button.Size = new Size(60, 60);
button.Click += (sender, args) =>
{
var dialog = new FolderBrowserDialog();
dialog.SelectedPath = textbox.Text;
dialog.InitialDirectory = textbox.Text;
dialog.Description = "Select the destination path for the .NET translation files.";
dialog.ShowNewFolderButton = true;
if (dialog.ShowDialog() == DialogResult.OK)
textbox.Text = dialog.SelectedPath;
};
button.Dock = DockStyle.Fill;
layout.Controls.Add(button, 1, 0);
return layout;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetNamespaceSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorDotnetNamespace();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET Namespace",
ChangeNeedsRestart: false,
SettingExplanation: () => "The namespace for the .NET I18N files.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetGeneratorDotnetNamespace(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
return textbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetDefaultCultureSettingAsync()
{
var currentSourceCultureIndex = await AppSettings.GetGeneratorDotnetDefaultCultureIndex();
// We load the corresponding culture for that index. As dropdown items, we show
// all other available cultures:
var allCultures = await AppSettings.GetCultureInfos();
// Attention: We have to store the culture's index, because the index is not
// continuous and can change when the user adds or removes a culture!
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET Default Culture",
ChangeNeedsRestart: false,
SettingExplanation: () => "The default culture for the .NET, which is used when no culture is specified or available.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
var dropdown = new ComboBox();
var currentCultureDropdownIndex = 0;
for (var n = 0; n < allCultures.Count; n++)
{
var cultureInfo = allCultures[n];
if(cultureInfo.Index == currentSourceCultureIndex)
currentCultureDropdownIndex = n;
dropdown.Items.Add(new ComboBoxItem($"{cultureInfo.Index}.: {cultureInfo.Code}", cultureInfo.Index));
}
dropdown.SelectedIndex = currentCultureDropdownIndex;
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) =>
{
if(dropdown.SelectedItem is ComboBoxItem selectedItem)
await AppSettings.SetGeneratorDotnetDefaultCultureIndex(selectedItem.CultureIndex);
};
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorGodotEnabledSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorGodotEnabled();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: Godot",
ChangeNeedsRestart: false,
SettingExplanation: () => "When enabled, Godot translation files are generated. Requires a Godot 3.5 or newer project.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up an checkbox:
var checkbox = new CheckBox();
checkbox.Checked = currentSetting;
checkbox.CheckedChanged += async (sender, args) => await AppSettings.SetGeneratorGodotEnabled(checkbox.Checked);
checkbox.CheckedChanged += (sender, args) => changeTrigger();
checkbox.Text = "Enable Godot Generator";
// Apply the desired layout:
checkbox.Dock = DockStyle.Fill;
return checkbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorGodotDestinationPathSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorGodotDestinationPath();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: Godot Destination Path",
ChangeNeedsRestart: false,
SettingExplanation: () => "The destination path for the Godot translation files. You might use environment variables like %USERPROFILE%.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a horizontal layout:
var layout = new TableLayoutPanel();
layout.ColumnCount = 2;
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66F));
layout.RowCount = 1;
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layout.Dock = DockStyle.Fill;
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetGeneratorGodotDestinationPath(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
layout.Controls.Add(textbox, 0, 0);
// Set up a button:
var button = new Button();
button.Text = string.Empty;
button.Image = Icons.icons8_folder_tree_512;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
button.BackColor = Color.Empty;
button.UseVisualStyleBackColor = true;
button.Size = new Size(60, 60);
button.Click += (sender, args) =>
{
var dialog = new FolderBrowserDialog();
dialog.SelectedPath = textbox.Text;
dialog.InitialDirectory = textbox.Text;
dialog.Description = "Select the destination path for the Godot translation files.";
dialog.ShowNewFolderButton = true;
if (dialog.ShowDialog() == DialogResult.OK)
textbox.Text = dialog.SelectedPath;
};
button.Dock = DockStyle.Fill;
layout.Controls.Add(button, 1, 0);
return layout;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorAutoExportEnabledSettingAsync()
{
var currentSetting = await AppSettings.GetAutoExportEnabled();
var settingData = new SettingUIData(
Icon: Icons.icons8_git,
SettingName: () => "Git (JSON) Auto-Export: Enabled",
ChangeNeedsRestart: true,
SettingExplanation: () => "When enabled, all changes are automatically exported into a Git repository as JSON file.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up an checkbox:
var checkbox = new CheckBox();
checkbox.Checked = currentSetting;
checkbox.CheckedChanged += async (sender, args) =>
{
await AppSettings.SetAutoExportEnabled(checkbox.Checked);
await ExportProcessor.TriggerExport();
changeTrigger();
};
checkbox.Text = "Enable Auto-Export";
// Apply the desired layout:
checkbox.Dock = DockStyle.Fill;
return checkbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorAutoExportDestinationPathSettingAsync()
{
var currentSetting = await AppSettings.GetAutoExportDestinationPath();
var settingData = new SettingUIData(
Icon: Icons.icons8_git,
SettingName: () => "Git (JSON) Auto-Export: Destination Path",
ChangeNeedsRestart: true,
SettingExplanation: () => "The destination path for the Git repository. You might use environment variables like %USERPROFILE%.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a horizontal layout:
var layout = new TableLayoutPanel();
layout.ColumnCount = 2;
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66F));
layout.RowCount = 1;
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layout.Dock = DockStyle.Fill;
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetAutoExportDestinationPath(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
layout.Controls.Add(textbox, 0, 0);
// Set up a button:
var button = new Button();
button.Text = string.Empty;
button.Image = Icons.icons8_folder_tree_512;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
button.BackColor = Color.Empty;
button.UseVisualStyleBackColor = true;
button.Size = new Size(60, 60);
button.Click += (sender, args) =>
{
var dialog = new FolderBrowserDialog();
dialog.SelectedPath = textbox.Text;
dialog.InitialDirectory = textbox.Text;
dialog.Description = "Select the destination path for the Git repository.";
dialog.ShowNewFolderButton = true;
if (dialog.ShowDialog() == DialogResult.OK)
textbox.Text = dialog.SelectedPath;
};
button.Dock = DockStyle.Fill;
layout.Controls.Add(button, 1, 0);
return layout;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorAutoExportFilenameSettingAsync()
{
var currentSetting = await AppSettings.GetAutoExportFilename();
var settingData = new SettingUIData(
Icon: Icons.icons8_git,
SettingName: () => "Git (JSON) Auto-Export: Filename",
ChangeNeedsRestart: true,
SettingExplanation: () => "The filename used for the Git export. You might use environment variables like %USERPROFILE%.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetAutoExportFilename(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
return textbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorAutoExportExportSensitiveDataSettingAsync()
{
var currentSetting = await AppSettings.GetAutoExportSensitiveData();
var settingData = new SettingUIData(
Icon: Icons.icons8_git,
SettingName: () => "Git (JSON) Auto-Export: Export Sensitive Data",
ChangeNeedsRestart: true,
SettingExplanation: () => "When enabled, sensitive data like API tokens are exported into the Git repository. This is not recommended!",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up an checkbox:
var checkbox = new CheckBox();
checkbox.Checked = currentSetting;
checkbox.CheckedChanged += async (sender, args) => await AppSettings.SetAutoExportSensitiveData(checkbox.Checked);
checkbox.CheckedChanged += (sender, args) => changeTrigger();
checkbox.Text = "Export Sensitive Data";
// Apply the desired layout:
checkbox.Dock = DockStyle.Fill;
return checkbox;
}
);
return new Setting(settingData);
}
public static IEnumerable<Task<Setting>> GetAllSettings()
{
//
// Remember: The reverse order is the order in the UI!
//
yield return ShowGeneratorAutoExportFilenameSettingAsync();
yield return ShowGeneratorAutoExportDestinationPathSettingAsync();
yield return ShowGeneratorAutoExportExportSensitiveDataSettingAsync();
yield return ShowGeneratorAutoExportEnabledSettingAsync();
yield return ShowGeneratorGodotDestinationPathSettingAsync();
yield return ShowGeneratorGodotEnabledSettingAsync();
yield return ShowGeneratorDotnetDefaultCultureSettingAsync();
yield return ShowGeneratorDotnetNamespaceSettingAsync();
yield return ShowGeneratorDotnetDestinationPathSettingAsync();
yield return ShowGeneratorDotnetEnabledSettingAsync();
yield return ShowGeneratorModeSettingAsync();
yield return ShowDeepLSourceCultureSettingAsync();
foreach (var setting in ShowCultureSettingsAsync())
yield return setting;
yield return ShowDeepLUsageSettingAsync();
yield return ShowDeepLActionSettingAsync();
yield return ShowDeepLAPIKeySettingAsync();
yield return ShowDeepLModeSettingAsync();
}
}