phase 1
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ModVersionChecker.forms;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using ModVersionChecker.managers.filesystem;
|
using ModVersionChecker.managers.filesystem;
|
||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
using ModVersionChecker.managers.litedb;
|
using ModVersionChecker.managers.litedb;
|
||||||
|
using ModVersionChecker.service;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
|
using ModVersionChecker.ui.forms;
|
||||||
|
|
||||||
namespace ModVersionChecker
|
namespace ModVersionChecker
|
||||||
{
|
{
|
||||||
@@ -18,13 +20,15 @@ namespace ModVersionChecker
|
|||||||
builder.ConfigureServices(services =>
|
builder.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
services.AddSingleton<IConfigManager, ConfigLiteDb>();
|
services.AddSingleton<IConfigManager, ConfigLiteDb>();
|
||||||
services.AddSingleton<IAppsManager, AppConfigLiteDb>();
|
services.AddSingleton<IAppsManager, AppLiteDb>();
|
||||||
services.AddSingleton<ISourcesDefManager, SourcesLiteDb>();
|
services.AddSingleton<ISourcesDefManager, SourcesLiteDb>();
|
||||||
services.AddSingleton<ICheckerTypesDefManager, CheckerTypesDefManager>();
|
services.AddSingleton<IFlightSimsManager, TypeLiteDb>();
|
||||||
services.AddSingleton<IFlightSimsManager, FlightSimsLiteDb>();
|
services.AddSingleton<ITypeManager, TypeConfigLiteDb>();
|
||||||
services.AddSingleton<IFormFactory, FormFactory>();
|
services.AddSingleton<IFormFactory, FormFactory>();
|
||||||
services.AddSingleton<IAppStatusManager, AppStatusManager>();
|
services.AddSingleton<IAppStatusManager, AppStatusManager>();
|
||||||
services.AddSingleton<INotifyIconService, NotifyIconService>();
|
services.AddSingleton<INotifyIconService, NotifyIconService>();
|
||||||
|
services.AddSingleton<IApiService, ApiService>();
|
||||||
|
services.AddSingleton<IVersionService, VersionService>();
|
||||||
|
|
||||||
services.AddTransient<MainForm>();
|
services.AddTransient<MainForm>();
|
||||||
services.AddTransient<AppDetailsForm>();
|
services.AddTransient<AppDetailsForm>();
|
||||||
@@ -55,9 +59,9 @@ namespace ModVersionChecker
|
|||||||
|
|
||||||
var serviceProvider = host.Services;
|
var serviceProvider = host.Services;
|
||||||
var configForm = serviceProvider.GetService<MainForm>();
|
var configForm = serviceProvider.GetService<MainForm>();
|
||||||
var versionChecker = serviceProvider.GetService<VersionChecker>();
|
|
||||||
var notifyIconService = serviceProvider.GetRequiredService<INotifyIconService>();
|
var notifyIconService = serviceProvider.GetRequiredService<INotifyIconService>();
|
||||||
var configManager = serviceProvider.GetRequiredService<IConfigManager>();
|
var configManager = serviceProvider.GetRequiredService<IConfigManager>();
|
||||||
|
var versionService = serviceProvider.GetRequiredService<IVersionService>();
|
||||||
var config = configManager.GetConfig();
|
var config = configManager.GetConfig();
|
||||||
|
|
||||||
EventHandler openFormHandler = (s, e) =>
|
EventHandler openFormHandler = (s, e) =>
|
||||||
@@ -94,38 +98,18 @@ namespace ModVersionChecker
|
|||||||
notifyIcon.DoubleClick += openFormHandler;
|
notifyIcon.DoubleClick += openFormHandler;
|
||||||
|
|
||||||
bool checkOnInitialStart = config.CheckOnStartup;
|
bool checkOnInitialStart = config.CheckOnStartup;
|
||||||
if (checkOnInitialStart && versionChecker != null)
|
if (checkOnInitialStart)
|
||||||
{
|
{
|
||||||
versionChecker.StartVersionChecking(notifyIcon);
|
|
||||||
versionChecker.OnFinished += (s, e) => {
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await versionService.CheckAllApps();
|
||||||
if (configForm != null)
|
if (configForm != null)
|
||||||
{
|
|
||||||
if (configForm.InvokeRequired)
|
|
||||||
{
|
|
||||||
configForm.Invoke(() => configForm.UpdateListView());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
configForm.UpdateListView();
|
configForm.UpdateListView();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (versionChecker != null)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (configForm != null)
|
|
||||||
{
|
|
||||||
configForm.OnRecheck += (s, e) =>
|
|
||||||
{
|
|
||||||
if (versionChecker != null)
|
|
||||||
{
|
|
||||||
versionChecker.CheckAsync();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CredentialManagement" Version="1.0.2" />
|
||||||
<PackageReference Include="HtmlAgilityPack.CssSelectors" Version="1.0.2" />
|
<PackageReference Include="HtmlAgilityPack.CssSelectors" Version="1.0.2" />
|
||||||
<PackageReference Include="LiteDB" Version="5.0.21" />
|
<PackageReference Include="LiteDB" Version="5.0.21" />
|
||||||
<PackageReference Include="LiteDB.Async" Version="0.1.8" />
|
<PackageReference Include="LiteDB.Async" Version="0.1.8" />
|
||||||
@@ -20,23 +21,12 @@
|
|||||||
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="139.0.7258.6800" />
|
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="139.0.7258.6800" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
<PackageReference Include="System.Text.Json" Version="9.0.8" />
|
<PackageReference Include="System.Text.Json" Version="9.0.8" />
|
||||||
|
<PackageReference Include="YamlDotNet" Version="16.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="data\apps - Copy.json">
|
<None Update="config.yaml">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
|
||||||
<None Update="data\apps.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="data\checkerTypesDef.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="data\config.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Update="data\sourcesDef.json">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
</None>
|
||||||
<None Update="Resources\error-icon.ico">
|
<None Update="Resources\error-icon.ico">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@@ -52,8 +42,4 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="database\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@@ -1,7 +1,6 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.model;
|
||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.managers.interfaces;
|
||||||
using ModVersionChecker.utils;
|
using ModVersionChecker.service.interfaces;
|
||||||
using NuGet.Versioning;
|
|
||||||
|
|
||||||
|
|
||||||
namespace ModVersionChecker
|
namespace ModVersionChecker
|
||||||
@@ -9,46 +8,33 @@ namespace ModVersionChecker
|
|||||||
public class VersionChecker
|
public class VersionChecker
|
||||||
{
|
{
|
||||||
private readonly IConfigManager _configManager;
|
private readonly IConfigManager _configManager;
|
||||||
private readonly IAppsManager _appsManager;
|
private readonly IVersionService _versionService;
|
||||||
private readonly ISourcesDefManager _sourcesDefManager;
|
|
||||||
private readonly INotifyIconService _notifyIconService;
|
|
||||||
private readonly IFlightSimsManager _fsManager;
|
|
||||||
private List<string> errorMessages = new List<string>();
|
|
||||||
private List<string> updateMessages = new List<string>();
|
|
||||||
private NotifyIcon? _notifyIcon;
|
|
||||||
|
|
||||||
public event EventHandler<string>? OnFinished;
|
public event EventHandler<string>? OnFinished;
|
||||||
|
|
||||||
public VersionChecker(
|
public VersionChecker(
|
||||||
IConfigManager configManager,
|
IVersionService versionService,
|
||||||
IAppsManager appsManager,
|
IConfigManager configManager)
|
||||||
ISourcesDefManager sourcesDefManager,
|
|
||||||
INotifyIconService notifyIconService,
|
|
||||||
IFlightSimsManager fsManager)
|
|
||||||
{
|
{
|
||||||
_configManager = configManager ?? throw new ArgumentNullException(nameof(configManager));
|
_configManager = configManager ?? throw new ArgumentNullException(nameof(configManager));
|
||||||
_appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager));
|
_versionService = versionService ?? throw new ArgumentNullException(nameof(versionService));
|
||||||
_sourcesDefManager = sourcesDefManager ?? throw new ArgumentNullException(nameof(sourcesDefManager));
|
|
||||||
_notifyIconService = notifyIconService ?? throw new ArgumentNullException(nameof(notifyIconService));
|
|
||||||
_fsManager = fsManager ?? throw new ArgumentNullException(nameof(fsManager));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleAppError(string message, AppConfig app)
|
//private void HandleAppError(string message, AppConfig app)
|
||||||
{
|
//{
|
||||||
errorMessages.Add(message);
|
// errorMessages.Add(message);
|
||||||
_appsManager.UpdateStatus(app, AppStatus.Error);
|
// _appsManager.UpdateStatus(app, AppStatus.ERROR);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public void StartVersionChecking(NotifyIcon notifyIcon)
|
public void StartVersionChecking()
|
||||||
{
|
{
|
||||||
var config = _configManager.Load() ?? new GlobalConfig();
|
var config = _configManager.Load() ?? new Config();
|
||||||
_notifyIcon = notifyIcon ?? throw new ArgumentNullException(nameof(notifyIcon));
|
|
||||||
// Run version checks in a background thread
|
// Run version checks in a background thread
|
||||||
new Thread(async () =>
|
new Thread(async () =>
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
await CheckAsync();
|
await _versionService.CheckAllApps();
|
||||||
|
|
||||||
Thread.Sleep(config.IntervalMinutes * 60 * 1000);
|
Thread.Sleep(config.IntervalMinutes * 60 * 1000);
|
||||||
}
|
}
|
||||||
@@ -57,86 +43,94 @@ namespace ModVersionChecker
|
|||||||
{ IsBackground = true }.Start();
|
{ IsBackground = true }.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CheckAsync()
|
|
||||||
{
|
|
||||||
var config = _configManager.Load() ?? new GlobalConfig();
|
|
||||||
var apps = _appsManager.Load() ?? new List<AppConfig>();
|
|
||||||
var sources = _sourcesDefManager.List() ?? new List<SourceDef>();
|
|
||||||
var fsMods = _fsManager.Load() ?? new List<FsModPathConfig>();
|
|
||||||
|
|
||||||
updateMessages = new List<string>();
|
|
||||||
errorMessages = new List<string>();
|
|
||||||
|
|
||||||
foreach (AppConfig app in apps)
|
|
||||||
{
|
|
||||||
if (app.Status != AppStatus.Error && app.LastCheckedAt != 0 && app.LastCheckedAt < TimeUtils.GetUnixTimeMillis(DateTime.Now.AddMinutes(-60)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var status = AppStatus.None;
|
|
||||||
var sourceId = app.Source;
|
|
||||||
if (string.IsNullOrWhiteSpace(sourceId))
|
|
||||||
{
|
|
||||||
HandleAppError($"{app.Name} has no source configured.", app);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var source = sources.FirstOrDefault(s => s.Id == sourceId);
|
|
||||||
if (source == null)
|
|
||||||
{
|
|
||||||
HandleAppError($"{app.Name} has an invalid source: {sourceId}", app);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (var fsVersion in app.MsfsVersions)
|
|
||||||
{
|
|
||||||
var fsConfig = _fsManager.GetByShortName(fsVersion);
|
|
||||||
if (fsConfig == null)
|
|
||||||
{
|
|
||||||
HandleAppError($"{app.Name} has no FS mod path configured for version {fsVersion}.", app);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var checker = CheckerFactory.CreateChecker(source.Type);
|
|
||||||
var current = NuGetVersion.Parse(VersionUtils.GetCurrentVersion(app, fsConfig));
|
|
||||||
var latest = NuGetVersion.Parse(await checker.GetLatestVersion(app.Params, source));
|
|
||||||
|
|
||||||
app.CurrentVersion = current.ToString();
|
|
||||||
app.LatestVersion = latest.ToString();
|
|
||||||
|
|
||||||
if (latest.CompareTo(current) == 1)
|
|
||||||
{
|
|
||||||
updateMessages.Add($"{app.Name}: New version {latest} (current: {current})");
|
|
||||||
status = AppStatus.UpdateAvailable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_appsManager.UpdateStatus(app, status);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
//public async Task CheckAsync()
|
||||||
catch (Exception ex)
|
//{
|
||||||
{
|
// var config = _configManager.Load() ?? new GlobalConfig();
|
||||||
HandleAppError($"Failed for {app.Name}: {ex.Message}", app);
|
// var apps = _appsManager.Load() ?? new List<AppConfig>();
|
||||||
}
|
// var sources = _sourcesDefManager.List() ?? new List<SourceDef>();
|
||||||
}
|
// var fsMods = _fsManager.Load() ?? new List<TypeDef>();
|
||||||
|
// var types = _typeConfigManager.GetTypeConfigs() ?? new List<TypeConfig>();
|
||||||
|
|
||||||
if (updateMessages.Count > 0)
|
// var appVersionsMap = await _apiVersionService.GetAppVersionsAsync(apps);
|
||||||
{
|
|
||||||
_notifyIconService.ShowBalloonTip(
|
// updateMessages = new List<string>();
|
||||||
10000,
|
// errorMessages = new List<string>();
|
||||||
"Updates Available",
|
|
||||||
string.Join("\n", updateMessages),
|
// foreach (AppConfig app in apps)
|
||||||
ToolTipIcon.Info
|
// {
|
||||||
);
|
// if (app.Status != AppStatus.ERROR && app.LastCheckedAt != 0 && app.LastCheckedAt < TimeUtils.GetUnixTimeMillis(DateTime.Now.AddMinutes(-60)))
|
||||||
}
|
// continue;
|
||||||
if (errorMessages.Count > 0)
|
|
||||||
{
|
// var status = AppStatus.NONE;
|
||||||
_notifyIconService.ShowBalloonTip(
|
// var sourceId = app.Source;
|
||||||
10000,
|
|
||||||
"Errors",
|
// // Skip apps that are not in the API response
|
||||||
string.Join("\n", errorMessages),
|
|
||||||
ToolTipIcon.Error
|
// if (!appVersionsMap.Any(a => app.Id == a.Id)) {
|
||||||
);
|
// continue;
|
||||||
}
|
// }
|
||||||
OnFinished?.Invoke(this, "Version check completed.");
|
// var latesstVersion = appVersionsMap.FirstOrDefault(a => a.Id == app.Id).LatestVersion;
|
||||||
}
|
// if (string.IsNullOrWhiteSpace(sourceId))
|
||||||
|
// {
|
||||||
|
// HandleAppError($"{app.Name} has no source configured.", app);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// var source = sources.FirstOrDefault(s => s.Id == sourceId);
|
||||||
|
// if (source == null)
|
||||||
|
// {
|
||||||
|
// HandleAppError($"{app.Name} has an invalid source: {sourceId}", app);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// var type = app.Types[0];
|
||||||
|
// var typeConfig = types[0];
|
||||||
|
// if (typeConfig == null)
|
||||||
|
// {
|
||||||
|
// HandleAppError($"{app.Name} has no FS mod path configured for version {type}.", app);
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// var current = NuGetVersion.Parse(VersionUtils.GetCurrentVersion(app, typeConfig));
|
||||||
|
// var latest = NuGetVersion.Parse(latesstVersion);
|
||||||
|
|
||||||
|
// app.CurrentVersion = current.ToString();
|
||||||
|
// app.LatestVersion = latest.ToString();
|
||||||
|
|
||||||
|
// if (latest.CompareTo(current) == 1)
|
||||||
|
// {
|
||||||
|
// updateMessages.Add($"{app.Name}: New version {latest} (current: {current})");
|
||||||
|
// status = AppStatus.UPDATE_AVAILABLE;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _appsManager.UpdateStatus(app, status);
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// HandleAppError($"Failed for {app.Name}: {ex.Message}", app);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (updateMessages.Count > 0)
|
||||||
|
// {
|
||||||
|
// _notifyIconService.ShowBalloonTip(
|
||||||
|
// 10000,
|
||||||
|
// "Updates Available",
|
||||||
|
// string.Join("\n", updateMessages),
|
||||||
|
// ToolTipIcon.Info
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// if (errorMessages.Count > 0)
|
||||||
|
// {
|
||||||
|
// _notifyIconService.ShowBalloonTip(
|
||||||
|
// 10000,
|
||||||
|
// "Errors",
|
||||||
|
// string.Join("\n", errorMessages),
|
||||||
|
// ToolTipIcon.Error
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// OnFinished?.Invoke(this, "Version check completed.");
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using System;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker
|
|
||||||
{
|
|
||||||
public class ApiChecker : IVersionChecker
|
|
||||||
{
|
|
||||||
private static readonly HttpClient _httpClient = new HttpClient();
|
|
||||||
|
|
||||||
public async Task<string> GetLatestVersion(Dictionary<string, string> paramsDict, SourceDef source)
|
|
||||||
{
|
|
||||||
if (!paramsDict.TryGetValue("url", out var url) || string.IsNullOrEmpty(url))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("API URL required");
|
|
||||||
}
|
|
||||||
if (!paramsDict.TryGetValue("jsonPath", out var jsonPath) || string.IsNullOrEmpty(jsonPath))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("jsonPath required");
|
|
||||||
}
|
|
||||||
|
|
||||||
var response = await _httpClient.GetAsync(url);
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
throw new Exception($"API error: {(int)response.StatusCode} {response.ReasonPhrase}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var body = await response.Content.ReadAsStringAsync();
|
|
||||||
if (string.IsNullOrEmpty(body))
|
|
||||||
{
|
|
||||||
throw new Exception("Empty API response");
|
|
||||||
}
|
|
||||||
|
|
||||||
using var jsonDoc = JsonDocument.Parse(body);
|
|
||||||
var element = jsonDoc.RootElement;
|
|
||||||
|
|
||||||
foreach (var key in jsonPath.Split('.'))
|
|
||||||
{
|
|
||||||
if (!element.TryGetProperty(key, out var nextElement))
|
|
||||||
{
|
|
||||||
throw new Exception($"JSON key '{key}' not found in response");
|
|
||||||
}
|
|
||||||
element = nextElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.ValueKind != JsonValueKind.String)
|
|
||||||
{
|
|
||||||
throw new Exception($"JSON value for '{jsonPath}' is not a string");
|
|
||||||
}
|
|
||||||
|
|
||||||
return element.GetString()!.Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
namespace ModVersionChecker
|
|
||||||
{
|
|
||||||
public static class CheckerFactory
|
|
||||||
{
|
|
||||||
public static IVersionChecker CreateChecker(string type)
|
|
||||||
{
|
|
||||||
string[] parts = type.Split(':');
|
|
||||||
|
|
||||||
return parts[0].ToLower() switch
|
|
||||||
{
|
|
||||||
"scrape" => new ScrapeChecker(),
|
|
||||||
"api" => new ApiChecker(),
|
|
||||||
_ => throw new ArgumentException($"Unknown checker type: {type}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,94 +0,0 @@
|
|||||||
using System.Text.RegularExpressions;
|
|
||||||
using ModVersionChecker.data.model;
|
|
||||||
using OpenQA.Selenium;
|
|
||||||
using OpenQA.Selenium.Chrome;
|
|
||||||
|
|
||||||
namespace ModVersionChecker
|
|
||||||
{
|
|
||||||
public class ScrapeChecker : IVersionChecker
|
|
||||||
{
|
|
||||||
public async Task<string> GetLatestVersion(Dictionary<string, string> paramsDict, SourceDef source)
|
|
||||||
{
|
|
||||||
if (!paramsDict.TryGetValue("url", out var url) || string.IsNullOrEmpty(url))
|
|
||||||
{
|
|
||||||
throw new ArgumentException("URL required");
|
|
||||||
}
|
|
||||||
|
|
||||||
var mode = GetValueOrDefault(paramsDict, "mode", source);
|
|
||||||
var response = "";
|
|
||||||
if (mode == "selenium")
|
|
||||||
{
|
|
||||||
response = await SeleniumFetch(url);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response = await DefaultFetch(url); ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string pattern = @">\s+<";
|
|
||||||
response = Regex.Replace(response, pattern, "><");
|
|
||||||
var regex = GetValueOrDefault(paramsDict, "regex", source);
|
|
||||||
|
|
||||||
var match = System.Text.RegularExpressions.Regex.Match(response, regex);
|
|
||||||
if (!match.Success || match.Groups.Count < 2)
|
|
||||||
{
|
|
||||||
throw new Exception($"No match with regex in response");
|
|
||||||
}
|
|
||||||
return match.Groups[1].Value;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetValueOrDefault(Dictionary<string, string> dict, string key, SourceDef source)
|
|
||||||
{
|
|
||||||
var value = "";
|
|
||||||
if (dict.ContainsKey(key) && !string.IsNullOrEmpty(dict[key]))
|
|
||||||
{
|
|
||||||
value = dict[key];
|
|
||||||
}
|
|
||||||
else if (source.Defaults != null && source.Defaults.ContainsKey(key))
|
|
||||||
{
|
|
||||||
value = source.Defaults[key];
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<string> DefaultFetch(string url)
|
|
||||||
{
|
|
||||||
var httpClient = new HttpClient();
|
|
||||||
httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
|
|
||||||
httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
|
|
||||||
httpClient.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.5");
|
|
||||||
|
|
||||||
return httpClient.GetStringAsync(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> SeleniumFetch(string url)
|
|
||||||
{
|
|
||||||
var service = ChromeDriverService.CreateDefaultService();
|
|
||||||
service.HideCommandPromptWindow = true;
|
|
||||||
|
|
||||||
var options = new ChromeOptions();
|
|
||||||
options.AddArgument("--headless"); // Run in headless mode
|
|
||||||
options.AddArgument("--disable-gpu");
|
|
||||||
options.AddArgument("--no-sandbox");
|
|
||||||
options.AddArgument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/91.0.4472.124");
|
|
||||||
|
|
||||||
using var driver = new ChromeDriver(service, options);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
driver.Navigate().GoToUrl(url);
|
|
||||||
// Wait for the page to load
|
|
||||||
await Task.Delay(2000); // Adjust as necessary
|
|
||||||
// Example: Get the page source
|
|
||||||
var pageSource = driver.PageSource;
|
|
||||||
// Close the driver
|
|
||||||
return pageSource;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
driver.Quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
|
|
||||||
namespace ModVersionChecker
|
|
||||||
{
|
|
||||||
public interface IVersionChecker
|
|
||||||
{
|
|
||||||
Task<string> GetLatestVersion(Dictionary<string, string> paramsDict, SourceDef source);
|
|
||||||
}
|
|
||||||
}
|
|
3
ModVersionChecker/config.yaml
Normal file
3
ModVersionChecker/config.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
api:
|
||||||
|
base-url: http://192.168.1.115:3115/api
|
||||||
|
# base-url: http://localhost:8080/api
|
@@ -1,55 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "PMS50 GTN750",
|
|
||||||
"msfsVersions": [ "msfs2024" ],
|
|
||||||
"source": "pms50_gtn750",
|
|
||||||
"params": {
|
|
||||||
"url": "https://pms50.com/msfs/"
|
|
||||||
},
|
|
||||||
"currentVersionConfig": {
|
|
||||||
"package": "pms50-instrument-gtn750"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Teikof SKMZ",
|
|
||||||
"msfsVersions": [ "msfs2024" ],
|
|
||||||
"source": "sim_market",
|
|
||||||
"params": {
|
|
||||||
"url": "https://secure.simmarket.com/teikof-studio-skmz-la-nubia-airport-msfs.phtml"
|
|
||||||
},
|
|
||||||
"currentVersionConfig": {
|
|
||||||
"package": "teikofstudio-airport-skmz-manizales"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "SWS",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "sws",
|
|
||||||
"params": {
|
|
||||||
"url": "https://simworksstudios.com/product/kodiak-100-series-ii/",
|
|
||||||
"regex": "Current Version: (\\d\u002B\\.\\d\u002B\\.\\d\u002B)"
|
|
||||||
},
|
|
||||||
"currentVersionConfig": {
|
|
||||||
"package": "sws-aircraft-kodiak-wheels",
|
|
||||||
"version": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "GSX Pro",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "custom",
|
|
||||||
"params": {
|
|
||||||
"url": "https://www.fsdreamteam.com/couatl_liveupdate_notes.html",
|
|
||||||
"regex": "<p>Version (\\d\u002B\\.\\d\u002B\\.\\d\u002B) –"
|
|
||||||
},
|
|
||||||
"currentVersionConfig": {
|
|
||||||
"package": "fsdreamteam-gsx-pro",
|
|
||||||
"version": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
@@ -1,86 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": "8",
|
|
||||||
"name": "PMS50 GTN750",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "pms50_gtn750",
|
|
||||||
"params": {
|
|
||||||
"url": "https://pms50.com/msfs/",
|
|
||||||
"regex": "Current version: (\\d\u002B\\.\\d\u002B\\.\\d\u002B)"
|
|
||||||
},
|
|
||||||
"fsFields": {
|
|
||||||
"msfs2024": {
|
|
||||||
"package": "pms50-instrument-gtn750"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"name": "Teikof SKMZ",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "sim_market",
|
|
||||||
"params": {
|
|
||||||
"url": "https://secure.simmarket.com/teikof-studio-skmz-la-nubia-airport-msfs.phtml"
|
|
||||||
},
|
|
||||||
"fsFields": {
|
|
||||||
"msfs2024": {
|
|
||||||
"package": "teikofstudio-airport-skmz-manizales"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "3",
|
|
||||||
"name": "SWS",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "sws",
|
|
||||||
"params": {
|
|
||||||
"url": "https://simworksstudios.com/product/kodiak-100-series-ii/",
|
|
||||||
"regex": "Current Version: (\\d\u002B\\.\\d\u002B\\.\\d\u002B)"
|
|
||||||
},
|
|
||||||
"fsFields": {
|
|
||||||
"msfs2024": {
|
|
||||||
"package": "sws-aircraft-kodiak-wheels"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "4",
|
|
||||||
"name": "GSX Pro",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "custom",
|
|
||||||
"params": {
|
|
||||||
"url": "https://www.fsdreamteam.com/couatl_liveupdate_notes.html",
|
|
||||||
"regex": "\u003Cp\u003EVersion (\\d\u002B\\.\\d\u002B\\.\\d\u002B) \u2013"
|
|
||||||
},
|
|
||||||
"fsFields": {
|
|
||||||
"msfs2024": {
|
|
||||||
"package": "fsdreamteam-gsx-pro"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "5",
|
|
||||||
"name": "Aerostar 600",
|
|
||||||
"msfsVersions": [
|
|
||||||
"msfs2024"
|
|
||||||
],
|
|
||||||
"source": "a2a",
|
|
||||||
"params": {
|
|
||||||
"url": "https://a2asimulations.com/forum/viewforum.php?f=153",
|
|
||||||
"regex": "Accu-Sim Aerostar 600 \u2013 v(\\d\u002B\\.\\d\u002B\\.\\d\u002B)"
|
|
||||||
},
|
|
||||||
"fsFields": {
|
|
||||||
"msfs2024": {
|
|
||||||
"package": "a2a-aircraft-aerostar600"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
@@ -1,33 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "scrape",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"name": "url",
|
|
||||||
"label": "Url",
|
|
||||||
"type": "string",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Regex",
|
|
||||||
"name": "regex",
|
|
||||||
"type": "string"
|
|
||||||
}, {
|
|
||||||
"label": "Mode",
|
|
||||||
"name": "mode",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "api",
|
|
||||||
"params": [
|
|
||||||
{
|
|
||||||
"label": "Url",
|
|
||||||
"name": "url",
|
|
||||||
"type": "string",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"intervalMinutes": 60,
|
|
||||||
"checkOnStartup": false,
|
|
||||||
"fsModPaths": {
|
|
||||||
"msfs2024": {
|
|
||||||
"path": "I:/Microsoft Flight Simulator 2024/Packages/Community/",
|
|
||||||
"file": "manifest.json",
|
|
||||||
"fileType": "json",
|
|
||||||
"key": "package_version",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"name": "package",
|
|
||||||
"label": "Package Name",
|
|
||||||
"type": "string",
|
|
||||||
"control": "directory",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.data.model
|
|
||||||
{
|
|
||||||
public class CheckerTypeDef
|
|
||||||
{
|
|
||||||
[JsonPropertyName("name")]
|
|
||||||
public string Name { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("params")]
|
|
||||||
public List<FieldDef> Params { get; set; } = new List<FieldDef>();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.data.model
|
|
||||||
{
|
|
||||||
public class FsModPathConfig
|
|
||||||
{
|
|
||||||
|
|
||||||
public string Id { get; set; } = String.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("name")]
|
|
||||||
public string Name { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("shortName")]
|
|
||||||
public string ShortName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("path")]
|
|
||||||
public string Path { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("file")]
|
|
||||||
public string File { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("fileType")]
|
|
||||||
public string FileType { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("key")]
|
|
||||||
public string Key { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
[JsonPropertyName("fields")]
|
|
||||||
public List<FieldDef> Fields { get; set; } = new List<FieldDef>();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,47 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": "custom",
|
|
||||||
"name": "Custom Source",
|
|
||||||
"type": "scrape",
|
|
||||||
"defaults": {
|
|
||||||
"regex": "",
|
|
||||||
"url": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "sim_market",
|
|
||||||
"name": "Sim Market",
|
|
||||||
"type": "scrape",
|
|
||||||
"defaults": {
|
|
||||||
"regex": "<span class=\"details-card__item-text\">(\\d+\\.\\d+\\.\\d+)<\\/span>",
|
|
||||||
"url": "https://secure.simmarket.com/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "pms50_gtn750",
|
|
||||||
"name": "PMS50 GTN750",
|
|
||||||
"type": "scrape",
|
|
||||||
"defaults": {
|
|
||||||
"url": "https://pms50.com/msfs/",
|
|
||||||
"regex": "Current version: (\\d+\\.\\d+\\.\\d+)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "sws",
|
|
||||||
"name": "SWS",
|
|
||||||
"type": "scrape",
|
|
||||||
"defaults": {
|
|
||||||
"url": "https://simworksstudios.com/product",
|
|
||||||
"regex": "Current Version: (\\d+\\.\\d+\\.\\d+)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "a2a",
|
|
||||||
"name": "A2A",
|
|
||||||
"type": "scrape",
|
|
||||||
"defaults": {
|
|
||||||
"url": "https://a2asimulations.com/forum/viewtopic.php?f=153",
|
|
||||||
"mode": "selenium"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
@@ -4,12 +4,12 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ModVersionChecker.data.model
|
namespace ModVersionChecker.enums
|
||||||
{
|
{
|
||||||
public enum AppStatus
|
public enum AppStatus
|
||||||
{
|
{
|
||||||
None,
|
NONE,
|
||||||
UpdateAvailable,
|
UPDATE_AVAILABLE,
|
||||||
Error,
|
ERROR,
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,477 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,68 +0,0 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.forms
|
|
||||||
{
|
|
||||||
public class FormFactory : IFormFactory
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
|
|
||||||
public FormFactory(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
|
||||||
}
|
|
||||||
|
|
||||||
public AppDetailsForm CreateAppDetailsForm(AppConfig? app, bool isEditable, EventHandler<string>? onAppChanged)
|
|
||||||
{
|
|
||||||
var configManager = _serviceProvider.GetRequiredService<IConfigManager>();
|
|
||||||
var appsManager = _serviceProvider.GetRequiredService<IAppsManager>();
|
|
||||||
var sourcesDefManager = _serviceProvider.GetRequiredService<ISourcesDefManager>();
|
|
||||||
var checkerTypesDefManager = _serviceProvider.GetRequiredService<ICheckerTypesDefManager>();
|
|
||||||
var flightSimsManager = _serviceProvider.GetRequiredService<IFlightSimsManager>();
|
|
||||||
var form = new AppDetailsForm(configManager, appsManager, sourcesDefManager, checkerTypesDefManager, flightSimsManager);
|
|
||||||
form.SetApp(app, false);
|
|
||||||
form.SetEditable(isEditable);
|
|
||||||
if (onAppChanged != null)
|
|
||||||
{
|
|
||||||
form.OnAppChanged += onAppChanged;
|
|
||||||
}
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlobalConfigForm CreateGlobalConfigForm()
|
|
||||||
{
|
|
||||||
var configManager = _serviceProvider.GetRequiredService<IConfigManager>();
|
|
||||||
var form = new GlobalConfigForm(configManager);
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SourcesConfigForm CreateSourcesConfigForm(EventHandler<string>? onSourcesChanged)
|
|
||||||
{
|
|
||||||
var sourcesDefManager = _serviceProvider.GetRequiredService<ISourcesDefManager>();
|
|
||||||
var formFactory = _serviceProvider.GetRequiredService<IFormFactory>();
|
|
||||||
var form = new SourcesConfigForm(formFactory, sourcesDefManager);
|
|
||||||
if (onSourcesChanged != null)
|
|
||||||
{
|
|
||||||
form.OnSourcesChanged += onSourcesChanged;
|
|
||||||
}
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SourceDetailForm CreateSourceDetailForm(SourceDef? sourceDef, EventHandler<string>? onSourceChanged)
|
|
||||||
{
|
|
||||||
var sourcesDefManager = _serviceProvider.GetRequiredService<ISourcesDefManager>();
|
|
||||||
var checkerTypesDefManager = _serviceProvider.GetRequiredService<ICheckerTypesDefManager>();
|
|
||||||
var formFactory = _serviceProvider.GetRequiredService<IFormFactory>();
|
|
||||||
var form = new SourceDetailForm(formFactory, sourcesDefManager);
|
|
||||||
form.SourceDef = sourceDef;
|
|
||||||
|
|
||||||
if (onSourceChanged != null)
|
|
||||||
{
|
|
||||||
form.UpdateFields();
|
|
||||||
form.OnSourceChanged += onSourceChanged;
|
|
||||||
}
|
|
||||||
return form;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,14 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.forms
|
|
||||||
{
|
|
||||||
public interface IFormFactory
|
|
||||||
{
|
|
||||||
AppDetailsForm CreateAppDetailsForm(AppConfig? app, bool isEditable, EventHandler<string>? onAppChanged);
|
|
||||||
GlobalConfigForm CreateGlobalConfigForm();
|
|
||||||
|
|
||||||
SourcesConfigForm CreateSourcesConfigForm(EventHandler<string>? onSourcesChanged);
|
|
||||||
|
|
||||||
SourceDetailForm CreateSourceDetailForm(SourceDef? sourceDef, EventHandler<string>? onSourceChanged);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,110 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.forms
|
|
||||||
{
|
|
||||||
// Simple editor form for SourceDef
|
|
||||||
public class SourceDetailForm : Form
|
|
||||||
{
|
|
||||||
private readonly IFormFactory _formFactory;
|
|
||||||
private readonly ISourcesDefManager _sourceManager;
|
|
||||||
public SourceDef SourceDef { get; set; }
|
|
||||||
public Boolean IsEditable => !string.IsNullOrWhiteSpace(SourceDef?.Id);
|
|
||||||
private TextBox _idField, _nameField, _typeField, _defaultsField;
|
|
||||||
private Button _okButton, _cancelButton;
|
|
||||||
|
|
||||||
public event EventHandler<string>? OnSourceChanged;
|
|
||||||
|
|
||||||
public SourceDetailForm(IFormFactory formFactory, ISourcesDefManager sourceManager)
|
|
||||||
{
|
|
||||||
_formFactory = formFactory ?? throw new ArgumentNullException(nameof(formFactory));
|
|
||||||
_sourceManager = sourceManager ?? throw new ArgumentNullException(nameof(sourceManager));
|
|
||||||
|
|
||||||
InitializeComponent();
|
|
||||||
_formFactory = formFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
Text = "Edit SourceDef";
|
|
||||||
Size = new Size(400, 300);
|
|
||||||
StartPosition = FormStartPosition.CenterParent;
|
|
||||||
Padding = new Padding(10);
|
|
||||||
|
|
||||||
var layout = new TableLayoutPanel
|
|
||||||
{
|
|
||||||
Dock = DockStyle.Fill,
|
|
||||||
RowCount = 5,
|
|
||||||
ColumnCount = 2,
|
|
||||||
Padding = new Padding(10)
|
|
||||||
};
|
|
||||||
|
|
||||||
layout.Controls.Add(new Label { Text = "Id:", Width = 80 }, 0, 0);
|
|
||||||
_idField = new TextBox { Text = "", Width = 200 };
|
|
||||||
layout.Controls.Add(_idField, 1, 0);
|
|
||||||
|
|
||||||
layout.Controls.Add(new Label { Text = "Name:", Width = 80 }, 0, 1);
|
|
||||||
_nameField = new TextBox { Text = "", Width = 200 };
|
|
||||||
layout.Controls.Add(_nameField, 1, 1);
|
|
||||||
|
|
||||||
layout.Controls.Add(new Label { Text = "Type:", Width = 80 }, 0, 2);
|
|
||||||
_typeField = new TextBox { Text = "", Width = 200 };
|
|
||||||
layout.Controls.Add(_typeField, 1, 2);
|
|
||||||
|
|
||||||
layout.Controls.Add(new Label { Text = "Defaults (key=value, comma separated):", Width = 80 }, 0, 3);
|
|
||||||
_defaultsField = new TextBox { Text = "", Width = 200 };
|
|
||||||
layout.Controls.Add(_defaultsField, 1, 3);
|
|
||||||
|
|
||||||
var buttonPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.RightToLeft, Dock = DockStyle.Fill };
|
|
||||||
_okButton = new Button { Text = "OK", DialogResult = DialogResult.OK };
|
|
||||||
_cancelButton = new Button { Text = "Cancel", DialogResult = DialogResult.Cancel };
|
|
||||||
buttonPanel.Controls.Add(_okButton);
|
|
||||||
buttonPanel.Controls.Add(_cancelButton);
|
|
||||||
|
|
||||||
layout.Controls.Add(buttonPanel, 0, 4);
|
|
||||||
layout.SetColumnSpan(buttonPanel, 2);
|
|
||||||
|
|
||||||
Controls.Add(layout);
|
|
||||||
|
|
||||||
_okButton.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
SourceDef.Id = _idField.Text.Trim();
|
|
||||||
SourceDef.Name = _nameField.Text.Trim();
|
|
||||||
SourceDef.Type = _typeField.Text.Trim();
|
|
||||||
SourceDef.Defaults = ParseDefaults(_defaultsField.Text);
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
Close();
|
|
||||||
};
|
|
||||||
_cancelButton.Click += (s, e) => { DialogResult = DialogResult.Cancel; Close(); };
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateFields()
|
|
||||||
{
|
|
||||||
if (SourceDef != null)
|
|
||||||
{
|
|
||||||
_idField.Text = SourceDef.Id;
|
|
||||||
_nameField.Text = SourceDef.Name;
|
|
||||||
_typeField.Text = SourceDef.Type;
|
|
||||||
_defaultsField.Text = string.Join(", ", SourceDef.Defaults.Select(d => $"{d.Key}={d.Value}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<string, string> ParseDefaults(string text)
|
|
||||||
{
|
|
||||||
var dict = new Dictionary<string, string>();
|
|
||||||
var pairs = text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
foreach (var pair in pairs)
|
|
||||||
{
|
|
||||||
var kv = pair.Split(new[] { '=' }, 2);
|
|
||||||
if (kv.Length == 2)
|
|
||||||
dict[kv[0].Trim()] = kv[1].Trim();
|
|
||||||
}
|
|
||||||
return dict;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,136 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.forms
|
|
||||||
{
|
|
||||||
public class SourcesConfigForm : Form
|
|
||||||
{
|
|
||||||
private List<SourceDef> _sourceDefs;
|
|
||||||
private ListView _listView;
|
|
||||||
private Button _addButton, _editButton, _deleteButton, _closeButton;
|
|
||||||
private TableLayoutPanel _mainLayout;
|
|
||||||
private readonly ISourcesDefManager _sourcesManager;
|
|
||||||
private readonly IFormFactory _formFactory;
|
|
||||||
public event EventHandler<string>? OnSourcesChanged;
|
|
||||||
public List<SourceDef> SourceDefs => _sourceDefs;
|
|
||||||
|
|
||||||
public SourcesConfigForm(IFormFactory formFactory, ISourcesDefManager sourcesManager)
|
|
||||||
{
|
|
||||||
_sourcesManager = sourcesManager ?? throw new ArgumentNullException(nameof(sourcesManager));
|
|
||||||
_formFactory = formFactory ?? throw new ArgumentNullException(nameof(formFactory));
|
|
||||||
_sourceDefs = _sourcesManager.List() ?? new List<SourceDef>();
|
|
||||||
Padding = new Padding(20);
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
Text = "Source Definitions";
|
|
||||||
Size = new Size(800, 400);
|
|
||||||
StartPosition = FormStartPosition.CenterParent;
|
|
||||||
|
|
||||||
_mainLayout = new TableLayoutPanel
|
|
||||||
{
|
|
||||||
Dock = DockStyle.Fill,
|
|
||||||
RowCount = 2,
|
|
||||||
ColumnCount = 1,
|
|
||||||
Padding = new Padding(10)
|
|
||||||
};
|
|
||||||
_mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 80));
|
|
||||||
_mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 20));
|
|
||||||
|
|
||||||
_listView = new ListView
|
|
||||||
{
|
|
||||||
Dock = DockStyle.Fill,
|
|
||||||
View = View.Details,
|
|
||||||
FullRowSelect = true,
|
|
||||||
MultiSelect = false,
|
|
||||||
GridLines = true
|
|
||||||
};
|
|
||||||
_listView.Columns.Add("Id", 100);
|
|
||||||
_listView.Columns.Add("Name", 150);
|
|
||||||
_listView.Columns.Add("Type", 100);
|
|
||||||
_listView.Columns.Add("Defaults", -2);
|
|
||||||
|
|
||||||
UpdateListView();
|
|
||||||
|
|
||||||
_mainLayout.Controls.Add(_listView, 0, 0);
|
|
||||||
|
|
||||||
var buttonPanel = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.LeftToRight };
|
|
||||||
_addButton = new Button { Text = "Add" };
|
|
||||||
_editButton = new Button { Text = "Edit", Enabled = false };
|
|
||||||
_deleteButton = new Button { Text = "Delete", Enabled = false };
|
|
||||||
_closeButton = new Button { Text = "Close", DialogResult = DialogResult.OK };
|
|
||||||
|
|
||||||
_addButton.Click += (s, e) => AddSourceDef();
|
|
||||||
_editButton.Click += (s, e) => EditSourceDef();
|
|
||||||
_deleteButton.Click += (s, e) => DeleteSourceDef();
|
|
||||||
_closeButton.Click += (s, e) => Close();
|
|
||||||
|
|
||||||
_listView.SelectedIndexChanged += (s, e) =>
|
|
||||||
{
|
|
||||||
bool hasSelection = _listView.SelectedItems.Count > 0;
|
|
||||||
_editButton.Enabled = hasSelection;
|
|
||||||
_deleteButton.Enabled = hasSelection;
|
|
||||||
};
|
|
||||||
|
|
||||||
buttonPanel.Controls.AddRange(new Control[] { _addButton, _editButton, _deleteButton, _closeButton });
|
|
||||||
_mainLayout.Controls.Add(buttonPanel, 0, 1);
|
|
||||||
|
|
||||||
Controls.Add(_mainLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateListView()
|
|
||||||
{
|
|
||||||
_listView.Items.Clear();
|
|
||||||
foreach (var src in _sourceDefs)
|
|
||||||
{
|
|
||||||
var item = new ListViewItem(src.Id);
|
|
||||||
item.SubItems.Add(src.Name);
|
|
||||||
item.SubItems.Add(src.Type);
|
|
||||||
item.SubItems.Add(string.Join(", ", src.Defaults.Select(d => $"{d.Key}={d.Value}")));
|
|
||||||
item.Tag = src;
|
|
||||||
_listView.Items.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddSourceDef()
|
|
||||||
{
|
|
||||||
EventHandler<string>? handler = (s, e) => MessageBox.Show("Source Changed");
|
|
||||||
var editor = _formFactory.CreateSourceDetailForm(null, handler);
|
|
||||||
if (editor.ShowDialog() == DialogResult.OK)
|
|
||||||
{
|
|
||||||
_sourceDefs.Add(editor.SourceDef);
|
|
||||||
UpdateListView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EditSourceDef()
|
|
||||||
{
|
|
||||||
if (_listView.SelectedItems.Count == 0) return;
|
|
||||||
var src = _listView.SelectedItems[0].Tag as SourceDef;
|
|
||||||
EventHandler<string>? handler = (s, e) => MessageBox.Show("Source Changed");
|
|
||||||
var editor = _formFactory.CreateSourceDetailForm(src, handler);
|
|
||||||
|
|
||||||
if (editor.ShowDialog() == DialogResult.OK)
|
|
||||||
{
|
|
||||||
//int idx = _sourceDefs.IndexOf(src);
|
|
||||||
//_sourceDefs[idx] = editor.SourceDef;
|
|
||||||
//UpdateListView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeleteSourceDef()
|
|
||||||
{
|
|
||||||
if (_listView.SelectedItems.Count == 0) return;
|
|
||||||
var src = _listView.SelectedItems[0].Tag as SourceDef;
|
|
||||||
_sourceDefs.Remove(src);
|
|
||||||
UpdateListView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.filesystem
|
|
||||||
{
|
|
||||||
public class CheckerTypesDefManager : ICheckerTypesDefManager
|
|
||||||
{
|
|
||||||
private readonly string FilePath = Path.Combine(AppContext.BaseDirectory, "data", "checkerTypesDef.json");
|
|
||||||
|
|
||||||
public List<CheckerTypeDef> Load()
|
|
||||||
{
|
|
||||||
if (!File.Exists(FilePath))
|
|
||||||
return new List<CheckerTypeDef>();
|
|
||||||
var json = File.ReadAllText(FilePath);
|
|
||||||
return JsonSerializer.Deserialize<List<CheckerTypeDef>>(json) ?? new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save(List<CheckerTypeDef> checkerTypesDef)
|
|
||||||
{
|
|
||||||
var options = new JsonSerializerOptions { WriteIndented = true };
|
|
||||||
var json = JsonSerializer.Serialize(checkerTypesDef, options);
|
|
||||||
File.WriteAllText(FilePath, json);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.interfaces
|
|
||||||
{
|
|
||||||
public interface ICheckerTypesDefManager
|
|
||||||
{
|
|
||||||
List<CheckerTypeDef> Load();
|
|
||||||
void Save(List<CheckerTypeDef> checkerTypesDef);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,70 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using ModVersionChecker.utils;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.litedb
|
|
||||||
{
|
|
||||||
public class AppConfigLiteDb : LiteDb, IAppsManager
|
|
||||||
{
|
|
||||||
private string collection = LiteDb.APPS_COLLECTION;
|
|
||||||
public List<AppConfig> Load()
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<AppConfig>(collection);
|
|
||||||
return col.FindAll().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Insert(AppConfig app)
|
|
||||||
{
|
|
||||||
var now = TimeUtils.GetUnixTimeMillis(null);
|
|
||||||
app.CreatedAt = now;
|
|
||||||
app.UpdatedAt = now;
|
|
||||||
var col = _db.GetCollection<AppConfig>(collection);
|
|
||||||
col.Insert(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(AppConfig app)
|
|
||||||
{
|
|
||||||
var now = TimeUtils.GetUnixTimeMillis(null);
|
|
||||||
app.UpdatedAt = now;
|
|
||||||
var col = _db.GetCollection<AppConfig>(collection);
|
|
||||||
col.Update(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
//public void Upsert(AppConfig app)
|
|
||||||
//{
|
|
||||||
// var now = TimeUtils.GetUnixTimeMillis(null);
|
|
||||||
// app.UpdatedAt = now;
|
|
||||||
// var col = _db.GetCollection<AppConfig>(collection);
|
|
||||||
// if (string.IsNullOrEmpty(app.Id))
|
|
||||||
// {
|
|
||||||
// app.CreatedAt = now;
|
|
||||||
// col.Insert(app);
|
|
||||||
// }
|
|
||||||
// col.Update(app);
|
|
||||||
//}
|
|
||||||
|
|
||||||
public void Delete(string id)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<AppConfig>(collection);
|
|
||||||
col.Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save(List<AppConfig> apps)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateStatus(AppConfig app, AppStatus status)
|
|
||||||
{
|
|
||||||
app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(null);
|
|
||||||
app.Status = status;
|
|
||||||
var col = _db.GetCollection<AppConfig>(collection);
|
|
||||||
col.Update(app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,24 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.litedb
|
|
||||||
{
|
|
||||||
public class ConfigLiteDb : LiteDb, IConfigManager
|
|
||||||
{
|
|
||||||
private string collection = LiteDb.CONFIG_COLLECTION;
|
|
||||||
public GlobalConfig Load()
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<GlobalConfig>(collection);
|
|
||||||
return col.FindAll().FirstOrDefault() ?? new GlobalConfig();
|
|
||||||
}
|
|
||||||
public void Save(GlobalConfig config)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<GlobalConfig>(collection);
|
|
||||||
col.Upsert(config);
|
|
||||||
}
|
|
||||||
public GlobalConfig GetConfig()
|
|
||||||
{
|
|
||||||
return Load();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,32 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.litedb
|
|
||||||
{
|
|
||||||
internal class FlightSimsLiteDb : LiteDb, IFlightSimsManager
|
|
||||||
{
|
|
||||||
private string collection = FLIGHT_SIMS_COLLECTION;
|
|
||||||
public List<FsModPathConfig> Load()
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<FsModPathConfig>(collection);
|
|
||||||
return col.FindAll().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save(FsModPathConfig config)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<FsModPathConfig>(collection);
|
|
||||||
col.Upsert(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FsModPathConfig? GetByShortName(string id)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<FsModPathConfig>(collection);
|
|
||||||
return col.FindOne(x => x.ShortName == id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,43 +0,0 @@
|
|||||||
using ModVersionChecker.data.model;
|
|
||||||
using ModVersionChecker.managers.interfaces;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.litedb
|
|
||||||
{
|
|
||||||
public class SourcesLiteDb : LiteDb, ISourcesDefManager
|
|
||||||
{
|
|
||||||
private string collection = SOURCES_DEF_COLLECTION;
|
|
||||||
public List<SourceDef> List()
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<SourceDef>(collection);
|
|
||||||
return col.FindAll().ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SourceDef? GetById(string id)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<SourceDef>(collection);
|
|
||||||
return col.FindOne(x => x.Id == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddSourceDef(SourceDef sourceDef)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<SourceDef>(collection);
|
|
||||||
col.Insert(sourceDef);
|
|
||||||
}
|
|
||||||
public void RemoveSourceDef(string id)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<SourceDef>(collection);
|
|
||||||
col.Delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save(SourceDef sourceDef)
|
|
||||||
{
|
|
||||||
var col = _db.GetCollection<SourceDef>(collection);
|
|
||||||
col.Upsert(sourceDef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,21 +1,21 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.enums;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
public class AppConfig
|
public class App
|
||||||
{
|
{
|
||||||
|
public App() { }
|
||||||
|
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("uid")]
|
||||||
|
public string Uid { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("name")]
|
[JsonPropertyName("name")]
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("msfsVersions")]
|
[JsonPropertyName("type")]
|
||||||
public List<string> MsfsVersions { get; set; } = new List<string> { "msfs2024" }; // Default to msfs2024
|
public string Type { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
[JsonPropertyName("source")]
|
[JsonPropertyName("source")]
|
||||||
@@ -24,8 +24,8 @@ public class AppConfig
|
|||||||
[JsonPropertyName("params")]
|
[JsonPropertyName("params")]
|
||||||
public Dictionary<string, string> Params { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> Params { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
[JsonPropertyName("fsFields")]
|
[JsonPropertyName("fields")]
|
||||||
public Dictionary<string, Dictionary<string, string>> FsFields { get; set; } = new Dictionary<string, Dictionary<string, string>>();
|
public Dictionary<string, string> Fields { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
[JsonPropertyName("downloadUrl")]
|
[JsonPropertyName("downloadUrl")]
|
||||||
public string DownloadUrl { get; set; } = string.Empty;
|
public string DownloadUrl { get; set; } = string.Empty;
|
||||||
@@ -37,15 +37,13 @@ public class AppConfig
|
|||||||
public string LatestVersion { get; set; } = string.Empty;
|
public string LatestVersion { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("status")]
|
[JsonPropertyName("status")]
|
||||||
public AppStatus Status { get; set; } = AppStatus.None;
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
|
public AppStatus Status { get; set; } = AppStatus.NONE;
|
||||||
[JsonPropertyName("createdAt")]
|
|
||||||
public long CreatedAt { get; set; } = 0;
|
|
||||||
|
|
||||||
[JsonPropertyName("updatedAt")]
|
|
||||||
public long UpdatedAt { get; set; } = 0;
|
|
||||||
|
|
||||||
[JsonPropertyName("lastCheckedAt")]
|
[JsonPropertyName("lastCheckedAt")]
|
||||||
public long LastCheckedAt { get; set; } = 0;
|
public long LastCheckedAt { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("localCheckedAt ")]
|
||||||
|
public long LocalCheckedAt { get; set; } = 0;
|
||||||
|
|
||||||
}
|
}
|
@@ -6,11 +6,11 @@ using System.Text;
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ModVersionChecker.data.model
|
namespace ModVersionChecker.model
|
||||||
{
|
{
|
||||||
public class GlobalConfig
|
public class Config
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = String.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("intervalMinutes")]
|
[JsonPropertyName("intervalMinutes")]
|
||||||
public int IntervalMinutes { get; set; } = 60;
|
public int IntervalMinutes { get; set; } = 60;
|
||||||
@@ -20,5 +20,14 @@ namespace ModVersionChecker.data.model
|
|||||||
|
|
||||||
[JsonPropertyName("runOnStartup")]
|
[JsonPropertyName("runOnStartup")]
|
||||||
public bool RunOnStartup { get; set; } = false;
|
public bool RunOnStartup { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonPropertyName("types")]
|
||||||
|
public List<TypeConfig> Types { get; set; } = new List<TypeConfig>();
|
||||||
|
|
||||||
|
[JsonPropertyName("accessToekn")]
|
||||||
|
public string AccessToken { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("refreshToken")]
|
||||||
|
public string RefreshToken { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
25
ModVersionChecker/model/TypeConfig.cs
Normal file
25
ModVersionChecker/model/TypeConfig.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.model
|
||||||
|
{
|
||||||
|
public class TypeConfig
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("shortName")]
|
||||||
|
public string ShortName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("configValues")]
|
||||||
|
public Dictionary<string, string> ConfigValues { get; set; } = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
27
ModVersionChecker/repository/api/ApiBase.cs
Normal file
27
ModVersionChecker/repository/api/ApiBase.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api
|
||||||
|
{
|
||||||
|
public class ApiBase: IDisposable
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient = new HttpClient();
|
||||||
|
|
||||||
|
public ApiBase()
|
||||||
|
{
|
||||||
|
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("User-Agent", "ModVersionChecker");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_httpClient?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
169
ModVersionChecker/repository/api/ApiRepository.cs
Normal file
169
ModVersionChecker/repository/api/ApiRepository.cs
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api
|
||||||
|
{
|
||||||
|
public class ApiRepository : IApiRepository, IDisposable
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private string baseUrl = "http://192.168.1.115:3115/api";
|
||||||
|
private JwtTokenResponse? _accessToken;
|
||||||
|
private JwtTokenResponse? _refreshToken;
|
||||||
|
private DateTime _accessTokenExpiry = DateTime.MinValue;
|
||||||
|
|
||||||
|
public ApiRepository()
|
||||||
|
{
|
||||||
|
_httpClient = new HttpClient();
|
||||||
|
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> AuthenticateAsync(string username, string password)
|
||||||
|
{
|
||||||
|
var url = $"{baseUrl}/auth";
|
||||||
|
var payload = new { username, password };
|
||||||
|
var jsonPayload = JsonSerializer.Serialize(payload);
|
||||||
|
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _httpClient.PostAsync(url, content);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var authentication = JsonSerializer.Deserialize<AuthenticationResponse>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
_accessToken = DecodeJwt(authentication?.AccessToken);
|
||||||
|
_refreshToken = DecodeJwt(authentication?.RefreshToken);
|
||||||
|
if (_accessToken == null)
|
||||||
|
throw new Exception("Failed to decode access token.");
|
||||||
|
_accessTokenExpiry = DateTime.UtcNow.AddSeconds(_accessToken.ExpireAt - 60);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JwtTokenResponse? DecodeJwt(string? token)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(token))
|
||||||
|
return null;
|
||||||
|
var parts = token.Split('.');
|
||||||
|
if (parts.Length != 3)
|
||||||
|
throw new ArgumentException("Invalid JWT token format.");
|
||||||
|
var payload = parts[1];
|
||||||
|
var paddedPayload = payload.PadRight(payload.Length + (4 - payload.Length % 4) % 4, '=');
|
||||||
|
var jsonBytes = Convert.FromBase64String(paddedPayload);
|
||||||
|
var json = Encoding.UTF8.GetString(jsonBytes);
|
||||||
|
var doc = JsonSerializer.Deserialize<JwtTokenResponse>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
if (doc != null)
|
||||||
|
doc.Token = token;
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> EnsureTokenValidAsync()
|
||||||
|
{
|
||||||
|
if (_accessToken == null || DateTime.UtcNow >= _accessTokenExpiry)
|
||||||
|
{
|
||||||
|
return await RefreshTokenAsync();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> RefreshTokenAsync()
|
||||||
|
{
|
||||||
|
if (_refreshToken == null)
|
||||||
|
return false;
|
||||||
|
var refreshData = new { refreshToken = _refreshToken };
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(refreshData), Encoding.UTF8, "application/json");
|
||||||
|
var response = await _httpClient.PostAsync($"{baseUrl}/auth/refresh", content);
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
return false;
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
var authentication = JsonSerializer.Deserialize<AuthenticationResponse>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
_accessToken = DecodeJwt(authentication?.AccessToken);
|
||||||
|
if (_accessToken == null)
|
||||||
|
throw new Exception("Failed to decode access token.");
|
||||||
|
_accessTokenExpiry = DateTime.UtcNow.AddSeconds(_accessToken.ExpireAt - 60);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<HttpRequestMessage> CreateRequestAsync(HttpMethod method, string url)
|
||||||
|
{
|
||||||
|
await EnsureTokenValidAsync();
|
||||||
|
var request = new HttpRequestMessage(method, url);
|
||||||
|
if (_accessToken != null)
|
||||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken.Token);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<AppVersionsResponse>?> GetAppVersionsAsync(List<App> apps)
|
||||||
|
{
|
||||||
|
var url = $"{baseUrl}/app/versions?{string.Join("&", apps.Select(a => $"version={Uri.EscapeDataString(a.Id)}"))}";
|
||||||
|
var request = await CreateRequestAsync(HttpMethod.Get, url);
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<List<AppVersionsResponse>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
}
|
||||||
|
public async Task<AppVersionsResponse?> GetAppLatestVersionAsync(App app)
|
||||||
|
{
|
||||||
|
var url = $"{baseUrl}/app/latest?version={Uri.EscapeDataString(app.Id)}";
|
||||||
|
var request = await CreateRequestAsync(HttpMethod.Get, url);
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<AppVersionsResponse>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TypeResponse>> GetTypes()
|
||||||
|
{
|
||||||
|
var url = $"{baseUrl}/type";
|
||||||
|
var request = await CreateRequestAsync(HttpMethod.Get, url);
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<List<TypeResponse>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<SourceResponse>> GetSources()
|
||||||
|
{
|
||||||
|
var url = $"{baseUrl}/source";
|
||||||
|
var request = await CreateRequestAsync(HttpMethod.Get, url);
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<List<SourceResponse>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<AppResponse>?> SearchApps(string searchText)
|
||||||
|
{
|
||||||
|
var url = $"{baseUrl}/app/search?query={Uri.EscapeDataString(searchText)}";
|
||||||
|
var request = await CreateRequestAsync(HttpMethod.Get, url);
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<List<AppResponse>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<AppResponse>> GetAppsByIds(App[] apps)
|
||||||
|
{
|
||||||
|
var query = string.Join("&", apps.Select(a => $"id={Uri.EscapeDataString(a.Id)}"));
|
||||||
|
var url = $"{baseUrl}/app/search?{query}";
|
||||||
|
var request = await CreateRequestAsync(HttpMethod.Get, url);
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
return JsonSerializer.Deserialize<List<AppResponse>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? new List<AppResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_httpClient?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
ModVersionChecker/repository/api/IApiRepository.cs
Normal file
17
ModVersionChecker/repository/api/IApiRepository.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api
|
||||||
|
{
|
||||||
|
public interface IApiRepository
|
||||||
|
{
|
||||||
|
Task<bool> AuthenticateAsync(string username, string password);
|
||||||
|
Task<List<AppVersionsResponse>?> GetAppVersionsAsync(List<App> apps);
|
||||||
|
Task<AppVersionsResponse?> GetAppLatestVersionAsync(App app);
|
||||||
|
Task<List<AppResponse>?> SearchApps(string searchText);
|
||||||
|
Task<List<TypeResponse>> GetTypes();
|
||||||
|
Task<List<SourceResponse>> GetSources();
|
||||||
|
Task<List<AppResponse>> GetAppsByIds(App[] apps);
|
||||||
|
}
|
||||||
|
}
|
81
ModVersionChecker/repository/api/dto/AppResponse.cs
Normal file
81
ModVersionChecker/repository/api/dto/AppResponse.cs
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
using ModVersionChecker.enums;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api.dto
|
||||||
|
{
|
||||||
|
public class AppResponse
|
||||||
|
{
|
||||||
|
public AppResponse() { }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("uid")]
|
||||||
|
public string Uid { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
[JsonPropertyName("source")]
|
||||||
|
public string Source { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("params")]
|
||||||
|
public Dictionary<string, string> Params { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
[JsonPropertyName("fields")]
|
||||||
|
public Dictionary<string, string> Fields { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
[JsonPropertyName("downloadUrl")]
|
||||||
|
public string DownloadUrl { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("currentVersion")]
|
||||||
|
public string CurrentVersion { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("latestVersion")]
|
||||||
|
public string LatestVersion { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("status")]
|
||||||
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
|
public AppStatus Status { get; set; } = AppStatus.NONE;
|
||||||
|
|
||||||
|
[JsonPropertyName("createdAt")]
|
||||||
|
public long CreatedAt { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("updatedAt")]
|
||||||
|
public long UpdatedAt { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("lastCheckedAt")]
|
||||||
|
public long LastCheckedAt { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("active")]
|
||||||
|
public bool Active { get; set; } = false;
|
||||||
|
|
||||||
|
public static App toModel(AppResponse appResponse)
|
||||||
|
{
|
||||||
|
if (appResponse == null)
|
||||||
|
{
|
||||||
|
return new App();
|
||||||
|
}
|
||||||
|
return new App()
|
||||||
|
{
|
||||||
|
Id = appResponse.Id,
|
||||||
|
Uid = appResponse.Uid,
|
||||||
|
Name = appResponse.Name,
|
||||||
|
Type = appResponse.Type,
|
||||||
|
Source = appResponse.Source,
|
||||||
|
Params = appResponse.Params,
|
||||||
|
Fields = appResponse.Fields,
|
||||||
|
DownloadUrl = appResponse.DownloadUrl,
|
||||||
|
CurrentVersion = appResponse.CurrentVersion,
|
||||||
|
LatestVersion = appResponse.LatestVersion,
|
||||||
|
Status = appResponse.Status,
|
||||||
|
LastCheckedAt = appResponse.LastCheckedAt,
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
ModVersionChecker/repository/api/dto/AppVersionsResponse.cs
Normal file
15
ModVersionChecker/repository/api/dto/AppVersionsResponse.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api.dto
|
||||||
|
{
|
||||||
|
public class AppVersionsResponse
|
||||||
|
{
|
||||||
|
public AppVersionsResponse() { }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("latestVersion")]
|
||||||
|
public string LatestVersion { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api.dto
|
||||||
|
{
|
||||||
|
public class AuthenticationResponse
|
||||||
|
{
|
||||||
|
[JsonPropertyName("accessToken")]
|
||||||
|
public string AccessToken { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("refreshToken")]
|
||||||
|
public string RefreshToken { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
@@ -5,15 +5,17 @@ using System.Text;
|
|||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ModVersionChecker.data.model
|
namespace ModVersionChecker.repository.api.dto
|
||||||
{
|
{
|
||||||
public class FieldDef
|
public class FieldResponse
|
||||||
{
|
{
|
||||||
[JsonPropertyName("name")]
|
[JsonPropertyName("name")]
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("label")]
|
[JsonPropertyName("label")]
|
||||||
public string Label { get; set; } = string.Empty;
|
public string Label { get; set; } = string.Empty;
|
||||||
|
[JsonPropertyName("description")]
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("type")]
|
[JsonPropertyName("type")]
|
||||||
public string Type { get; set; } = string.Empty;
|
public string Type { get; set; } = string.Empty;
|
||||||
@@ -21,7 +23,10 @@ namespace ModVersionChecker.data.model
|
|||||||
[JsonPropertyName("required")]
|
[JsonPropertyName("required")]
|
||||||
public bool Required { get; set; } = false;
|
public bool Required { get; set; } = false;
|
||||||
|
|
||||||
[JsonPropertyName("control")]
|
[JsonPropertyName("controlType")]
|
||||||
public string Control { get; set; } = string.Empty;
|
public string ControlType { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("defaultValue")]
|
||||||
|
public string DefaultValue { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
26
ModVersionChecker/repository/api/dto/JwtTokenResponse.cs
Normal file
26
ModVersionChecker/repository/api/dto/JwtTokenResponse.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api.dto
|
||||||
|
{
|
||||||
|
public class JwtTokenResponse
|
||||||
|
{
|
||||||
|
public JwtTokenResponse() { }
|
||||||
|
public string Token { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("exp")]
|
||||||
|
public long ExpireAt { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("iat")]
|
||||||
|
public long IssuedAt { get; set; } = 0;
|
||||||
|
|
||||||
|
[JsonPropertyName("sub")]
|
||||||
|
public string Subject { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -1,13 +1,8 @@
|
|||||||
using System;
|
using System.Text.Json.Serialization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ModVersionChecker.data.model
|
namespace ModVersionChecker.repository.api.dto
|
||||||
{
|
{
|
||||||
public class SourceDef
|
public class SourceResponse
|
||||||
{
|
{
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
27
ModVersionChecker/repository/api/dto/TypeResponse.cs
Normal file
27
ModVersionChecker/repository/api/dto/TypeResponse.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.repository.api.dto
|
||||||
|
{
|
||||||
|
public class TypeResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
public string Id { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("shortName")]
|
||||||
|
public string ShortName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("configFields")]
|
||||||
|
public List<FieldResponse> ConfigFields { get; set; } = new List<FieldResponse>();
|
||||||
|
|
||||||
|
[JsonPropertyName("appFields")]
|
||||||
|
public List<FieldResponse> AppFields { get; set; } = new List<FieldResponse>();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.enums;
|
||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.managers.interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
@@ -9,22 +9,22 @@ namespace ModVersionChecker.managers.filesystem
|
|||||||
{
|
{
|
||||||
private readonly string FilePath = Path.Combine(AppContext.BaseDirectory, "data", "apps.json");
|
private readonly string FilePath = Path.Combine(AppContext.BaseDirectory, "data", "apps.json");
|
||||||
|
|
||||||
public List<AppConfig> Load()
|
public List<App> Load()
|
||||||
{
|
{
|
||||||
if (!File.Exists(FilePath))
|
if (!File.Exists(FilePath))
|
||||||
return new List<AppConfig>();
|
return new List<App>();
|
||||||
var json = File.ReadAllText(FilePath);
|
var json = File.ReadAllText(FilePath);
|
||||||
return JsonSerializer.Deserialize<List<AppConfig>>(json) ?? new();
|
return JsonSerializer.Deserialize<List<App>>(json) ?? new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(List<AppConfig> apps)
|
public void Save(List<App> apps)
|
||||||
{
|
{
|
||||||
var options = new JsonSerializerOptions { WriteIndented = true };
|
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||||
var json = JsonSerializer.Serialize(apps, options);
|
var json = JsonSerializer.Serialize(apps, options);
|
||||||
File.WriteAllText(FilePath, json);
|
File.WriteAllText(FilePath, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Upsert(AppConfig app)
|
public void Upsert(App app)
|
||||||
{
|
{
|
||||||
var apps = Load();
|
var apps = Load();
|
||||||
var index = apps.FindIndex(a => a.Id == app.Id);
|
var index = apps.FindIndex(a => a.Id == app.Id);
|
@@ -1,5 +1,5 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.managers.interfaces;
|
||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.model;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -10,27 +10,27 @@ namespace ModVersionChecker.managers.filesystem
|
|||||||
{
|
{
|
||||||
|
|
||||||
private static readonly string _filePath = Path.Combine(AppContext.BaseDirectory, "data", "config.json");
|
private static readonly string _filePath = Path.Combine(AppContext.BaseDirectory, "data", "config.json");
|
||||||
private GlobalConfig _config;
|
private Config _config;
|
||||||
|
|
||||||
public ConfigManager()
|
public ConfigManager()
|
||||||
{
|
{
|
||||||
_config = Load();
|
_config = Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalConfig Load()
|
public Config Load()
|
||||||
{
|
{
|
||||||
if (!File.Exists(_filePath))
|
if (!File.Exists(_filePath))
|
||||||
return new GlobalConfig();
|
return new Config();
|
||||||
var json = File.ReadAllText(_filePath);
|
var json = File.ReadAllText(_filePath);
|
||||||
return JsonSerializer.Deserialize<GlobalConfig>(json) ?? new GlobalConfig();
|
return JsonSerializer.Deserialize<Config>(json) ?? new Config();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalConfig GetConfig()
|
public Config GetConfig()
|
||||||
{
|
{
|
||||||
return _config;
|
return _config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(GlobalConfig config)
|
public void Save(Config config)
|
||||||
{
|
{
|
||||||
var options = new JsonSerializerOptions { WriteIndented = true };
|
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||||
var json = JsonSerializer.Serialize(config, options);
|
var json = JsonSerializer.Serialize(config, options);
|
@@ -1,5 +1,5 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.managers.interfaces;
|
||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.repository.api.dto;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -9,27 +9,27 @@ namespace ModVersionChecker.managers.filesystem
|
|||||||
public class SourcesDefManager
|
public class SourcesDefManager
|
||||||
{
|
{
|
||||||
private readonly string _filePath = Path.Combine(AppContext.BaseDirectory, "data", "sourcesDef.json");
|
private readonly string _filePath = Path.Combine(AppContext.BaseDirectory, "data", "sourcesDef.json");
|
||||||
private List<SourceDef> _sourcesDef = new List<SourceDef>();
|
private List<SourceResponse> _sourcesDef = new List<SourceResponse>();
|
||||||
|
|
||||||
public SourcesDefManager()
|
public SourcesDefManager()
|
||||||
{
|
{
|
||||||
_sourcesDef = Load();
|
_sourcesDef = Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SourceDef> Load()
|
private List<SourceResponse> Load()
|
||||||
{
|
{
|
||||||
if (!File.Exists(_filePath))
|
if (!File.Exists(_filePath))
|
||||||
return new List<SourceDef>();
|
return new List<SourceResponse>();
|
||||||
var json = File.ReadAllText(_filePath);
|
var json = File.ReadAllText(_filePath);
|
||||||
return JsonSerializer.Deserialize<List<SourceDef>>(json) ?? new();
|
return JsonSerializer.Deserialize<List<SourceResponse>>(json) ?? new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SourceDef> GetSourcesDef()
|
public List<SourceResponse> GetSourcesDef()
|
||||||
{
|
{
|
||||||
return _sourcesDef;
|
return _sourcesDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSourceDef(SourceDef sourceDef)
|
public void AddSourceDef(SourceResponse sourceDef)
|
||||||
{
|
{
|
||||||
_sourcesDef.Add(sourceDef);
|
_sourcesDef.Add(sourceDef);
|
||||||
Save(_sourcesDef);
|
Save(_sourcesDef);
|
||||||
@@ -42,7 +42,7 @@ namespace ModVersionChecker.managers.filesystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Save(List<SourceDef> sourcesDef)
|
public void Save(List<SourceResponse> sourcesDef)
|
||||||
{
|
{
|
||||||
var options = new JsonSerializerOptions { WriteIndented = true };
|
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||||
var json = JsonSerializer.Serialize(sourcesDef, options);
|
var json = JsonSerializer.Serialize(sourcesDef, options);
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.enums;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.enums;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -10,17 +10,17 @@ namespace ModVersionChecker.managers.interfaces
|
|||||||
public interface IAppsManager
|
public interface IAppsManager
|
||||||
{
|
{
|
||||||
|
|
||||||
List<AppConfig> Load();
|
List<App> Load();
|
||||||
|
|
||||||
void Save(List<AppConfig> apps);
|
void Save(List<App> apps);
|
||||||
|
|
||||||
public void Insert(AppConfig app);
|
public void Insert(App app);
|
||||||
|
|
||||||
public void Update(AppConfig app);
|
public void Update(App app);
|
||||||
|
|
||||||
void Delete(string id);
|
void Delete(string id);
|
||||||
|
|
||||||
void UpdateStatus(AppConfig app, AppStatus status);
|
void UpdateStatus(App app, AppStatus status);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.model;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -9,8 +9,8 @@ namespace ModVersionChecker.managers.interfaces
|
|||||||
{
|
{
|
||||||
public interface IConfigManager
|
public interface IConfigManager
|
||||||
{
|
{
|
||||||
GlobalConfig Load();
|
Config Load();
|
||||||
void Save(GlobalConfig config);
|
void Save(Config config);
|
||||||
GlobalConfig GetConfig();
|
Config GetConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.repository.api.dto;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -9,9 +9,11 @@ namespace ModVersionChecker.managers.interfaces
|
|||||||
{
|
{
|
||||||
public interface IFlightSimsManager
|
public interface IFlightSimsManager
|
||||||
{
|
{
|
||||||
List<FsModPathConfig> Load();
|
List<TypeResponse> Load();
|
||||||
void Save(FsModPathConfig config);
|
void Save(TypeResponse config);
|
||||||
|
|
||||||
FsModPathConfig? GetByShortName(string id);
|
TypeResponse? GetByShortName(string id);
|
||||||
|
|
||||||
|
void DeleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.repository.api.dto;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -9,11 +9,12 @@ namespace ModVersionChecker.managers.interfaces
|
|||||||
{
|
{
|
||||||
public interface ISourcesDefManager
|
public interface ISourcesDefManager
|
||||||
{
|
{
|
||||||
List<SourceDef> List();
|
List<SourceResponse> List();
|
||||||
|
|
||||||
SourceDef? GetById(string id);
|
SourceResponse? GetById(string id);
|
||||||
void AddSourceDef(SourceDef sourceDef);
|
void AddSourceDef(SourceResponse sourceDef);
|
||||||
void RemoveSourceDef(string id);
|
void RemoveSourceDef(string id);
|
||||||
void Save(SourceDef sourceDef);
|
void Save(SourceResponse sourceDef);
|
||||||
|
void DeleteAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
13
ModVersionChecker/repository/interfaces/ITypeManager.cs
Normal file
13
ModVersionChecker/repository/interfaces/ITypeManager.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using ModVersionChecker.model;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.managers.interfaces
|
||||||
|
{
|
||||||
|
public interface ITypeManager
|
||||||
|
{
|
||||||
|
List<TypeConfig> GetTypeConfigs();
|
||||||
|
void SaveTypeConfigs(List<TypeConfig> types);
|
||||||
|
TypeConfig? GetTypeConfigById(string id);
|
||||||
|
void SaveTypeConfig(TypeConfig type);
|
||||||
|
void DeleteTypeConfig(string id);
|
||||||
|
}
|
||||||
|
}
|
50
ModVersionChecker/repository/litedb/AppLiteDb.cs
Normal file
50
ModVersionChecker/repository/litedb/AppLiteDb.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using ModVersionChecker.enums;
|
||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.managers.litedb
|
||||||
|
{
|
||||||
|
public class AppLiteDb : LiteDb, IAppsManager
|
||||||
|
{
|
||||||
|
protected override string collection => LiteDb.APPS_COLLECTION;
|
||||||
|
|
||||||
|
public List<App> Load()
|
||||||
|
{
|
||||||
|
return GetCollection<App>().FindAll().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(App app)
|
||||||
|
{
|
||||||
|
var now = TimeUtils.GetUnixTimeMillis(null);
|
||||||
|
GetCollection<App>().Insert(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(App app)
|
||||||
|
{
|
||||||
|
var now = TimeUtils.GetUnixTimeMillis(null);
|
||||||
|
GetCollection<App>().Update(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete(string id)
|
||||||
|
{
|
||||||
|
GetCollection<App>().Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(List<App> apps)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateStatus(App app, AppStatus status)
|
||||||
|
{
|
||||||
|
app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(null);
|
||||||
|
app.Status = status;
|
||||||
|
GetCollection<App>().Update(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
ModVersionChecker/repository/litedb/ConfigLiteDb.cs
Normal file
22
ModVersionChecker/repository/litedb/ConfigLiteDb.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.model;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.managers.litedb
|
||||||
|
{
|
||||||
|
public class ConfigLiteDb : LiteDb, IConfigManager
|
||||||
|
{
|
||||||
|
protected override string collection => LiteDb.CONFIG_COLLECTION;
|
||||||
|
public Config Load()
|
||||||
|
{
|
||||||
|
return GetCollection<Config>().FindAll().FirstOrDefault() ?? new Config();
|
||||||
|
}
|
||||||
|
public void Save(Config config)
|
||||||
|
{
|
||||||
|
GetCollection<Config>().Upsert(config);
|
||||||
|
}
|
||||||
|
public Config GetConfig()
|
||||||
|
{
|
||||||
|
return Load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace ModVersionChecker.managers.litedb
|
namespace ModVersionChecker.managers.litedb
|
||||||
{
|
{
|
||||||
public class LiteDb
|
public abstract class LiteDb
|
||||||
{
|
{
|
||||||
public static string DB_PATH = "ModVersionChecker.db";
|
public static string DB_PATH = "ModVersionChecker.db";
|
||||||
public static string APPS_COLLECTION = "apps";
|
public static string APPS_COLLECTION = "apps";
|
||||||
@@ -10,7 +10,16 @@ namespace ModVersionChecker.managers.litedb
|
|||||||
public static string SOURCES_DEF_COLLECTION = "sources_def";
|
public static string SOURCES_DEF_COLLECTION = "sources_def";
|
||||||
public static string CONFIG_COLLECTION = "config";
|
public static string CONFIG_COLLECTION = "config";
|
||||||
public static string FLIGHT_SIMS_COLLECTION = "flight_sims";
|
public static string FLIGHT_SIMS_COLLECTION = "flight_sims";
|
||||||
|
public static string TYPES_COLLECTION = "types";
|
||||||
|
public static string LOCAL_APPS_COLLECTION = "local_apps";
|
||||||
|
|
||||||
protected LiteDatabase _db = LiteDbSingleton.Instance;
|
protected LiteDatabase _db = LiteDbSingleton.Instance;
|
||||||
|
|
||||||
|
protected abstract string collection { get; }
|
||||||
|
|
||||||
|
protected ILiteCollection<T> GetCollection<T>()
|
||||||
|
{
|
||||||
|
return _db.GetCollection<T>(collection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
44
ModVersionChecker/repository/litedb/SourcesLiteDb.cs
Normal file
44
ModVersionChecker/repository/litedb/SourcesLiteDb.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.managers.litedb
|
||||||
|
{
|
||||||
|
public class SourcesLiteDb : LiteDb, ISourcesDefManager
|
||||||
|
{
|
||||||
|
protected override string collection => SOURCES_DEF_COLLECTION;
|
||||||
|
|
||||||
|
public List<SourceResponse> List()
|
||||||
|
{
|
||||||
|
return GetCollection<SourceResponse>().FindAll().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceResponse? GetById(string id)
|
||||||
|
{
|
||||||
|
return GetCollection<SourceResponse>().FindOne(x => x.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSourceDef(SourceResponse sourceDef)
|
||||||
|
{
|
||||||
|
GetCollection<SourceResponse>().Insert(sourceDef);
|
||||||
|
}
|
||||||
|
public void RemoveSourceDef(string id)
|
||||||
|
{
|
||||||
|
GetCollection<SourceResponse>().Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(SourceResponse sourceDef)
|
||||||
|
{
|
||||||
|
GetCollection<SourceResponse>().Upsert(sourceDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteAll()
|
||||||
|
{
|
||||||
|
GetCollection<SourceResponse>().DeleteAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
ModVersionChecker/repository/litedb/TypeConfigLiteDb.cs
Normal file
35
ModVersionChecker/repository/litedb/TypeConfigLiteDb.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.model;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.managers.litedb
|
||||||
|
{
|
||||||
|
internal class TypeConfigLiteDb : LiteDb, ITypeManager
|
||||||
|
{
|
||||||
|
protected override string collection => TYPES_COLLECTION;
|
||||||
|
|
||||||
|
public void DeleteTypeConfig(string id)
|
||||||
|
{
|
||||||
|
GetCollection<TypeConfig>().Delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeConfig? GetTypeConfigById(string id)
|
||||||
|
{
|
||||||
|
return GetCollection<TypeConfig>().FindOne(x => x.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TypeConfig> GetTypeConfigs()
|
||||||
|
{
|
||||||
|
return GetCollection<TypeConfig>().FindAll().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveTypeConfig(TypeConfig type)
|
||||||
|
{
|
||||||
|
GetCollection<TypeConfig>().Upsert(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveTypeConfigs(List<TypeConfig> types)
|
||||||
|
{
|
||||||
|
GetCollection<TypeConfig>().InsertBulk(types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
ModVersionChecker/repository/litedb/TypeLiteDb.cs
Normal file
35
ModVersionChecker/repository/litedb/TypeLiteDb.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.managers.litedb
|
||||||
|
{
|
||||||
|
internal class TypeLiteDb : LiteDb, IFlightSimsManager
|
||||||
|
{
|
||||||
|
protected override string collection => FLIGHT_SIMS_COLLECTION;
|
||||||
|
|
||||||
|
public List<TypeResponse> Load()
|
||||||
|
{
|
||||||
|
return GetCollection<TypeResponse>().FindAll().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(TypeResponse config)
|
||||||
|
{
|
||||||
|
GetCollection<TypeResponse>().Upsert(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeResponse? GetByShortName(string id)
|
||||||
|
{
|
||||||
|
return GetCollection<TypeResponse>().FindOne(x => x.ShortName == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteAll()
|
||||||
|
{
|
||||||
|
GetCollection<TypeResponse>().DeleteAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
ModVersionChecker/service/ApiService.cs
Normal file
47
ModVersionChecker/service/ApiService.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using ModVersionChecker.repository.api;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.service
|
||||||
|
{
|
||||||
|
public class ApiService : IApiService
|
||||||
|
{
|
||||||
|
private readonly IApiRepository _apiRepository;
|
||||||
|
|
||||||
|
public ApiService(IApiRepository apiRepository)
|
||||||
|
{
|
||||||
|
_apiRepository = apiRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> AuthenticateAsync(string username, string password)
|
||||||
|
=> _apiRepository.AuthenticateAsync(username, password);
|
||||||
|
|
||||||
|
public Task<List<AppVersionsResponse>?> GetAppVersionsAsync(List<App> apps)
|
||||||
|
=> _apiRepository.GetAppVersionsAsync(apps);
|
||||||
|
|
||||||
|
public Task<AppVersionsResponse?> GetAppLatestVersionAsync(App app)
|
||||||
|
=> _apiRepository.GetAppLatestVersionAsync(app);
|
||||||
|
|
||||||
|
|
||||||
|
public Task<List<TypeResponse>> GetTypes()
|
||||||
|
=> _apiRepository.GetTypes();
|
||||||
|
|
||||||
|
public Task<List<SourceResponse>> GetSources()
|
||||||
|
=> _apiRepository.GetSources();
|
||||||
|
|
||||||
|
public async Task<List<App>> GetAppsByIds(App[] apps)
|
||||||
|
{
|
||||||
|
var appResponses = await _apiRepository.GetAppsByIds(apps);
|
||||||
|
return appResponses.Select(AppResponse.toModel).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<List<App>?> SearchApps(string searchText)
|
||||||
|
{
|
||||||
|
var appResponses = _apiRepository.SearchApps(searchText);
|
||||||
|
return appResponses.ContinueWith(t => t.Result?.Select(AppResponse.toModel).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -1,11 +1,11 @@
|
|||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.service.interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.filesystem
|
namespace ModVersionChecker.service
|
||||||
{
|
{
|
||||||
public class NotifyIconService : INotifyIconService
|
public class NotifyIconService : INotifyIconService
|
||||||
{
|
{
|
141
ModVersionChecker/service/VersionService.cs
Normal file
141
ModVersionChecker/service/VersionService.cs
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
using ModVersionChecker.enums;
|
||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.model;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
|
using ModVersionChecker.utils;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.service
|
||||||
|
{
|
||||||
|
public class VersionService: IVersionService
|
||||||
|
{
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
private readonly IAppsManager _appsManager;
|
||||||
|
private readonly INotifyIconService _notifyIconService;
|
||||||
|
private readonly Config _globalConfig;
|
||||||
|
|
||||||
|
public VersionService(
|
||||||
|
IApiService apiVersionService,
|
||||||
|
IAppsManager appsManager,
|
||||||
|
IConfigManager configManager,
|
||||||
|
INotifyIconService notifyIconService)
|
||||||
|
{
|
||||||
|
_apiService = apiVersionService;
|
||||||
|
_appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager));
|
||||||
|
_notifyIconService = notifyIconService ?? throw new ArgumentNullException(nameof(notifyIconService));
|
||||||
|
_globalConfig = configManager.Load() ?? new Config();
|
||||||
|
}
|
||||||
|
|
||||||
|
public App CheckApp(App app)
|
||||||
|
{
|
||||||
|
var status = AppStatus.NONE;
|
||||||
|
if (app.LatestVersion== null)
|
||||||
|
{
|
||||||
|
app.Status = AppStatus.ERROR;
|
||||||
|
_appsManager.Update(app);
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
var currentVersion = app.CurrentVersion;
|
||||||
|
var updateMessage = "";
|
||||||
|
if (isUpdateAvailable(currentVersion, app.LatestVersion))
|
||||||
|
{
|
||||||
|
updateMessage = $"{app.Name}: New version {app.LatestVersion} (current: {currentVersion})";
|
||||||
|
status = AppStatus.UPDATE_AVAILABLE;
|
||||||
|
}
|
||||||
|
app.Status = status;
|
||||||
|
app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(null);
|
||||||
|
_appsManager.Update(app);
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CheckAllApps()
|
||||||
|
{
|
||||||
|
|
||||||
|
var apps = _appsManager.Load();
|
||||||
|
var sources = await _apiService.GetSources();
|
||||||
|
var appVersionsMap = await _apiService.GetAppVersionsAsync(apps);
|
||||||
|
List<string> errorMessages = new List<string>();
|
||||||
|
List<string> updateMessages = new List<string>();
|
||||||
|
|
||||||
|
if (apps == null || apps.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (App app in apps)
|
||||||
|
{
|
||||||
|
|
||||||
|
var sourceId = app.Source;
|
||||||
|
|
||||||
|
if (
|
||||||
|
app.Status != AppStatus.ERROR && app.LastCheckedAt != 0 && app.LastCheckedAt < TimeUtils.GetUnixTimeMillis(DateTime.UtcNow.AddMinutes(-60)) ||
|
||||||
|
!app.Active || string.IsNullOrWhiteSpace(sourceId)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var latesstVersion = appVersionsMap.FirstOrDefault(a => a.Id == app.Id)?.LatestVersion;
|
||||||
|
var source = sources.FirstOrDefault(s => s.Id == sourceId);
|
||||||
|
if (source == null)
|
||||||
|
{
|
||||||
|
errorMessages.Add($"{app.Name} has an invalid source: {sourceId}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var typeConfig = _globalConfig.Types.FirstOrDefault(t => t.ShortName == app.Type);
|
||||||
|
if (typeConfig == null)
|
||||||
|
{
|
||||||
|
errorMessages.Add($"{app.Name} has no valid type config.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
app.CurrentVersion = VersionUtils.GetCurrentVersion(app, typeConfig);
|
||||||
|
|
||||||
|
var updatedApp = CheckApp(app);
|
||||||
|
if (updatedApp.Status == AppStatus.UPDATE_AVAILABLE)
|
||||||
|
{
|
||||||
|
updateMessages.Add($"{app.Name}: New version {app.LatestVersion} (current: {app.CurrentVersion})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
errorMessages.Add($"Failed to check {app.Name}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateMessages.Count > 0)
|
||||||
|
{
|
||||||
|
_notifyIconService.ShowBalloonTip(
|
||||||
|
10000,
|
||||||
|
"Updates Available",
|
||||||
|
string.Join("\n", updateMessages),
|
||||||
|
ToolTipIcon.Info
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (errorMessages.Count > 0)
|
||||||
|
{
|
||||||
|
_notifyIconService.ShowBalloonTip(
|
||||||
|
10000,
|
||||||
|
"Errors",
|
||||||
|
string.Join("\n", errorMessages),
|
||||||
|
ToolTipIcon.Error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isUpdateAvailable(string currentVersion, string latestVersion)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var current = NuGetVersion.Parse(currentVersion);
|
||||||
|
var latest = NuGetVersion.Parse(latestVersion);
|
||||||
|
return latest.CompareTo(current) == 1;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to compare versions: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
ModVersionChecker/service/interfaces/IApiService.cs
Normal file
19
ModVersionChecker/service/interfaces/IApiService.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using NuGet.Versioning;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.service.interfaces
|
||||||
|
{
|
||||||
|
public interface IApiService
|
||||||
|
{
|
||||||
|
Task<List<AppVersionsResponse>> GetAppVersionsAsync(List<App> apps);
|
||||||
|
Task<List<TypeResponse>> GetTypes();
|
||||||
|
Task<List<SourceResponse>> GetSources();
|
||||||
|
Task<AppVersionsResponse?> GetAppLatestVersionAsync(App app);
|
||||||
|
Task<bool> AuthenticateAsync(string username, string password);
|
||||||
|
Task<List<App>> GetAppsByIds(App[] apps);
|
||||||
|
Task<List<App>?> SearchApps(string searchText);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace ModVersionChecker.managers.interfaces
|
namespace ModVersionChecker.service.interfaces
|
||||||
{
|
{
|
||||||
public interface INotifyIconService
|
public interface INotifyIconService
|
||||||
{
|
{
|
15
ModVersionChecker/service/interfaces/IVersionService.cs
Normal file
15
ModVersionChecker/service/interfaces/IVersionService.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.service.interfaces
|
||||||
|
{
|
||||||
|
public interface IVersionService
|
||||||
|
{
|
||||||
|
App CheckApp(App app);
|
||||||
|
|
||||||
|
Task CheckAllApps();
|
||||||
|
}
|
||||||
|
}
|
58
ModVersionChecker/ui/controls/DirectoryPickerControl.cs
Normal file
58
ModVersionChecker/ui/controls/DirectoryPickerControl.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.controls
|
||||||
|
{
|
||||||
|
public class DirectoryPickerControl : UserControl
|
||||||
|
{
|
||||||
|
private readonly TextBox _textBox;
|
||||||
|
private readonly Button _browseButton;
|
||||||
|
|
||||||
|
public string SelectedPath
|
||||||
|
{
|
||||||
|
get => _textBox.Text;
|
||||||
|
set => _textBox.Text = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryPickerControl()
|
||||||
|
{
|
||||||
|
_textBox = new TextBox
|
||||||
|
{
|
||||||
|
Width = 300,
|
||||||
|
ReadOnly = true,
|
||||||
|
Dock = DockStyle.Fill
|
||||||
|
};
|
||||||
|
|
||||||
|
_browseButton = new Button
|
||||||
|
{
|
||||||
|
Text = "Browse",
|
||||||
|
Width = 80,
|
||||||
|
Dock = DockStyle.Right
|
||||||
|
};
|
||||||
|
|
||||||
|
_browseButton.Click += (s, e) =>
|
||||||
|
{
|
||||||
|
using var folderDialog = new FolderBrowserDialog();
|
||||||
|
folderDialog.Description = "Select directory";
|
||||||
|
if (folderDialog.ShowDialog() == DialogResult.OK)
|
||||||
|
{
|
||||||
|
SelectedPath = folderDialog.SelectedPath;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var panel = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
ColumnCount = 2,
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
AutoSize = true
|
||||||
|
};
|
||||||
|
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 80));
|
||||||
|
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20));
|
||||||
|
panel.Controls.Add(_textBox, 0, 0);
|
||||||
|
panel.Controls.Add(_browseButton, 1, 0);
|
||||||
|
|
||||||
|
Controls.Add(panel);
|
||||||
|
AutoSize = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
ModVersionChecker/ui/forms/AppDetailsForm.cs
Normal file
74
ModVersionChecker/ui/forms/AppDetailsForm.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.ui.forms
|
||||||
|
{
|
||||||
|
public class AppDetailsForm : Form
|
||||||
|
{
|
||||||
|
private TextBox _searchBox;
|
||||||
|
private ListBox _resultsList;
|
||||||
|
private Button _addButton;
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
private readonly IAppsManager _appsManager;
|
||||||
|
public App? SelectedApp { get; private set; }
|
||||||
|
|
||||||
|
public event EventHandler<string> OnAppAdded;
|
||||||
|
|
||||||
|
public AppDetailsForm(IApiService apiService, IAppsManager appsManager)
|
||||||
|
{
|
||||||
|
_apiService = apiService ?? throw new ArgumentNullException(nameof(apiService));
|
||||||
|
_appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager));
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
Text = "Search and Add App";
|
||||||
|
Width = 400;
|
||||||
|
Height = 500;
|
||||||
|
Padding = new Padding(20);
|
||||||
|
|
||||||
|
_searchBox = new TextBox { Dock = DockStyle.Top, PlaceholderText = "Search..." };
|
||||||
|
_resultsList = new ListBox { Dock = DockStyle.Fill };
|
||||||
|
_addButton = new Button { Text = "Add Selected", Dock = DockStyle.Bottom, Enabled = false };
|
||||||
|
|
||||||
|
_searchBox.TextChanged += async (s, e) => await UpdateResultsAync();
|
||||||
|
_resultsList.SelectedIndexChanged += (s, e) => _addButton.Enabled = _resultsList.SelectedItem != null;
|
||||||
|
_resultsList.DoubleClick += (s, e) => AddSelected();
|
||||||
|
_addButton.Click += (s, e) => AddSelected();
|
||||||
|
|
||||||
|
Controls.Add(_resultsList);
|
||||||
|
Controls.Add(_addButton);
|
||||||
|
Controls.Add(_searchBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateResultsAync()
|
||||||
|
{
|
||||||
|
var query = _searchBox.Text.Trim().ToLower();
|
||||||
|
if (query.Length < 3)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(query))
|
||||||
|
{
|
||||||
|
_resultsList.DataSource = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var results = await _apiService.SearchApps(query);
|
||||||
|
_resultsList.DataSource = results;
|
||||||
|
_resultsList.DisplayMember = "Name";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddSelected()
|
||||||
|
{
|
||||||
|
if (_resultsList.SelectedItem is App app)
|
||||||
|
{
|
||||||
|
SelectedApp = app;
|
||||||
|
_appsManager.Insert(app);
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
OnAppAdded?.Invoke(this, "App saved");
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
ModVersionChecker/ui/forms/FormFactory.cs
Normal file
70
ModVersionChecker/ui/forms/FormFactory.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.ui.forms
|
||||||
|
{
|
||||||
|
public class FormFactory : IFormFactory
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public FormFactory(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppDetailsForm CreateAppDetailsForm(App? app, bool isEditable, EventHandler<string>? onAppSaved)
|
||||||
|
{
|
||||||
|
var apiService = _serviceProvider.GetRequiredService<IApiService>();
|
||||||
|
var appsManager = _serviceProvider.GetRequiredService<IAppsManager>();
|
||||||
|
var form = new AppDetailsForm(apiService, appsManager);
|
||||||
|
if (onAppSaved != null)
|
||||||
|
{
|
||||||
|
form.OnAppAdded += onAppSaved;
|
||||||
|
}
|
||||||
|
return form;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalConfigForm CreateGlobalConfigForm()
|
||||||
|
{
|
||||||
|
var configManager = _serviceProvider.GetRequiredService<IConfigManager>();
|
||||||
|
return new GlobalConfigForm(configManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeConfigForm CreateTypeConfigForm()
|
||||||
|
{
|
||||||
|
var typeManager = _serviceProvider.GetRequiredService<ITypeManager>();
|
||||||
|
var apiService = _serviceProvider.GetRequiredService<IApiService>();
|
||||||
|
var configManager = _serviceProvider.GetRequiredService<IConfigManager>();
|
||||||
|
return new TypeConfigForm(typeManager, apiService, configManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
//public SourcesConfigForm CreateSourcesConfigForm(EventHandler<string>? onSourcesChanged)
|
||||||
|
//{
|
||||||
|
// var sourcesDefManager = _serviceProvider.GetRequiredService<ISourcesDefManager>();
|
||||||
|
// var formFactory = _serviceProvider.GetRequiredService<IFormFactory>();
|
||||||
|
// var form = new SourcesConfigForm(formFactory, sourcesDefManager);
|
||||||
|
// if (onSourcesChanged != null)
|
||||||
|
// {
|
||||||
|
// form.OnSourcesChanged += onSourcesChanged;
|
||||||
|
// }
|
||||||
|
// return form;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public SourceDetailForm CreateSourceDetailForm(SourceDef? sourceDef, EventHandler<string>? onSourceChanged)
|
||||||
|
//{
|
||||||
|
// var sourcesDefManager = _serviceProvider.GetRequiredService<ISourcesDefManager>();
|
||||||
|
// var checkerTypesDefManager = _serviceProvider.GetRequiredService<ICheckerTypesDefManager>();
|
||||||
|
// var formFactory = _serviceProvider.GetRequiredService<IFormFactory>();
|
||||||
|
// var form = new SourceDetailForm(formFactory, sourcesDefManager);
|
||||||
|
// form.SourceDef = sourceDef;
|
||||||
|
|
||||||
|
// if (onSourceChanged != null)
|
||||||
|
// {
|
||||||
|
// form.UpdateFields();
|
||||||
|
// form.OnSourceChanged += onSourceChanged;
|
||||||
|
// }
|
||||||
|
// return form;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,12 +1,12 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.managers.interfaces;
|
||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.model;
|
||||||
|
|
||||||
namespace ModVersionChecker.forms
|
namespace ModVersionChecker.ui.forms
|
||||||
{
|
{
|
||||||
public class GlobalConfigForm : Form
|
public class GlobalConfigForm : Form
|
||||||
{
|
{
|
||||||
private IConfigManager _configManager;
|
private IConfigManager _configManager;
|
||||||
private GlobalConfig _config;
|
private Config _config;
|
||||||
|
|
||||||
private Label _millislabel, _checkStartupLabel, _runOnStartupLabel;
|
private Label _millislabel, _checkStartupLabel, _runOnStartupLabel;
|
||||||
private TrackBar _millisField;
|
private TrackBar _millisField;
|
||||||
@@ -19,8 +19,17 @@ namespace ModVersionChecker.forms
|
|||||||
{
|
{
|
||||||
_configManager = configManager;
|
_configManager = configManager;
|
||||||
_config = _configManager.GetConfig();
|
_config = _configManager.GetConfig();
|
||||||
InitializeComponent();
|
this.Load += GlobalConfigForm_Load;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GlobalConfigForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Load existing configurations if needed
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
SuspendLayout();
|
SuspendLayout();
|
14
ModVersionChecker/ui/forms/IFormFactory.cs
Normal file
14
ModVersionChecker/ui/forms/IFormFactory.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
namespace ModVersionChecker.ui.forms
|
||||||
|
{
|
||||||
|
public interface IFormFactory
|
||||||
|
{
|
||||||
|
AppDetailsForm CreateAppDetailsForm(App? app, bool isEditable, EventHandler<string>? onAppChanged);
|
||||||
|
GlobalConfigForm CreateGlobalConfigForm();
|
||||||
|
TypeConfigForm CreateTypeConfigForm();
|
||||||
|
|
||||||
|
//SourcesConfigForm CreateSourcesConfigForm(EventHandler<string>? onSourcesChanged);
|
||||||
|
|
||||||
|
//SourceDetailForm CreateSourceDetailForm(SourceDef? sourceDef, EventHandler<string>? onSourceChanged);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,43 +1,51 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.enums;
|
||||||
using ModVersionChecker.managers.interfaces;
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.model;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
using ModVersionChecker.utils;
|
using ModVersionChecker.utils;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Intrinsics.Arm;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
|
|
||||||
namespace ModVersionChecker.forms
|
namespace ModVersionChecker.ui.forms
|
||||||
{
|
{
|
||||||
public class MainForm : Form
|
public class MainForm : Form
|
||||||
{
|
{
|
||||||
private readonly IConfigManager _configManager;
|
|
||||||
private readonly IAppsManager _appsManager;
|
private readonly IAppsManager _appsManager;
|
||||||
private readonly IFormFactory _formFactory;
|
private readonly IFormFactory _formFactory;
|
||||||
private readonly IAppStatusManager _appStatusManager;
|
|
||||||
private readonly IFlightSimsManager _fsManager;
|
private readonly IFlightSimsManager _fsManager;
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
private readonly IVersionService _versionService;
|
||||||
private readonly TableLayoutPanel _mainLayout;
|
private readonly TableLayoutPanel _mainLayout;
|
||||||
|
|
||||||
private readonly GlobalConfig _globalConfig;
|
private readonly Config _globalConfig;
|
||||||
private List<AppConfig> _apps = new List<AppConfig>();
|
private List<App> _apps = new List<App>();
|
||||||
private ListView _listView;
|
private ListView _listView;
|
||||||
private ImageList _statusImageList = new ImageList();
|
private ImageList _statusImageList = new ImageList();
|
||||||
|
|
||||||
public event EventHandler<EventArgs> OnConfigChanged;
|
public event EventHandler<EventArgs> OnConfigChanged;
|
||||||
public event EventHandler<string> OnRecheck;
|
public event EventHandler<string> OnRecheck;
|
||||||
private EventHandler<string> onAppChangedHandler;
|
private EventHandler<string> onAppSavedHandler;
|
||||||
private MenuStrip _menuStrip;
|
private MenuStrip _menuStrip;
|
||||||
private List<FsModPathConfig> _fsMods;
|
private List<TypeResponse> _fsMods;
|
||||||
private readonly Dictionary<string, TextBox> _fsModPathTextBoxes = new Dictionary<string, TextBox>();
|
private readonly Dictionary<string, TextBox> _fsModPathTextBoxes = new Dictionary<string, TextBox>();
|
||||||
|
|
||||||
public MainForm(IConfigManager configManager, IAppsManager appsManager, IFormFactory formFactory, IAppStatusManager appStatusManager, IFlightSimsManager fsManager)
|
private List<SourceResponse> _sources = new List<SourceResponse>();
|
||||||
|
private List<TypeResponse> _typesDef = new List<TypeResponse>();
|
||||||
|
|
||||||
|
public MainForm(
|
||||||
|
IConfigManager configManager,
|
||||||
|
IAppsManager appsManager,
|
||||||
|
IFormFactory formFactory,
|
||||||
|
IFlightSimsManager fsManager,
|
||||||
|
IApiService apiService,
|
||||||
|
ITypeManager typeConfigManager,
|
||||||
|
IVersionService versionService)
|
||||||
{
|
{
|
||||||
_configManager = configManager ?? throw new ArgumentNullException(nameof(configManager));
|
|
||||||
_appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager));
|
_appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager));
|
||||||
_formFactory = formFactory ?? throw new ArgumentNullException(nameof(formFactory));
|
_formFactory = formFactory ?? throw new ArgumentNullException(nameof(formFactory));
|
||||||
_appStatusManager = appStatusManager ?? throw new ArgumentNullException(nameof(appStatusManager));
|
|
||||||
_fsManager = fsManager ?? throw new ArgumentNullException(nameof(fsManager));
|
_fsManager = fsManager ?? throw new ArgumentNullException(nameof(fsManager));
|
||||||
|
_apiService = apiService ?? throw new ArgumentNullException(nameof(apiService));
|
||||||
|
_versionService = versionService ?? throw new ArgumentNullException(nameof(versionService));
|
||||||
_fsMods = _fsManager.Load();
|
_fsMods = _fsManager.Load();
|
||||||
|
|
||||||
_statusImageList.Images.Add("none", new Icon("Resources/ok-icon.ico"));
|
_statusImageList.Images.Add("none", new Icon("Resources/ok-icon.ico"));
|
||||||
@@ -48,26 +56,55 @@ namespace ModVersionChecker.forms
|
|||||||
Size = new Size(600, 800);
|
Size = new Size(600, 800);
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
|
||||||
_globalConfig = configManager.Load() ?? new GlobalConfig();
|
_globalConfig = configManager.Load() ?? new Config();
|
||||||
|
|
||||||
_mainLayout = GetMainLayout();
|
_mainLayout = GetMainLayout();
|
||||||
|
|
||||||
_mainLayout.Controls.Add(GetPathsPanel(), 0, 0);
|
|
||||||
|
|
||||||
_listView = GetListView();
|
_listView = GetListView();
|
||||||
_listView.SmallImageList = _statusImageList;
|
_listView.SmallImageList = _statusImageList;
|
||||||
|
|
||||||
_mainLayout.Controls.Add(_listView , 0, 1);
|
_mainLayout.Controls.Add(_listView , 0, 0);
|
||||||
|
|
||||||
_mainLayout.Controls.Add(GetButtonsPanel(), 0, 2);
|
_mainLayout.Controls.Add(GetButtonsPanel(), 0, 1);
|
||||||
|
|
||||||
onAppChangedHandler = (s2, e) =>
|
onAppSavedHandler = (s2, e) =>
|
||||||
{
|
{
|
||||||
|
var form = s2 as AppDetailsForm;
|
||||||
|
if (form == null || form.SelectedApp == null) return;
|
||||||
|
|
||||||
|
var app = form.SelectedApp;
|
||||||
|
UpdateCurrentVersion(app);
|
||||||
UpdateListView();
|
UpdateListView();
|
||||||
OnConfigChanged?.Invoke(this, EventArgs.Empty);
|
OnConfigChanged?.Invoke(this, EventArgs.Empty);
|
||||||
};
|
};
|
||||||
|
|
||||||
InitializeMenu();
|
this.Load += MainForm_LoadAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCurrentVersion(App app)
|
||||||
|
{
|
||||||
|
TypeConfig? typeConfig = _globalConfig.Types.FirstOrDefault(tc => app.Type == tc.ShortName);
|
||||||
|
if (typeConfig == null) return;
|
||||||
|
var versionInDisk = VersionUtils.GetCurrentVersion(app, typeConfig);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(versionInDisk))
|
||||||
|
{
|
||||||
|
app.CurrentVersion = versionInDisk;
|
||||||
|
app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(DateTime.Now);
|
||||||
|
|
||||||
|
_versionService.CheckApp(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async void MainForm_LoadAsync(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
await _apiService.AuthenticateAsync("user", "user");
|
||||||
|
_apps = await _apiService.GetAppsByIds([]);
|
||||||
|
_sources = await _apiService.GetSources();
|
||||||
|
_typesDef = await _apiService.GetTypes();
|
||||||
|
UpdateListView();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TableLayoutPanel GetMainLayout()
|
private TableLayoutPanel GetMainLayout()
|
||||||
@@ -76,50 +113,17 @@ namespace ModVersionChecker.forms
|
|||||||
var mainLayout = new TableLayoutPanel
|
var mainLayout = new TableLayoutPanel
|
||||||
{
|
{
|
||||||
Dock = DockStyle.Fill,
|
Dock = DockStyle.Fill,
|
||||||
RowCount = 3,
|
RowCount = 2,
|
||||||
ColumnCount = 1
|
ColumnCount = 1
|
||||||
};
|
};
|
||||||
mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 150)); // Paths panel height
|
// mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 150)); // Paths panel height
|
||||||
mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 70)); // ListView takes remaining space
|
mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 70)); // ListView takes remaining space
|
||||||
mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 50)); // Button panel height
|
mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 50)); // Button panel height
|
||||||
Controls.Add(mainLayout);
|
Controls.Add(mainLayout);
|
||||||
|
InitializeMenu();
|
||||||
return mainLayout;
|
return mainLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FlowLayoutPanel GetPathsPanel()
|
|
||||||
{
|
|
||||||
var pathPanel = new FlowLayoutPanel { Dock = DockStyle.Fill, FlowDirection = FlowDirection.TopDown };
|
|
||||||
|
|
||||||
foreach (var fsMod in _fsMods)
|
|
||||||
{
|
|
||||||
var singlePathPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.LeftToRight, AutoSize = true };
|
|
||||||
singlePathPanel.Controls.Add(new Label { Text = $"{fsMod.Name} Path:", Width = 100 });
|
|
||||||
var pathField = new TextBox { Text = fsMod.Path ?? "", Width = 300 };
|
|
||||||
singlePathPanel.Controls.Add(pathField);
|
|
||||||
_fsModPathTextBoxes.Add(fsMod.ShortName, pathField);
|
|
||||||
pathPanel.Controls.Add(singlePathPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
//var pathPanel2024 = new FlowLayoutPanel { FlowDirection = FlowDirection.LeftToRight, AutoSize = true };
|
|
||||||
//pathPanel2024.Controls.Add(new Label { Text = "MSFS 2024 Path:", Width = 100 });
|
|
||||||
//var msfs2024PathField = new TextBox { Text = _globalConfig.FsModPaths.ContainsKey("msfs2024") ? _globalConfig.FsModPaths["msfs2024"].Path : "", Width = 300 };
|
|
||||||
//pathPanel2024.Controls.Add(msfs2024PathField);
|
|
||||||
//pathPanel.Controls.Add(pathPanel2024);
|
|
||||||
|
|
||||||
var savePathsButton = new Button { Text = "Save Paths" };
|
|
||||||
savePathsButton.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
foreach (var fsMod in _fsMods)
|
|
||||||
{
|
|
||||||
fsMod.Path = _fsModPathTextBoxes[fsMod.ShortName].Text;
|
|
||||||
_fsManager.Save(fsMod);
|
|
||||||
}
|
|
||||||
_fsMods = _fsManager.Load();
|
|
||||||
};
|
|
||||||
pathPanel.Controls.Add(savePathsButton);
|
|
||||||
return pathPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ListView GetListView()
|
private ListView GetListView()
|
||||||
{
|
{
|
||||||
var listView = new ListView
|
var listView = new ListView
|
||||||
@@ -143,9 +147,9 @@ namespace ModVersionChecker.forms
|
|||||||
if (listView.SelectedItems.Count > 0)
|
if (listView.SelectedItems.Count > 0)
|
||||||
{
|
{
|
||||||
ListViewItem selectedItem = listView.SelectedItems[0];
|
ListViewItem selectedItem = listView.SelectedItems[0];
|
||||||
AppConfig? app = selectedItem.Tag as AppConfig;
|
App? app = selectedItem.Tag as App;
|
||||||
if (app == null) return;
|
if (app == null) return;
|
||||||
if (_appStatusManager.GetAppStatus(app.Id) == AppStatus.UpdateAvailable)
|
if (app.Status == AppStatus.UPDATE_AVAILABLE)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(app.DownloadUrl))
|
if (string.IsNullOrEmpty(app.DownloadUrl))
|
||||||
{
|
{
|
||||||
@@ -159,14 +163,7 @@ namespace ModVersionChecker.forms
|
|||||||
});
|
});
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
var form = _formFactory.CreateAppDetailsForm(app, true, onAppChangedHandler);
|
|
||||||
form.FormClosed += (s2, e) =>
|
|
||||||
{
|
|
||||||
UpdateListView();
|
|
||||||
};
|
|
||||||
UpdateListView();
|
|
||||||
form.ShowDialog();
|
|
||||||
form.BringToFront();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -178,49 +175,38 @@ namespace ModVersionChecker.forms
|
|||||||
private FlowLayoutPanel GetButtonsPanel() {
|
private FlowLayoutPanel GetButtonsPanel() {
|
||||||
var buttonPanel = new FlowLayoutPanel { Dock = DockStyle.Fill };
|
var buttonPanel = new FlowLayoutPanel { Dock = DockStyle.Fill };
|
||||||
var addButton = new Button { Text = "Add App" };
|
var addButton = new Button { Text = "Add App" };
|
||||||
var editButton = new Button { Text = "Edit App", Enabled = false };
|
|
||||||
var deleteButton = new Button { Text = "Delete App", Enabled = false };
|
var deleteButton = new Button { Text = "Delete App", Enabled = false };
|
||||||
var recheckButton = new Button { Text = "Recheck Versions" };
|
var recheckButton = new Button { Text = "Recheck Versions" };
|
||||||
|
|
||||||
addButton.Click += (s, e) =>
|
addButton.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
var form = _formFactory.CreateAppDetailsForm(null, true, onAppChangedHandler); // Use factory
|
var form = _formFactory.CreateAppDetailsForm(null, true, onAppSavedHandler); // Use factory
|
||||||
form.ShowDialog();
|
form.ShowDialog();
|
||||||
};
|
};
|
||||||
editButton.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
if (_listView.SelectedItems.Count > 0)
|
|
||||||
{
|
|
||||||
ListViewItem selectedItem = _listView.SelectedItems[0];
|
|
||||||
AppConfig app = selectedItem.Tag as AppConfig;
|
|
||||||
var form = _formFactory.CreateAppDetailsForm(app, true, onAppChangedHandler); // Use factory
|
|
||||||
form.ShowDialog();
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
deleteButton.Click += (s, e) =>
|
deleteButton.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
if (_listView.SelectedItems.Count > 0 && _listView.SelectedItems[0].Tag != null)
|
if (_listView.SelectedItems.Count > 0 && _listView.SelectedItems[0].Tag != null)
|
||||||
{
|
{
|
||||||
_appsManager.Delete((_listView.SelectedItems[0].Tag as AppConfig).Id);
|
var app = _listView.SelectedItems[0].Tag as App;
|
||||||
UpdateListView();
|
DeleteApp(app);
|
||||||
OnConfigChanged?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
_listView.SelectedIndexChanged += (s, e) =>
|
_listView.SelectedIndexChanged += (s, e) =>
|
||||||
{
|
{
|
||||||
editButton.Enabled = deleteButton.Enabled = _listView.SelectedItems.Count > 0;
|
deleteButton.Enabled = _listView.SelectedItems.Count > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add recheck logic here
|
// Add recheck logic here
|
||||||
recheckButton.Click += async (s, e) =>
|
recheckButton.Click += async (s, e) =>
|
||||||
{
|
{
|
||||||
recheckButton.Enabled = false;
|
recheckButton.Enabled = false;
|
||||||
OnRecheck.Invoke(this, "User initiated recheck from ConfigForm");
|
await _versionService.CheckAllApps();
|
||||||
|
UpdateListView();
|
||||||
|
//OnRecheck.Invoke(this, "User initiated recheck from ConfigForm");
|
||||||
recheckButton.Enabled = true;
|
recheckButton.Enabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
buttonPanel.Controls.AddRange(new[] { addButton, editButton, deleteButton, recheckButton });
|
buttonPanel.Controls.AddRange(new[] { addButton, deleteButton, recheckButton });
|
||||||
return buttonPanel;
|
return buttonPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,12 +217,10 @@ namespace ModVersionChecker.forms
|
|||||||
foreach (var app in _apps)
|
foreach (var app in _apps)
|
||||||
{
|
{
|
||||||
var item = new ListViewItem(app.Name);
|
var item = new ListViewItem(app.Name);
|
||||||
|
try {
|
||||||
item.Tag = app;
|
item.Tag = app;
|
||||||
item.SubItems.Add(string.Join(", ", app.MsfsVersions));
|
item.SubItems.Add(app.Type);
|
||||||
try
|
|
||||||
{
|
|
||||||
var fsMod = _fsMods.FirstOrDefault(fs => fs.ShortName == "msfs2024");
|
|
||||||
// Pass the FsModPathConfig object directly, not its Path property
|
|
||||||
var currentVersion = app.CurrentVersion;
|
var currentVersion = app.CurrentVersion;
|
||||||
var latestVersion = app.LatestVersion;
|
var latestVersion = app.LatestVersion;
|
||||||
var lastChecked = TimeUtils.ToFriendlyTime(app.LastCheckedAt);
|
var lastChecked = TimeUtils.ToFriendlyTime(app.LastCheckedAt);
|
||||||
@@ -248,12 +232,13 @@ namespace ModVersionChecker.forms
|
|||||||
{
|
{
|
||||||
item.SubItems.Add($"Error: {ex.Message}");
|
item.SubItems.Add($"Error: {ex.Message}");
|
||||||
}
|
}
|
||||||
switch (_appStatusManager.GetAppStatus(app.Id))
|
|
||||||
|
switch (app.Status)
|
||||||
{
|
{
|
||||||
case AppStatus.UpdateAvailable:
|
case AppStatus.UPDATE_AVAILABLE:
|
||||||
item.ImageKey = "update";
|
item.ImageKey = "update";
|
||||||
break;
|
break;
|
||||||
case AppStatus.Error:
|
case AppStatus.ERROR:
|
||||||
item.ImageKey = "error";
|
item.ImageKey = "error";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -261,8 +246,19 @@ namespace ModVersionChecker.forms
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_listView.Items.Add(item);
|
_listView.Items.Add(item);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteApp(App app)
|
||||||
|
{
|
||||||
|
var result = MessageBox.Show($"Are you sure you want to delete '{app?.Name ?? ""}'?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||||
|
if (result == DialogResult.Yes)
|
||||||
|
{
|
||||||
|
_appsManager.Delete((_listView.SelectedItems[0].Tag as App).Id);
|
||||||
|
UpdateListView();
|
||||||
|
OnConfigChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
Console.WriteLine($"UpdateListView item count: {_listView.Items.Count}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeMenu()
|
private void InitializeMenu()
|
||||||
@@ -273,18 +269,22 @@ namespace ModVersionChecker.forms
|
|||||||
var configMenu = new ToolStripMenuItem("Configuration");
|
var configMenu = new ToolStripMenuItem("Configuration");
|
||||||
|
|
||||||
// Add sub-menu items
|
// Add sub-menu items
|
||||||
var globalConfigItem = new ToolStripMenuItem("Global Settings");
|
var settingsItem = new ToolStripMenuItem("Settings");
|
||||||
globalConfigItem.Click += (s, e) => ShowGlobalConfigDialog();
|
settingsItem.Click += (s, e) => ShowGlobalConfigDialog();
|
||||||
|
|
||||||
var sourcesConfigItem = new ToolStripMenuItem("Sources");
|
var typesItem = new ToolStripMenuItem("Types");
|
||||||
sourcesConfigItem.Click += (s, e) => ShowSourcesConfigDialog();
|
typesItem.Click += (s, e) => ShowTypesConfigForm();
|
||||||
|
|
||||||
var FlightSimsConfigItem = new ToolStripMenuItem("Flight Sims");
|
//var sourcesConfigItem = new ToolStripMenuItem("Sources");
|
||||||
FlightSimsConfigItem.Click += (s, e) => MessageBox.Show("Flight Sims configuration dialog would open here.");
|
//sourcesConfigItem.Click += (s, e) => ShowSourcesConfigDialog();
|
||||||
|
|
||||||
configMenu.DropDownItems.Add(globalConfigItem);
|
//var FlightSimsConfigItem = new ToolStripMenuItem("Flight Sims");
|
||||||
configMenu.DropDownItems.Add(sourcesConfigItem);
|
//FlightSimsConfigItem.Click += (s, e) => MessageBox.Show("Flight Sims configuration dialog would open here.");
|
||||||
configMenu.DropDownItems.Add(FlightSimsConfigItem);
|
|
||||||
|
configMenu.DropDownItems.Add(settingsItem);
|
||||||
|
configMenu.DropDownItems.Add(typesItem);
|
||||||
|
// configMenu.DropDownItems.Add(sourcesConfigItem);
|
||||||
|
// configMenu.DropDownItems.Add(FlightSimsConfigItem);
|
||||||
|
|
||||||
_menuStrip.Items.Add(configMenu);
|
_menuStrip.Items.Add(configMenu);
|
||||||
|
|
||||||
@@ -293,6 +293,12 @@ namespace ModVersionChecker.forms
|
|||||||
MainMenuStrip = _menuStrip;
|
MainMenuStrip = _menuStrip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShowTypesConfigForm()
|
||||||
|
{
|
||||||
|
var typesConfigForm = _formFactory.CreateTypeConfigForm();
|
||||||
|
typesConfigForm.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowGlobalConfigDialog()
|
private void ShowGlobalConfigDialog()
|
||||||
{
|
{
|
||||||
// Show your global config form/dialog here
|
// Show your global config form/dialog here
|
||||||
@@ -300,11 +306,11 @@ namespace ModVersionChecker.forms
|
|||||||
globalConfigForm.ShowDialog();
|
globalConfigForm.ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowSourcesConfigDialog()
|
//private void ShowSourcesConfigDialog()
|
||||||
{
|
//{
|
||||||
EventHandler<string> onSourcesChanged = (s, e) => MessageBox.Show("Sources Changed");
|
// EventHandler<string> onSourcesChanged = (s, e) => MessageBox.Show("Sources Changed");
|
||||||
var form = _formFactory.CreateSourcesConfigForm(onSourcesChanged);
|
// var form = _formFactory.CreateSourcesConfigForm(onSourcesChanged);
|
||||||
form.ShowDialog();
|
// form.ShowDialog();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
145
ModVersionChecker/ui/forms/TypeConfigForm.cs
Normal file
145
ModVersionChecker/ui/forms/TypeConfigForm.cs
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
using ModVersionChecker.controls;
|
||||||
|
using ModVersionChecker.managers.interfaces;
|
||||||
|
using ModVersionChecker.model;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using ModVersionChecker.service.interfaces;
|
||||||
|
using ModVersionChecker.utils;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.ui.forms
|
||||||
|
{
|
||||||
|
public class TypeConfigForm : Form
|
||||||
|
{
|
||||||
|
private List<TypeResponse> _typeDefs;
|
||||||
|
private List<TypeConfig> _typeConfigs;
|
||||||
|
private Config _globalConfig;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, CheckBox> _typeCheckBoxes = new();
|
||||||
|
private readonly Dictionary<string, Panel> _typePanels = new();
|
||||||
|
private readonly Dictionary<(string typeId, string fieldName), Control> _fieldControls = new();
|
||||||
|
private FlowLayoutPanel _mainPanel;
|
||||||
|
private Button _saveButton, _cancelButton;
|
||||||
|
private readonly IApiService _apiService;
|
||||||
|
private readonly IConfigManager _configManager;
|
||||||
|
private readonly ITypeManager _typeManager;
|
||||||
|
|
||||||
|
public TypeConfigForm(
|
||||||
|
ITypeManager typeManager,
|
||||||
|
IApiService apiService,
|
||||||
|
IConfigManager configManager
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_apiService = apiService ?? throw new ArgumentNullException(nameof(apiService));
|
||||||
|
_configManager = configManager ?? throw new ArgumentNullException(nameof(configManager));
|
||||||
|
_typeManager = typeManager ?? throw new ArgumentNullException(nameof(typeManager));
|
||||||
|
Load += TypeConfigForm_LoadAsync;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void TypeConfigForm_LoadAsync(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_typeDefs = await _apiService.GetTypes();
|
||||||
|
_typeConfigs = _typeManager.GetTypeConfigs();
|
||||||
|
_globalConfig = _configManager.Load();
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
Text = "Configure Types";
|
||||||
|
Width = 600;
|
||||||
|
Height = 700;
|
||||||
|
StartPosition = FormStartPosition.CenterParent;
|
||||||
|
_mainPanel = new FlowLayoutPanel { Dock = DockStyle.Top, AutoScroll = true, FlowDirection = FlowDirection.TopDown, WrapContents = false, Width = 580, Height = 600 };
|
||||||
|
|
||||||
|
foreach (var typeDef in _typeDefs)
|
||||||
|
{
|
||||||
|
var isInConfig = _globalConfig.Types.Any(t => t.Id == typeDef.Id);
|
||||||
|
var typeConfig = _globalConfig.Types.FirstOrDefault(tc => tc.Id == typeDef.Id);
|
||||||
|
var checkBox = new CheckBox {
|
||||||
|
Text = typeDef.Name,
|
||||||
|
Checked = isInConfig,
|
||||||
|
Enabled = !isInConfig,
|
||||||
|
AutoSize = true
|
||||||
|
};
|
||||||
|
_typeCheckBoxes[typeDef.Id] = checkBox;
|
||||||
|
var panel = new Panel {
|
||||||
|
Visible = checkBox.Checked,
|
||||||
|
AutoSize = false,
|
||||||
|
BorderStyle = BorderStyle.FixedSingle,
|
||||||
|
Width = _mainPanel.Width - 20, // leave some margin
|
||||||
|
Height = 0 // will be set by content
|
||||||
|
};
|
||||||
|
_typePanels[typeDef.Id] = panel;
|
||||||
|
|
||||||
|
checkBox.CheckedChanged += (s, e) => { panel.Visible = checkBox.Checked; };
|
||||||
|
|
||||||
|
var fieldsLayout = new TableLayoutPanel {
|
||||||
|
ColumnCount = 2,
|
||||||
|
AutoSize = true,
|
||||||
|
Dock = DockStyle.Top
|
||||||
|
};
|
||||||
|
foreach (var field in typeDef.ConfigFields)
|
||||||
|
{
|
||||||
|
fieldsLayout.RowCount++;
|
||||||
|
fieldsLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
||||||
|
fieldsLayout.Controls.Add(new Label {
|
||||||
|
Text = $"{field.Label ?? field.Name} {field.ControlType}",
|
||||||
|
AutoSize = true
|
||||||
|
}, 0, fieldsLayout.RowCount - 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var filedInput = InputControlsFactory.CreateControl(field, typeConfig, !isInConfig);
|
||||||
|
_fieldControls[(typeDef.Id, field.Name)] = filedInput;
|
||||||
|
fieldsLayout.Controls.Add(filedInput, 1, fieldsLayout.RowCount - 1);
|
||||||
|
}
|
||||||
|
panel.Controls.Add(fieldsLayout);
|
||||||
|
panel.Height = fieldsLayout.PreferredSize.Height + 10;
|
||||||
|
_mainPanel.Controls.Add(checkBox);
|
||||||
|
_mainPanel.Controls.Add(panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveButton = new Button { Text = "Save", AutoSize = true };
|
||||||
|
_saveButton.Click += (s, e) => { SaveConfigs(); };
|
||||||
|
_cancelButton = new Button { Text = "Cancel", AutoSize = true };
|
||||||
|
_cancelButton.Click += (s, e) => { DialogResult = DialogResult.Cancel; Close(); };
|
||||||
|
var buttonPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.RightToLeft, Dock = DockStyle.Bottom, AutoSize = true };
|
||||||
|
buttonPanel.Controls.Add(_saveButton);
|
||||||
|
buttonPanel.Controls.Add(_cancelButton);
|
||||||
|
|
||||||
|
Controls.Add(_mainPanel);
|
||||||
|
Controls.Add(buttonPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveConfigs()
|
||||||
|
{
|
||||||
|
var result = new List<TypeConfig>();
|
||||||
|
foreach (var typeDef in _typeDefs)
|
||||||
|
{
|
||||||
|
if (_typeCheckBoxes[typeDef.Id].Checked)
|
||||||
|
{
|
||||||
|
var config = new TypeConfig { Id = typeDef.Id, Name = typeDef.Name, ShortName = typeDef.ShortName, ConfigValues = new Dictionary<string, string>() };
|
||||||
|
foreach (var field in typeDef.ConfigFields)
|
||||||
|
{
|
||||||
|
if (_fieldControls.TryGetValue((typeDef.Id, field.Name), out var ctrl))
|
||||||
|
{
|
||||||
|
if (ctrl is DirectoryPickerControl)
|
||||||
|
{
|
||||||
|
config.ConfigValues[field.Name] = (ctrl as DirectoryPickerControl).SelectedPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
config.ConfigValues[field.Name] = ctrl.Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.Add(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_globalConfig.Types = result;
|
||||||
|
_configManager.Save(_globalConfig);
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
ModVersionChecker/utils/InputControlsFactory.cs
Normal file
64
ModVersionChecker/utils/InputControlsFactory.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using ModVersionChecker.controls;
|
||||||
|
using ModVersionChecker.model;
|
||||||
|
using ModVersionChecker.repository.api.dto;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ModVersionChecker.utils
|
||||||
|
{
|
||||||
|
public class InputControlsFactory
|
||||||
|
{
|
||||||
|
public static Control CreateControl(FieldResponse field, TypeConfig config, Boolean enabled = true)
|
||||||
|
{
|
||||||
|
var value = config?.ConfigValues != null && config.ConfigValues.ContainsKey(field.Name) ? config.ConfigValues[field.Name] : field.DefaultValue;
|
||||||
|
var directoryField = () =>
|
||||||
|
{
|
||||||
|
var textBox = new TextBox
|
||||||
|
{
|
||||||
|
Width = 300,
|
||||||
|
Text = value,
|
||||||
|
ReadOnly = true
|
||||||
|
};
|
||||||
|
var control = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
AutoSize = true,
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
ColumnCount = 2,
|
||||||
|
RowCount = 1,
|
||||||
|
ColumnStyles = { new ColumnStyle(SizeType.Percent, 80), new ColumnStyle(SizeType.Percent, 20) }
|
||||||
|
};
|
||||||
|
control.Controls.Add(textBox, 0, 0);
|
||||||
|
var browseButton = new Button { Text = "Browse", Width = 80, Enabled = enabled };
|
||||||
|
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 = selectedDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
control.Controls.Add(browseButton, 1, 0);
|
||||||
|
return control;
|
||||||
|
};
|
||||||
|
|
||||||
|
return field. ControlType.ToLower() switch
|
||||||
|
{
|
||||||
|
"text" => new TextBox { Text = value, Width = 300, Enabled = enabled },
|
||||||
|
"number" => new NumericUpDown { Value = decimal.TryParse(value, out var num) ? num : 0, Width = 100, Enabled = enabled },
|
||||||
|
"checkbox" => new CheckBox { Checked = bool.TryParse(value, out var isChecked) && isChecked, AutoSize = true, Enabled = enabled },
|
||||||
|
"directory" => new DirectoryPickerControl { SelectedPath = value, Enabled = enabled },
|
||||||
|
_ => new TextBox { Text = value, Width = 300, Enabled = enabled }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -8,8 +8,10 @@ namespace ModVersionChecker.utils
|
|||||||
{
|
{
|
||||||
public class TimeUtils
|
public class TimeUtils
|
||||||
{
|
{
|
||||||
public static long GetUnixTimeMillis(DateTime? dateTime)
|
public static long GetUnixTimeMillis(DateTime? dateTime = null)
|
||||||
{
|
{
|
||||||
|
var a = DateTime.Now;
|
||||||
|
var b = DateTime.UtcNow;
|
||||||
DateTime dt = dateTime ?? DateTime.UtcNow;
|
DateTime dt = dateTime ?? DateTime.UtcNow;
|
||||||
return (long)(dt - new DateTime(1970, 1, 1)).TotalMilliseconds;
|
return (long)(dt - new DateTime(1970, 1, 1)).TotalMilliseconds;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using ModVersionChecker.data.model;
|
using ModVersionChecker.model;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@@ -6,14 +6,14 @@ namespace ModVersionChecker.utils
|
|||||||
{
|
{
|
||||||
public static class VersionUtils
|
public static class VersionUtils
|
||||||
{
|
{
|
||||||
public static string GetCurrentVersion(AppConfig app, FsModPathConfig config)
|
public static string GetCurrentVersion(App app, TypeConfig typeConfig)
|
||||||
{
|
{
|
||||||
var versionConfig = app.FsFields;
|
var versionConfig = app.Fields;
|
||||||
var packageName = versionConfig["msfs2024"]["package"];
|
var packageName = versionConfig["package"];
|
||||||
var fsPath = config.Path;
|
var fsPath = typeConfig.ConfigValues.GetValueOrDefault("path", "");
|
||||||
var fsFile = config.File;
|
var fsFile = typeConfig.ConfigValues.GetValueOrDefault("filename");
|
||||||
var fsFileType = config.FileType;
|
var fsFileType = typeConfig.ConfigValues.GetValueOrDefault("filetype", "");
|
||||||
var fsKey = config.Key;
|
var fsKey = typeConfig.ConfigValues.GetValueOrDefault("jsonkey", "");
|
||||||
|
|
||||||
var filePath = Path.GetFullPath(Path.Combine(fsPath, packageName, fsFile));
|
var filePath = Path.GetFullPath(Path.Combine(fsPath, packageName, fsFile));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user