Migrate user settings from settings.ini to usersettings.json
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace HorseRacingPredictor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// User-editable preferences persisted as JSON.
|
||||||
|
/// Replaces the legacy settings.ini key=value format.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class UserSettings
|
||||||
|
{
|
||||||
|
private static readonly string FilePath =
|
||||||
|
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "usersettings.json");
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
|
||||||
|
// ?? Football ????????????????????????????????????????????
|
||||||
|
public string ApiKey { get; set; } = string.Empty;
|
||||||
|
public string FbExportPath { get; set; } = string.Empty;
|
||||||
|
public string FbPrefix { get; set; } = string.Empty;
|
||||||
|
public string FbSuffix { get; set; } = string.Empty;
|
||||||
|
public bool FbIncludeDate { get; set; } = true;
|
||||||
|
public string FbDateFormat { get; set; } = "yyyy-MM-dd";
|
||||||
|
public string FbFormat { get; set; } = "CSV";
|
||||||
|
|
||||||
|
// ?? Racing ??????????????????????????????????????????????
|
||||||
|
public string RacingApiKey { get; set; } = string.Empty;
|
||||||
|
public string RcExportPath { get; set; } = string.Empty;
|
||||||
|
public string RcPrefix { get; set; } = string.Empty;
|
||||||
|
public string RcSuffix { get; set; } = string.Empty;
|
||||||
|
public bool RcIncludeDate { get; set; } = true;
|
||||||
|
public string RcDateFormat { get; set; } = "yyyy-MM-dd";
|
||||||
|
public string RcFormat { get; set; } = "CSV";
|
||||||
|
public string RcTimezone { get; set; } = "Australia/Sydney";
|
||||||
|
public List<string> RcCountries { get; set; } = new() { "au", "nz" };
|
||||||
|
|
||||||
|
// ?? Persistence ?????????????????????????????????????????
|
||||||
|
|
||||||
|
public static UserSettings Load()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(FilePath))
|
||||||
|
return MigrateFromIniOrDefault();
|
||||||
|
|
||||||
|
var json = File.ReadAllText(FilePath);
|
||||||
|
return JsonSerializer.Deserialize<UserSettings>(json, JsonOptions) ?? new UserSettings();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new UserSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(this, JsonOptions);
|
||||||
|
File.WriteAllText(FilePath, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// One-time migration: reads old settings.ini if present, converts to UserSettings,
|
||||||
|
/// saves the new usersettings.json, then deletes the ini file.
|
||||||
|
/// </summary>
|
||||||
|
private static UserSettings MigrateFromIniOrDefault()
|
||||||
|
{
|
||||||
|
var iniPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.ini");
|
||||||
|
if (!File.Exists(iniPath))
|
||||||
|
return new UserSettings();
|
||||||
|
|
||||||
|
var settings = new UserSettings();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var line in File.ReadAllLines(iniPath))
|
||||||
|
{
|
||||||
|
var idx = line.IndexOf('=');
|
||||||
|
if (idx < 0) continue;
|
||||||
|
var key = line[..idx].Trim();
|
||||||
|
var val = line[(idx + 1)..].Trim();
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case "ApiKey": settings.ApiKey = val; break;
|
||||||
|
case "FbExportPath": settings.FbExportPath = val; break;
|
||||||
|
case "FbPrefix": settings.FbPrefix = val; break;
|
||||||
|
case "FbSuffix": settings.FbSuffix = val; break;
|
||||||
|
case "FbIncludeDate": settings.FbIncludeDate = val is "1" or "true" or "True"; break;
|
||||||
|
case "FbDateFormat": settings.FbDateFormat = val; break;
|
||||||
|
case "FbFormat": settings.FbFormat = val; break;
|
||||||
|
case "RcExportPath": settings.RcExportPath = val; break;
|
||||||
|
case "RcPrefix": settings.RcPrefix = val; break;
|
||||||
|
case "RcSuffix": settings.RcSuffix = val; break;
|
||||||
|
case "RcIncludeDate": settings.RcIncludeDate = val is "1" or "true" or "True"; break;
|
||||||
|
case "RcDateFormat": settings.RcDateFormat = val; break;
|
||||||
|
case "RcFormat": settings.RcFormat = val; break;
|
||||||
|
case "RacingApiKey": settings.RacingApiKey = val; break;
|
||||||
|
case "RcTimezone": settings.RcTimezone = val; break;
|
||||||
|
case "RcCountries":
|
||||||
|
settings.RcCountries = new List<string>(
|
||||||
|
val.Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist as JSON and remove legacy file
|
||||||
|
settings.Save();
|
||||||
|
File.Delete(iniPath);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// If migration fails, return whatever we parsed
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -831,54 +831,35 @@ namespace HorseRacingPredictor
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ???????????????????? SETTINGS ????????????????????
|
// —————————————————— SETTINGS ——————————————————
|
||||||
|
|
||||||
private string SettingsFilePath =>
|
|
||||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.ini");
|
|
||||||
|
|
||||||
private void LoadSettings()
|
private void LoadSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
txtRacingApiKey.Text = DefaultRacingApiKey;
|
var s = UserSettings.Load();
|
||||||
|
|
||||||
// Default countries
|
txtApiKey.Text = s.ApiKey;
|
||||||
SetSelectedCountries(new[] { "au", "nz" });
|
txtFbExportPath.Text = s.FbExportPath;
|
||||||
|
txtFbPrefix.Text = s.FbPrefix;
|
||||||
|
txtFbSuffix.Text = s.FbSuffix;
|
||||||
|
chkFbIncludeDate.IsChecked = s.FbIncludeDate;
|
||||||
|
SetComboBoxSelectionByContent(cmbFbDateFormat, s.FbDateFormat);
|
||||||
|
SetComboBoxSelectionByContent(cmbFbFormat, s.FbFormat);
|
||||||
|
|
||||||
if (!File.Exists(SettingsFilePath)) { ApplyRacingSettings(); return; }
|
txtRcExportPath.Text = s.RcExportPath;
|
||||||
foreach (var line in File.ReadAllLines(SettingsFilePath))
|
txtRcPrefix.Text = s.RcPrefix;
|
||||||
{
|
txtRcSuffix.Text = s.RcSuffix;
|
||||||
var idx = line.IndexOf('=');
|
chkRcIncludeDate.IsChecked = s.RcIncludeDate;
|
||||||
if (idx < 0) continue;
|
SetComboBoxSelectionByContent(cmbRcDateFormat, s.RcDateFormat);
|
||||||
var key = line.Substring(0, idx).Trim();
|
SetComboBoxSelectionByContent(cmbRcFormat, s.RcFormat);
|
||||||
var val = line.Substring(idx + 1).Trim();
|
|
||||||
|
|
||||||
if (key == "ApiKey") txtApiKey.Text = val;
|
txtRacingApiKey.Text = string.IsNullOrEmpty(s.RacingApiKey) ? DefaultRacingApiKey : s.RacingApiKey;
|
||||||
else if (key == "FbExportPath") txtFbExportPath.Text = val;
|
if (txtRcTimezone != null) txtRcTimezone.Text = s.RcTimezone;
|
||||||
else if (key == "FbPrefix") txtFbPrefix.Text = val;
|
SetSelectedCountries(s.RcCountries.ToArray());
|
||||||
else if (key == "FbSuffix") txtFbSuffix.Text = val;
|
|
||||||
else if (key == "FbIncludeDate") chkFbIncludeDate.IsChecked = val == "1" || val.Equals("true", StringComparison.OrdinalIgnoreCase);
|
|
||||||
else if (key == "FbDateFormat") { try { SetComboBoxSelectionByContent(cmbFbDateFormat, val); } catch { } }
|
|
||||||
else if (key == "FbFormat") { try { SetComboBoxSelectionByContent(cmbFbFormat, val); } catch { } }
|
|
||||||
else if (key == "RcExportPath") txtRcExportPath.Text = val;
|
|
||||||
else if (key == "RcPrefix") txtRcPrefix.Text = val;
|
|
||||||
else if (key == "RcSuffix") txtRcSuffix.Text = val;
|
|
||||||
else if (key == "RcIncludeDate") chkRcIncludeDate.IsChecked = val == "1" || val.Equals("true", StringComparison.OrdinalIgnoreCase);
|
|
||||||
else if (key == "RcDateFormat") { try { SetComboBoxSelectionByContent(cmbRcDateFormat, val); } catch { } }
|
|
||||||
else if (key == "RcFormat") { try { SetComboBoxSelectionByContent(cmbRcFormat, val); } catch { } }
|
|
||||||
else if (key == "RacingApiKey") txtRacingApiKey.Text = val;
|
|
||||||
else if (key == "RcTimezone" && txtRcTimezone != null) txtRcTimezone.Text = val;
|
|
||||||
else if (key == "RcCountries")
|
|
||||||
{
|
|
||||||
var codes = val.Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
SetSelectedCountries(codes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update preview UI after loading values
|
|
||||||
UpdateFbPreview();
|
UpdateFbPreview();
|
||||||
UpdateRcPreview();
|
UpdateRcPreview();
|
||||||
|
|
||||||
ApplyRacingSettings();
|
ApplyRacingSettings();
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
@@ -1110,29 +1091,29 @@ namespace HorseRacingPredictor
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var s = new UserSettings
|
||||||
sb.AppendLine($"ApiKey={txtApiKey.Text.Trim()}");
|
{
|
||||||
sb.AppendLine($"FbExportPath={txtFbExportPath.Text.Trim()}");
|
ApiKey = txtApiKey.Text.Trim(),
|
||||||
sb.AppendLine($"FbPrefix={txtFbPrefix.Text.Trim()}");
|
FbExportPath = txtFbExportPath.Text.Trim(),
|
||||||
sb.AppendLine($"FbSuffix={txtFbSuffix.Text.Trim()}");
|
FbPrefix = txtFbPrefix.Text.Trim(),
|
||||||
sb.AppendLine($"FbIncludeDate={(chkFbIncludeDate.IsChecked==true?"1":"0")}");
|
FbSuffix = txtFbSuffix.Text.Trim(),
|
||||||
sb.AppendLine($"FbDateFormat={(cmbFbDateFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "yyyy-MM-dd"}");
|
FbIncludeDate = chkFbIncludeDate.IsChecked == true,
|
||||||
sb.AppendLine($"FbFormat={(cmbFbFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "CSV"}");
|
FbDateFormat = (cmbFbDateFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "yyyy-MM-dd",
|
||||||
sb.AppendLine($"RcExportPath={txtRcExportPath.Text.Trim()}");
|
FbFormat = (cmbFbFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "CSV",
|
||||||
sb.AppendLine($"RcPrefix={txtRcPrefix.Text.Trim()}");
|
RcExportPath = txtRcExportPath.Text.Trim(),
|
||||||
sb.AppendLine($"RcSuffix={txtRcSuffix.Text.Trim()}");
|
RcPrefix = txtRcPrefix.Text.Trim(),
|
||||||
sb.AppendLine($"RcIncludeDate={(chkRcIncludeDate.IsChecked==true?"1":"0")}");
|
RcSuffix = txtRcSuffix.Text.Trim(),
|
||||||
sb.AppendLine($"RcDateFormat={(cmbRcDateFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "yyyy-MM-dd"}");
|
RcIncludeDate = chkRcIncludeDate.IsChecked == true,
|
||||||
sb.AppendLine($"RcFormat={(cmbRcFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "CSV"}");
|
RcDateFormat = (cmbRcDateFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "yyyy-MM-dd",
|
||||||
sb.AppendLine($"RacingApiKey={txtRacingApiKey.Text.Trim()}");
|
RcFormat = (cmbRcFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "CSV",
|
||||||
sb.AppendLine($"RcTimezone={txtRcTimezone?.Text?.Trim() ?? "Australia/Sydney"}");
|
RacingApiKey = txtRacingApiKey.Text.Trim(),
|
||||||
sb.AppendLine($"RcCountries={string.Join(",", GetSelectedCountries())}");
|
RcTimezone = txtRcTimezone?.Text?.Trim() ?? "Australia/Sydney",
|
||||||
File.WriteAllText(SettingsFilePath, sb.ToString(), Encoding.UTF8);
|
RcCountries = new List<string>(GetSelectedCountries())
|
||||||
|
};
|
||||||
|
s.Save();
|
||||||
|
|
||||||
// update previews after save
|
|
||||||
UpdateFbPreview();
|
UpdateFbPreview();
|
||||||
UpdateRcPreview();
|
UpdateRcPreview();
|
||||||
|
|
||||||
ApplyRacingSettings();
|
ApplyRacingSettings();
|
||||||
|
|
||||||
MessageBox.Show("Impostazioni salvate con successo.",
|
MessageBox.Show("Impostazioni salvate con successo.",
|
||||||
|
|||||||
Reference in New Issue
Block a user