Transizione completa da WinForms a WPF con interfaccia moderna (sidebar, pagine, palette Catppuccin Mocha). Aggiunta integrazione con The Racing API per le corse dei cavalli, inclusi nuovi moduli di backend e parsing dati. Introdotti componenti UI personalizzati (CardPanel, ModernButton, ModernProgressBar, NavButton, ModernTheme) per un look coerente e moderno. Gestione avanzata delle impostazioni, esportazione CSV migliorata, refactoring della logica di business e maggiore robustezza nelle chiamate API. Aggiunti stub CsvHelper e file di progetto di backup per facilitare la compatibilità e la migrazione.
397 lines
14 KiB
C#
397 lines
14 KiB
C#
using BettingPredictor.UI;
|
|
using System;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace BettingPredictor
|
|
{
|
|
public partial class Main : Form
|
|
{
|
|
private readonly HorseRacingPredictor.Football.Main footballManager;
|
|
private HorseRacingPredictor.HorseRacing.Main racingManager;
|
|
private DataTable footballData;
|
|
private DataTable racingData;
|
|
|
|
// Credenziali predefinite Racing API
|
|
private const string DefaultRacingUser = "qi1mHOHPquDY9KNDASAeGipy";
|
|
private const string DefaultRacingPass = "RXNFU1YX27R9rTnk8Vop8ZfH";
|
|
|
|
// Pagine e nav gestiti come array per semplificare la navigazione
|
|
private Panel[] pages;
|
|
private NavButton[] navButtons;
|
|
private string[] pageTitles;
|
|
|
|
public Main()
|
|
{
|
|
InitializeComponent();
|
|
footballManager = new HorseRacingPredictor.Football.Main();
|
|
racingManager = new HorseRacingPredictor.HorseRacing.Main(DefaultRacingUser, DefaultRacingPass);
|
|
|
|
pages = new[] { pageFootball, pageHorseRacing, pageSettings, pageInfo };
|
|
navButtons = new[] { navFootball, navHorseRacing, navSettings, navInfo };
|
|
pageTitles = new[] { "Calcio", "Corse Cavalli", "Impostazioni", "Informazioni" };
|
|
}
|
|
|
|
#region Navigation
|
|
|
|
private void ShowPage(int index)
|
|
{
|
|
for (int i = 0; i < pages.Length; i++)
|
|
{
|
|
pages[i].Visible = (i == index);
|
|
navButtons[i].IsActive = (i == index);
|
|
}
|
|
labelPageTitle.Text = pageTitles[index];
|
|
}
|
|
|
|
private void navFootball_Click(object sender, EventArgs e) => ShowPage(0);
|
|
private void navHorseRacing_Click(object sender, EventArgs e) => ShowPage(1);
|
|
private void navSettings_Click(object sender, EventArgs e) => ShowPage(2);
|
|
private void navInfo_Click(object sender, EventArgs e) => ShowPage(3);
|
|
|
|
#endregion
|
|
|
|
#region Football
|
|
|
|
private async Task DownloadFootballFixturesAsync(DateTime selectedDate)
|
|
{
|
|
try
|
|
{
|
|
progressBarFootball.Minimum = 0;
|
|
progressBarFootball.Maximum = 100;
|
|
progressBarFootball.Value = 0;
|
|
labelStatusFootball.Text = "Scaricamento elenco partite...";
|
|
|
|
dateTimePicker.Enabled = false;
|
|
btnDownload.Enabled = false;
|
|
btnExportCsv.Enabled = false;
|
|
|
|
var progress = new Progress<int>(v => progressBarFootball.Value = v);
|
|
var status = new Progress<string>(s => labelStatusFootball.Text = s);
|
|
|
|
var table = await Task.Run(() =>
|
|
footballManager.GetTodayFixtures(selectedDate, progress, status));
|
|
|
|
footballData = table;
|
|
dataGridViewFootball.DataSource = footballData;
|
|
|
|
if (footballData != null && footballData.Rows.Count > 0)
|
|
{
|
|
btnExportCsv.Enabled = true;
|
|
labelStatusFootball.Text = $"Scaricate {footballData.Rows.Count} partite";
|
|
}
|
|
else
|
|
{
|
|
labelStatusFootball.Text = "Nessuna partita trovata per la data selezionata";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Errore durante lo scaricamento:\n{ex.Message}",
|
|
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
labelStatusFootball.Text = "Errore nello scaricamento";
|
|
progressBarFootball.Value = 0;
|
|
}
|
|
finally
|
|
{
|
|
dateTimePicker.Enabled = true;
|
|
btnDownload.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void ExportFootballToCsv()
|
|
{
|
|
if (footballData == null || footballData.Rows.Count == 0)
|
|
{
|
|
MessageBox.Show("Nessun dato da esportare. Scarica prima le partite.",
|
|
"Nessun dato", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
return;
|
|
}
|
|
|
|
string folder = txtExportPath.Text;
|
|
string filePath = null;
|
|
|
|
if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
|
|
{
|
|
filePath = Path.Combine(folder, $"Partite_{dateTimePicker.Value:yyyy-MM-dd}.csv");
|
|
}
|
|
else
|
|
{
|
|
using (var dlg = new SaveFileDialog())
|
|
{
|
|
dlg.Filter = "File CSV|*.csv";
|
|
dlg.FileName = $"Partite_{dateTimePicker.Value:yyyy-MM-dd}.csv";
|
|
if (dlg.ShowDialog() != DialogResult.OK) return;
|
|
filePath = dlg.FileName;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
var headers = new string[footballData.Columns.Count];
|
|
for (int i = 0; i < footballData.Columns.Count; i++)
|
|
headers[i] = footballData.Columns[i].ColumnName;
|
|
sb.AppendLine(string.Join(";", headers));
|
|
|
|
foreach (DataRow row in footballData.Rows)
|
|
{
|
|
var vals = new string[footballData.Columns.Count];
|
|
for (int i = 0; i < footballData.Columns.Count; i++)
|
|
{
|
|
var v = row[i]?.ToString() ?? "";
|
|
if (v.Contains(";") || v.Contains("\""))
|
|
v = "\"" + v.Replace("\"", "\"\"") + "\"";
|
|
vals[i] = v;
|
|
}
|
|
sb.AppendLine(string.Join(";", vals));
|
|
}
|
|
|
|
File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
|
|
labelStatusFootball.Text = $"CSV esportato: {Path.GetFileName(filePath)}";
|
|
MessageBox.Show($"Esportate {footballData.Rows.Count} partite in:\n{filePath}",
|
|
"Esportazione completata", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Errore durante l'esportazione CSV:\n{ex.Message}",
|
|
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Horse Racing
|
|
|
|
private async Task DownloadRacecardsAsync()
|
|
{
|
|
try
|
|
{
|
|
progressBarRacing.Minimum = 0;
|
|
progressBarRacing.Maximum = 100;
|
|
progressBarRacing.Value = 0;
|
|
labelStatusRacing.Text = "Scaricamento racecard...";
|
|
|
|
cmbRacingDay.Enabled = false;
|
|
btnDownloadRacing.Enabled = false;
|
|
btnExportRacingCsv.Enabled = false;
|
|
|
|
var progress = new Progress<int>(v => progressBarRacing.Value = v);
|
|
var status = new Progress<string>(s => labelStatusRacing.Text = s);
|
|
|
|
string day = cmbRacingDay.SelectedIndex == 0 ? "today" : "tomorrow";
|
|
|
|
var table = await Task.Run(() =>
|
|
racingManager.GetRacecards(day, progress, status));
|
|
|
|
racingData = table;
|
|
dataGridViewRacing.DataSource = racingData;
|
|
|
|
if (racingData != null && racingData.Rows.Count > 0)
|
|
{
|
|
btnExportRacingCsv.Enabled = true;
|
|
labelStatusRacing.Text = $"Trovate {racingData.Rows.Count} corse";
|
|
}
|
|
else
|
|
{
|
|
labelStatusRacing.Text = "Nessuna corsa trovata";
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Errore durante lo scaricamento:\n{ex.Message}",
|
|
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
labelStatusRacing.Text = "Errore nello scaricamento";
|
|
progressBarRacing.Value = 0;
|
|
}
|
|
finally
|
|
{
|
|
cmbRacingDay.Enabled = true;
|
|
btnDownloadRacing.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void ExportRacingToCsv()
|
|
{
|
|
if (racingData == null || racingData.Rows.Count == 0)
|
|
{
|
|
MessageBox.Show("Nessun dato da esportare. Scarica prima le corse.",
|
|
"Nessun dato", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
return;
|
|
}
|
|
|
|
string folder = txtExportPath.Text;
|
|
string dayLabel = cmbRacingDay.SelectedIndex == 0 ? "oggi" : "domani";
|
|
string filePath = null;
|
|
|
|
if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
|
|
{
|
|
filePath = Path.Combine(folder, $"Corse_{dayLabel}_{DateTime.Now:yyyy-MM-dd}.csv");
|
|
}
|
|
else
|
|
{
|
|
using (var dlg = new SaveFileDialog())
|
|
{
|
|
dlg.Filter = "File CSV|*.csv";
|
|
dlg.FileName = $"Corse_{dayLabel}_{DateTime.Now:yyyy-MM-dd}.csv";
|
|
if (dlg.ShowDialog() != DialogResult.OK) return;
|
|
filePath = dlg.FileName;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
var headers = new string[racingData.Columns.Count];
|
|
for (int i = 0; i < racingData.Columns.Count; i++)
|
|
headers[i] = racingData.Columns[i].ColumnName;
|
|
sb.AppendLine(string.Join(";", headers));
|
|
|
|
foreach (DataRow row in racingData.Rows)
|
|
{
|
|
var vals = new string[racingData.Columns.Count];
|
|
for (int i = 0; i < racingData.Columns.Count; i++)
|
|
{
|
|
var v = row[i]?.ToString() ?? "";
|
|
if (v.Contains(";") || v.Contains("\""))
|
|
v = "\"" + v.Replace("\"", "\"\"") + "\"";
|
|
vals[i] = v;
|
|
}
|
|
sb.AppendLine(string.Join(";", vals));
|
|
}
|
|
|
|
File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
|
|
labelStatusRacing.Text = $"CSV esportato: {Path.GetFileName(filePath)}";
|
|
MessageBox.Show($"Esportate {racingData.Rows.Count} corse in:\n{filePath}",
|
|
"Esportazione completata", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Errore durante l'esportazione CSV:\n{ex.Message}",
|
|
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Settings
|
|
|
|
private string SettingsFilePath =>
|
|
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.ini");
|
|
|
|
private void LoadSettings()
|
|
{
|
|
try
|
|
{
|
|
// Imposta valori predefiniti Racing API
|
|
txtRacingUser.Text = DefaultRacingUser;
|
|
txtRacingPass.Text = DefaultRacingPass;
|
|
|
|
if (!File.Exists(SettingsFilePath)) return;
|
|
foreach (var line in File.ReadAllLines(SettingsFilePath))
|
|
{
|
|
var idx = line.IndexOf('=');
|
|
if (idx < 0) continue;
|
|
var key = line.Substring(0, idx).Trim();
|
|
var val = line.Substring(idx + 1).Trim();
|
|
|
|
if (key == "ApiKey") txtApiKey.Text = val;
|
|
else if (key == "ExportPath") txtExportPath.Text = val;
|
|
else if (key == "RacingUser") txtRacingUser.Text = val;
|
|
else if (key == "RacingPass") txtRacingPass.Text = val;
|
|
}
|
|
|
|
// Aggiorna il manager con le credenziali caricate
|
|
racingManager.UpdateCredentials(txtRacingUser.Text, txtRacingPass.Text);
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
private void SaveSettings()
|
|
{
|
|
try
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"ApiKey={txtApiKey.Text.Trim()}");
|
|
sb.AppendLine($"ExportPath={txtExportPath.Text.Trim()}");
|
|
sb.AppendLine($"RacingUser={txtRacingUser.Text.Trim()}");
|
|
sb.AppendLine($"RacingPass={txtRacingPass.Text.Trim()}");
|
|
File.WriteAllText(SettingsFilePath, sb.ToString(), Encoding.UTF8);
|
|
|
|
// Aggiorna il manager con le nuove credenziali
|
|
racingManager.UpdateCredentials(txtRacingUser.Text.Trim(), txtRacingPass.Text.Trim());
|
|
|
|
MessageBox.Show("Impostazioni salvate con successo.",
|
|
"Salvato", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Errore nel salvataggio:\n{ex.Message}",
|
|
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Event handlers
|
|
|
|
private void Main_Load(object sender, EventArgs e)
|
|
{
|
|
dateTimePicker.Value = DateTime.Today;
|
|
progressBarFootball.Value = 0;
|
|
labelStatusFootball.Text = "Pronto";
|
|
progressBarRacing.Value = 0;
|
|
labelStatusRacing.Text = "Pronto";
|
|
LoadSettings();
|
|
LayoutToolbars();
|
|
}
|
|
|
|
private void Main_Resize(object sender, EventArgs e)
|
|
{
|
|
LayoutToolbars();
|
|
}
|
|
|
|
private void btnDownload_Click(object sender, EventArgs e)
|
|
{
|
|
_ = DownloadFootballFixturesAsync(dateTimePicker.Value);
|
|
}
|
|
|
|
private void btnExportCsv_Click(object sender, EventArgs e)
|
|
{
|
|
ExportFootballToCsv();
|
|
}
|
|
|
|
private void btnDownloadRacing_Click(object sender, EventArgs e)
|
|
{
|
|
_ = DownloadRacecardsAsync();
|
|
}
|
|
|
|
private void btnExportRacingCsv_Click(object sender, EventArgs e)
|
|
{
|
|
ExportRacingToCsv();
|
|
}
|
|
|
|
private void btnBrowseExport_Click(object sender, EventArgs e)
|
|
{
|
|
using (var dlg = new FolderBrowserDialog())
|
|
{
|
|
dlg.Description = "Seleziona la cartella di esportazione CSV";
|
|
if (dlg.ShowDialog() == DialogResult.OK)
|
|
txtExportPath.Text = dlg.SelectedPath;
|
|
}
|
|
}
|
|
|
|
private void btnSaveSettings_Click(object sender, EventArgs e)
|
|
{
|
|
SaveSettings();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|