Files
rssotto-csharp-client/ModVersionChecker/forms/AppDetailsForm.cs
2025-09-04 10:14:30 +02:00

477 lines
19 KiB
C#

using Microsoft.VisualBasic.FileIO;
using ModVersionChecker.data.model;
using ModVersionChecker.managers.interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
namespace ModVersionChecker.forms
{
public class AppDetailsForm : Form
{
private readonly IConfigManager _configManager;
private readonly IAppsManager _appsManager;
private readonly ISourcesDefManager _sourcesDefManager;
private readonly ICheckerTypesDefManager _checkerTypesDefManager;
private readonly IFlightSimsManager _flightSimsManager;
private readonly GlobalConfig _globalConfig;
private int _currentRow;
//private string? _appId;
private bool _isEditable;
//private List<AppConfig> _apps;
private List<SourceDef> _sourcesDef;
private List<CheckerTypeDef> _checkerTypesDef;
private TextBox _nameField, _downloadUrlField;
private Label _nameLabel, _msfsVersionsLabel, _sourceLabel, _paramsSubtitle, _downloadUrlLabel;
private ComboBox _sourceField;
private Button _saveButton, _closeButton;
private TableLayoutPanel _mainLayout, _paramsPanel, _fsFieldsPanel;
private FlowLayoutPanel _buttonsPanel, _fsPanel;
private readonly Dictionary<string, TextBox> _paramFields = new Dictionary<string, TextBox>();
private readonly Dictionary<string, Dictionary<string, TextBox>> _fsFields = new Dictionary<string, Dictionary<string, TextBox>>();
private List<string> _selectedFs = new List<string>();
private List<CheckBox> _fsCheckBoxes = new List<CheckBox>();
private AppConfig? _currentApp;
private List<FsModPathConfig> _flightSims;
public event EventHandler<string> OnAppChanged;
public AppDetailsForm(
IConfigManager configManager,
IAppsManager appsManager,
ISourcesDefManager sourcesDefManager,
ICheckerTypesDefManager checkerTypesDefManager,
IFlightSimsManager flightSimsManager
)
{
_configManager = configManager ?? throw new ArgumentNullException(nameof(configManager));
_appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager));
_sourcesDefManager = sourcesDefManager ?? throw new ArgumentNullException(nameof(sourcesDefManager));
_checkerTypesDefManager = checkerTypesDefManager ?? throw new ArgumentNullException(nameof(checkerTypesDefManager));
_flightSimsManager = flightSimsManager ?? throw new ArgumentNullException(nameof(flightSimsManager));
_flightSims = _flightSimsManager.Load() ?? new List<FsModPathConfig>();
_globalConfig = _configManager.Load() ?? new GlobalConfig();
_sourcesDef = _sourcesDefManager.List() ?? new List<SourceDef>();
_checkerTypesDef = _checkerTypesDefManager.Load() ?? new List<CheckerTypeDef>();
_selectedFs = _flightSims.Select(sim => sim.ShortName).ToList();
_mainLayout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 14,
ColumnStyles = { new ColumnStyle(SizeType.Absolute, 150), new ColumnStyle(SizeType.Percent, 100) }
};
// App Name
_nameLabel = new Label { Text = "Name:" };
_nameField = new TextBox { Text = "", Enabled = _isEditable, Width = 300 };
// FS Versions
_msfsVersionsLabel = new Label { Text = "FS:" };
_fsPanel = new FlowLayoutPanel
{
FlowDirection = FlowDirection.LeftToRight,
AutoSize = true,
Dock = DockStyle.Fill
};
//_msfs2020CheckBox = new CheckBox { Text = "MSFS 2020", Enabled = _isEditable };
//_msfs2024CheckBox = new CheckBox { Text = "MSFS 2024", Enabled = _isEditable };
// Source
_sourceLabel = new Label { Text = "Source:" };
_sourceField = new ComboBox { Enabled = _isEditable, Width = 300, DropDownStyle = ComboBoxStyle.DropDownList };
_sourceField.Items.AddRange(_sourcesDef.Select(sd => sd.Id).ToArray());
_sourceField.SelectedIndexChanged += OnSourceFieldIndexChanged;
// Parameters
_paramsSubtitle = new Label { Text = "SourceParameters:", Font = new System.Drawing.Font(Font, System.Drawing.FontStyle.Bold) };
_paramsPanel = new TableLayoutPanel
{
AutoSize = true,
BackColor = Color.White,
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 2,
ColumnStyles = { new ColumnStyle(SizeType.Absolute, 150), new ColumnStyle(SizeType.Percent, 100) }
};
// Fs Fields Panel
_fsFieldsPanel = new TableLayoutPanel
{
AutoSize = true,
BackColor = Color.White,
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 2,
ColumnStyles = { new ColumnStyle(SizeType.Absolute, 150), new ColumnStyle(SizeType.Percent, 100) }
};
// App Name
_downloadUrlLabel = new Label { Text = "Download Url:" };
_downloadUrlField = new TextBox { Text = "", Enabled = _isEditable, Width = 300 };
_buttonsPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.RightToLeft, AutoSize = true, Dock = DockStyle.Fill };
_saveButton = new Button { Text = "Save", Width = 100 };
_closeButton = new Button { Text = "Close", Width = 100 };
_saveButton.Click += OnSaveButtonClicked;
_closeButton.Click += (s, e) => Close();
Controls.Add(_mainLayout);
Size = new System.Drawing.Size(500, 500);
StartPosition = FormStartPosition.CenterParent;
InitializeForm();
}
public void SetApp(AppConfig? app, bool update = true)
{
_currentApp = app;
_selectedFs = _currentApp?.MsfsVersions ?? new List<string>();
if (update)
{
UpdateForm();
}
}
public void SetEditable(bool isEditable, bool update = true)
{
_isEditable = isEditable;
if (update)
{
UpdateForm();
}
}
public void UpdateForm()
{
Text = _currentApp == null ? "Add App" : (_isEditable ? "Edit App" : "App Details");
_nameField.Text = _currentApp != null ? _currentApp.Name : "";
_downloadUrlField.Enabled = _nameField.Enabled = _sourceField.Enabled = _isEditable;
_downloadUrlField.Text = _currentApp != null ? _currentApp.DownloadUrl : "";
_flightSims.ForEach(fs =>
{
if (_currentApp != null && _currentApp.MsfsVersions.Contains(fs.ShortName))
{
if (!_selectedFs.Contains(fs.ShortName))
{
_selectedFs.Add(fs.ShortName);
}
}
});
for (int i = 0; i < _fsCheckBoxes.Count; i++)
{
var fsKey = _flightSims.FirstOrDefault(f => f.ShortName == _fsCheckBoxes[i].Text)?.ShortName;
if (fsKey != null)
{
_fsCheckBoxes[i].Checked = _currentApp != null && _currentApp.MsfsVersions.Contains(fsKey);
}
}
_sourceField.SelectedIndex = _sourceField.Items.IndexOf(_currentApp != null ? _currentApp.Source : "");
UpdateFsFields();
UpdateParamFields();
}
private bool isFsSelected(FsModPathConfig fs)
{
return _selectedFs.Contains(fs.ShortName);
}
private void UpdateFsFields()
{
_fsFields.Clear();
_fsFieldsPanel.Controls.Clear();
foreach (var fs in _flightSims)
{
if (fs == null || !isFsSelected(fs))
{
continue;
}
var fsKey = fs.ShortName;
var fieldsDict = new Dictionary<string, TextBox>();
_fsFields[fsKey] = fieldsDict;
int currentRow = 0;
Label horizontalSeparator = new Label
{
Height = 50,
Padding = new Padding(10, 0, 0, 0),
BackColor = Color.GhostWhite, // Line-like separator
Dock = DockStyle.Fill,
TextAlign = ContentAlignment.MiddleLeft,
Text = fsKey, // Optional: Add text to the separator
ForeColor = Color.FromArgb(50, 50, 50) // Text color contrasts with background
};
_fsFieldsPanel.Controls.Add(horizontalSeparator, 0, currentRow);
_fsFieldsPanel.SetColumnSpan(horizontalSeparator, 2);
currentRow++;
foreach (var field in fs.Fields)
{
Control control;
var value = GetFsFieldValue(fsKey, field.Name);
var label = new Label { Text = $"{field.Label} ({(field.Required ? "Required" : "Optional")}):", Width = 100, AutoSize = true };
var textBox = new TextBox
{
Width = 300,
Enabled = _isEditable,
Text = value
};
switch (field.Control.ToLower())
{
case "directory":
textBox.ReadOnly = true;
control = new TableLayoutPanel
{
AutoSize = true,
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 1,
ColumnStyles = { new ColumnStyle(SizeType.Percent, 80), new ColumnStyle(SizeType.Percent, 20) }
};
(control as TableLayoutPanel).Controls.Add(textBox, 0, 0);
var browseButton = new Button { Text = "Browse", Width = 80, Enabled = _isEditable };
browseButton.Click += (s, e) =>
{
using (var folderDialog = new FolderBrowserDialog())
{
folderDialog.Description = $"Select directory for {field.Label}";
folderDialog.SelectedPath = textBox.Text == "" ? Path.Combine(fs.Path) : textBox.Text;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
string selectedDirectory = folderDialog.SelectedPath;
string folderName = Path.GetFileName(selectedDirectory);
textBox.Text = folderName;
}
}
};
(control as TableLayoutPanel).Controls.Add(browseButton, 1, 0);
break;
default:
control = textBox;
break;
}
fieldsDict[field.Name] = textBox;
_fsFieldsPanel.Controls.Add(label, 0, currentRow);
_fsFieldsPanel.Controls.Add(control, 1, currentRow);
currentRow++;
}
}
}
private string GetFsFieldValue(string fsKey, string fieldName)
{
if (_currentApp == null) return "";
var fsFields = _currentApp.FsFields.ContainsKey(fsKey) ? _currentApp.FsFields[fsKey] : new Dictionary<string, string>();
if (fsFields.ContainsKey(fieldName))
{
return fsFields[fieldName];
}
return "";
}
private void UpdateParamFields()
{
if (_sourceField?.SelectedItem == null) return;
var selectedSource = _sourcesDef.FirstOrDefault(sd => sd.Id == _sourceField.SelectedItem.ToString());
if (selectedSource == null) return;
var checkerType = _checkerTypesDef.FirstOrDefault(ct => ct.Name == selectedSource.Type);
if (checkerType == null) return;
_paramFields.Clear();
_paramsPanel.Controls.Clear();
int currentRow = 0;
foreach (var paramDef in checkerType.Params)
{
var label = new Label { Text = $"{paramDef.Label} ({(paramDef.Required ? "Required" : "Optional")}):", Width = 100, AutoSize = true };
var textBox = new TextBox
{
Width = 300,
Enabled = _isEditable,
Text = GetParamValue(paramDef.Name, selectedSource)
};
_paramFields[paramDef.Name] = textBox;
_paramsPanel.Controls.Add(label, 0, currentRow);
_paramsPanel.Controls.Add(textBox, 1, currentRow);
currentRow++;
}
}
private string GetParamValue(string paramName, SourceDef source)
{
var valueFromSource = source.Defaults != null && source.Defaults.ContainsKey(paramName) ? source.Defaults[paramName] : "";
if (_currentApp == null || _currentApp.Params == null || !_currentApp.Params.ContainsKey(paramName))
return valueFromSource;
return _currentApp.Params[paramName];
}
private void InitializeForm()
{
_currentRow = 0;
_mainLayout.Controls.Add(_nameLabel, 0, _currentRow);
_mainLayout.Controls.Add(_nameField, 1, _currentRow++);
_mainLayout.Controls.Add(_msfsVersionsLabel, 0, _currentRow++);
_mainLayout.Controls.Add(_fsPanel, 1, _currentRow);
_mainLayout.SetColumnSpan(_fsPanel, 2);
_currentRow++;
_mainLayout.Controls.Add(_fsFieldsPanel, 0, _currentRow);
_mainLayout.SetColumnSpan(_fsFieldsPanel, 2);
_currentRow++;
_mainLayout.Controls.Add(_sourceLabel, 0, _currentRow);
_mainLayout.Controls.Add(_sourceField, 1, _currentRow++);
_mainLayout.Controls.Add(_paramsSubtitle, 0, _currentRow);
_mainLayout.SetColumnSpan(_paramsSubtitle, 2);
_currentRow++;
_mainLayout.Controls.Add(_paramsPanel, 0, _currentRow);
_mainLayout.SetColumnSpan(_paramsPanel, 2);
_currentRow++;
_mainLayout.Controls.Add(_downloadUrlLabel, 0, _currentRow);
_mainLayout.Controls.Add(_downloadUrlField, 1, _currentRow++);
_currentRow++;
_mainLayout.Controls.Add(_buttonsPanel, 0, _currentRow++);
AddFsCheckboxes();
AddButtons();
// UpdateForm();
}
private void AddFsCheckboxes()
{
foreach (var fs in _flightSims)
{
var checkBox = new CheckBox
{
Text = fs.ShortName,
Checked = _currentApp != null && _currentApp.MsfsVersions.Contains(fs.ShortName),
};
checkBox.CheckedChanged += (s, e) =>
{
if (checkBox.Checked)
{
if (!_selectedFs.Contains(fs.ShortName))
{
_selectedFs.Add(fs.ShortName);
}
}
else
{
_selectedFs.Remove(fs.ShortName);
}
UpdateFsFields();
};
_fsPanel.Controls.Add(checkBox);
_fsCheckBoxes.Add(checkBox);
}
}
private void OnSourceFieldIndexChanged(object? sender, EventArgs e)
{
if (_isEditable && _sourceField.SelectedItem != null)
{
UpdateParamFields();
}
}
private void AddButtons()
{
_buttonsPanel.Controls.Clear();
_buttonsPanel.Controls.Add(_saveButton);
_buttonsPanel.Controls.Add(_closeButton);
}
private void OnSaveButtonClicked(object? sender, EventArgs e)
{
try {
var paramsDict = _paramFields.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Text.Trim());
var fsFieldsDict = _fsFields.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.ToDictionary(fkvp => fkvp.Key, fkvp => fkvp.Value.Text.Trim())
);
var requiredParams = _checkerTypesDef
.First(ct => ct.Name == _sourcesDef.FirstOrDefault(sd => sd.Id == _sourceField.SelectedItem?.ToString())?.Type)
.Params.Where(p => p.Required)
.Select(p => p.Name);
if (requiredParams.Any(rp => string.IsNullOrWhiteSpace(paramsDict[rp])))
{
throw new Exception("All required parameters must be filled.");
}
var msfsVersions = _selectedFs;
var isNewApp = (_currentApp == null || string.IsNullOrEmpty(_currentApp.Id));
var app = new AppConfig
{
Id = isNewApp ? GetUuid() : _currentApp.Id,
Name = _nameField.Text.Trim(),
MsfsVersions = msfsVersions,
Source = _sourceField.SelectedItem?.ToString() ?? "",
Params = paramsDict,
FsFields = fsFieldsDict,
DownloadUrl = _downloadUrlField.Text.Trim(),
CurrentVersion = _currentApp?.CurrentVersion ?? "",
LatestVersion = _currentApp?.LatestVersion ?? "",
Status = _currentApp?.Status ?? AppStatus.None
};
if (isNewApp)
{
_appsManager.Insert(app);
} else
{
_appsManager.Update(app);
}
_currentApp = app;
OnAppChanged?.Invoke(this, "App saved");
Close();
}
catch (Exception ex)
{
MessageBox.Show($"Error: {ex.Message}", "Invalid Input", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private string GetUuid()
{
Guid uuid = Guid.NewGuid();
return uuid.ToString();
}
}
}