Tutto ciò che l'applicazione registra sta ora in due file SQLite in %LocalAppData%\AutoBidder\Database: autobidder.sqlite per le osservazioni e esercizio.sqlite per i documenti d'esercizio (aste nel monitor, prodotti, promozioni, modelli appresi con prefisso ml/) e per i registri applicativo e del riscatto puntate. Il motore comune è SqliteDatabase; i file JSON e la cartella Apprendimento delle versioni precedenti vengono importati la prima volta e lasciati dove sono. La cartella si cambia dalle Impostazioni: al salvataggio si chiede se spostare i file, e si riavvia. Le cartelle Dati/Statistiche/Registri, i registri su file, le misure dell'anticipo e le impostazioni morte (LogBids, AutoApplyProductDefaults, NewAuctionLimitsPriority…) non esistono più. Il kill-switch se ne va: al suo posto un solo interruttore in barra, accanto ad Avvia/Osserva/Ferma, che spegne l'apprendimento. Spento, il motore punta solo entro i limiti dell'utente (prezzo, puntate, budget, fascia oraria, rischio) con l'anticipo fisso: niente valore atteso, regime, duello, bandit, anticipo adattivo. Le aste vengono comunque registrate e studiate. Tre difetti visti osservando il motore dal vivo per un'ora, in Osserva: - la copertura «Compralo Ora» con V lasciato al listino azzerava la perdita coperta e il motore diceva BID a ogni scadenza con P dell'1%: ora vale solo per i prodotti con «Valore reale €» scritto, altrimenti la puntata si conta persa e P decide; - la chiusura di un'asta arrivava due volte (fine, poi rimozione dal monitor) e di nuovo al riavvio: modello, profilo, bandit e statistiche per prodotto contavano ogni asta due volte. Il monitor la comunica una volta sola, l'apprendimento salta le aste già apprese, e le schede prodotto vengono ricostruite una volta dallo storico; - la pagina delle ricompense veniva scambiata per la pagina di accesso perché porta un collegamento a /login.php: prima si guarda se è la pagina delle ricompense. Interfaccia: la scheda Esporta e tutto il suo codice sono tolti; le esportazioni chiedono sempre dove salvare. Prodotti, Storico e Apprendimento hanno barre a sole icone con tooltip che dicono esattamente cosa succede, colorate come il monitor, con i nuovi pulsanti di pulizia (spegni tutte le stelline, togli i non seguiti, pulizia completa; seleziona tutte / elimina le selezionate / svuota lo storico). Impostazioni: sezione Database, Manutenzione con «Elimina tutti i dati (tranne la login)» e «Impostazioni di fabbrica», esportazione dei registri in testo. Modifiche.txt, il prompt ormai realizzato, esce dal repository. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
629 lines
25 KiB
C#
629 lines
25 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using AutoBidder.Dialogs;
|
|
using AutoBidder.Utilities;
|
|
using AutoBidder.ViewModels;
|
|
|
|
namespace AutoBidder
|
|
{
|
|
/// <summary>
|
|
/// Button click event handlers for auction operations
|
|
/// </summary>
|
|
public partial class MainWindow
|
|
{
|
|
// sender null = azione interna (non richiesta dall'utente): si evita di loggarla.
|
|
private void StartButton_Click(object? sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (!_isAutomationActive)
|
|
{
|
|
// Avvia il monitoraggio globale
|
|
_auctionMonitor.Start();
|
|
_isAutomationActive = true;
|
|
Log("[START] Monitoraggio avviato!", LogLevel.Success);
|
|
}
|
|
|
|
// Attiva e riprendi tutte le aste
|
|
foreach (var vm in _auctionViewModels)
|
|
{
|
|
if (!vm.IsActive)
|
|
{
|
|
vm.IsActive = true;
|
|
}
|
|
vm.IsPaused = false;
|
|
}
|
|
|
|
if (sender != null) // Solo se chiamato dall'utente, non internamente
|
|
{
|
|
Log("[START ALL] Tutte le aste avviate/riprese", LogLevel.Info);
|
|
}
|
|
|
|
// ? Salva gli stati aggiornati su disco
|
|
SaveAuctions();
|
|
UpdateGlobalControlButtons();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Avvio: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private void StopButton_Click(object? sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// Ferma tutte le aste
|
|
foreach (var vm in _auctionViewModels)
|
|
{
|
|
vm.IsActive = false;
|
|
}
|
|
|
|
// Ferma il monitoraggio globale
|
|
if (_isAutomationActive)
|
|
{
|
|
_auctionMonitor.Stop();
|
|
_isAutomationActive = false;
|
|
}
|
|
|
|
// ? Salva gli stati aggiornati su disco
|
|
SaveAuctions();
|
|
UpdateGlobalControlButtons();
|
|
|
|
if (sender != null) // Solo se chiamato dall'utente
|
|
{
|
|
Log("[STOP ALL] Monitoraggio fermato e tutte le aste arrestate", LogLevel.Warning);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE STOP] {ex.Message}", LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private async void PauseAllButton_Click(object? sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// Osserva vale anche per le aste ferme: servono comunque i motori accesi
|
|
// per seguirle, semplicemente non punteranno.
|
|
foreach (var vm in _auctionViewModels)
|
|
{
|
|
vm.IsActive = true;
|
|
vm.IsPaused = true;
|
|
}
|
|
|
|
if (_auctionViewModels.Count > 0 && !_isAutomationActive)
|
|
{
|
|
_auctionMonitor.Start();
|
|
_isAutomationActive = true;
|
|
}
|
|
|
|
// ? Salva gli stati aggiornati su disco
|
|
SaveAuctions();
|
|
UpdateGlobalControlButtons();
|
|
|
|
if (sender != null) // Solo se chiamato dall'utente
|
|
{
|
|
Log("[OSSERVA] Tutte le aste seguite senza puntare", LogLevel.Warning);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Pausa globale: {ex.Message}", LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
private async void AddUrlButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var dialog = new AddAuctionSimpleDialog();
|
|
if (dialog.ShowDialog() == true)
|
|
{
|
|
var raw = dialog.AuctionId ?? string.Empty;
|
|
var parts = Regex.Split(raw, "[\r\n;]+|\\s+")
|
|
.Select(p => p.Trim())
|
|
.Where(p => !string.IsNullOrWhiteSpace(p))
|
|
.ToList();
|
|
|
|
if (parts.Count == 0)
|
|
{
|
|
MessageBox.Show("Nessun URL/ID valido trovato.", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
var added = 0;
|
|
var skipped = new System.Collections.Generic.List<string>();
|
|
|
|
foreach (var part in parts)
|
|
{
|
|
try
|
|
{
|
|
var input = part;
|
|
string? aid = null;
|
|
if (input.Contains("bidoo.com") || input.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
aid = ExtractAuctionId(input);
|
|
}
|
|
else
|
|
{
|
|
aid = input;
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(aid) && _auctionViewModels.Any(a => a.AuctionId == aid))
|
|
{
|
|
skipped.Add(part + " (duplicato)");
|
|
continue;
|
|
}
|
|
|
|
await AddAuctionById(input);
|
|
added++;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
skipped.Add(part + " (errore: " + ex.Message + ")");
|
|
}
|
|
}
|
|
|
|
UpdateGlobalControlButtons();
|
|
|
|
var summary = $"Aggiunte: {added}. Skipped: {skipped.Count}.";
|
|
if (skipped.Count > 0)
|
|
summary += "\nDettagli: " + string.Join("; ", skipped.Take(10));
|
|
|
|
MessageBox.Show(summary, "Aggiunta aste", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
// ? RIMOSSO: Retry automatico ora avviene alla selezione on-demand
|
|
// Le aste con nome generico vengono aggiornate automaticamente quando l'utente le seleziona
|
|
}
|
|
}
|
|
|
|
private void RemoveUrlButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
var auctionName = _selectedAuction.Name;
|
|
var auctionId = _selectedAuction.AuctionId;
|
|
|
|
// Salva l'indice corrente prima di rimuovere
|
|
var currentIndex = _auctionViewModels.IndexOf(_selectedAuction);
|
|
|
|
// Conferma rimozione
|
|
var result = MessageBox.Show(
|
|
$"Rimuovere l'asta dal monitoraggio?\n\n{auctionName}\n(ID: {auctionId})\n\nL'asta verr� eliminata dalla lista e non sar� pi� monitorata.",
|
|
"Conferma Rimozione",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Question);
|
|
|
|
if (result != MessageBoxResult.Yes)
|
|
{
|
|
Log($"[REMOVE] Rimozione annullata: {auctionName}", LogLevel.Info);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Rimuove dal monitor
|
|
_auctionMonitor.RemoveAuction(auctionId);
|
|
|
|
// Rimuove dal ViewModel
|
|
_auctionViewModels.Remove(_selectedAuction);
|
|
|
|
// Salva modifiche
|
|
SaveAuctions();
|
|
UpdateTotalCount();
|
|
UpdateGlobalControlButtons();
|
|
|
|
Log($"[REMOVE] Asta rimossa: {auctionName} (ID: {auctionId})", LogLevel.Success);
|
|
|
|
// ? NUOVO: Sposta il focus sulla riga successiva
|
|
if (_auctionViewModels.Count > 0)
|
|
{
|
|
// Se c'� ancora almeno un'asta nella lista
|
|
int newIndex;
|
|
|
|
if (currentIndex >= _auctionViewModels.Count)
|
|
{
|
|
// L'asta rimossa era l'ultima, seleziona la nuova ultima
|
|
newIndex = _auctionViewModels.Count - 1;
|
|
}
|
|
else
|
|
{
|
|
// Seleziona l'asta che ora si trova nella stessa posizione
|
|
newIndex = currentIndex;
|
|
}
|
|
|
|
// Seleziona l'asta
|
|
MultiAuctionsGrid.SelectedIndex = newIndex;
|
|
_selectedAuction = _auctionViewModels[newIndex];
|
|
|
|
// ? FIX: Salva il nome della NUOVA asta selezionata per il log
|
|
var newAuctionName = _selectedAuction?.Name ?? "Sconosciuta";
|
|
|
|
// Forza il focus sulla griglia dopo un breve delay per permettere alla UI di aggiornarsi
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
MultiAuctionsGrid.Focus();
|
|
|
|
// Scroll fino alla riga selezionata per assicurarsi che sia visibile
|
|
if (MultiAuctionsGrid.SelectedItem != null)
|
|
{
|
|
MultiAuctionsGrid.ScrollIntoView(MultiAuctionsGrid.SelectedItem);
|
|
}
|
|
|
|
// ? FIX: Usa la variabile locale invece di _selectedAuction.Name
|
|
Log($"[FOCUS] Focus spostato su: {newAuctionName}", LogLevel.Info);
|
|
}), System.Windows.Threading.DispatcherPriority.Background);
|
|
}
|
|
else
|
|
{
|
|
// Nessuna asta rimasta, reset selezione
|
|
_selectedAuction = null;
|
|
Log($"[REMOVE] Nessuna asta rimasta nella lista", LogLevel.Info);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERROR] Errore rimozione asta: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante la rimozione:\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private void RemoveAllButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_auctionViewModels.Count == 0)
|
|
{
|
|
MessageBox.Show("Non ci sono aste da rimuovere", "Lista Vuota", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
var count = _auctionViewModels.Count;
|
|
|
|
// Conferma rimozione
|
|
var result = MessageBox.Show(
|
|
$"Rimuovere TUTTE le aste dal monitoraggio?\n\nSono presenti {count} aste monitorate.\n\nTutte le aste verranno eliminate dalla lista e non saranno pi� monitorate.",
|
|
"Conferma Rimozione Totale",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Warning);
|
|
|
|
if (result != MessageBoxResult.Yes)
|
|
{
|
|
Log($"[REMOVE ALL] Rimozione annullata", LogLevel.Info);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Ferma il monitoraggio se attivo
|
|
if (_isAutomationActive)
|
|
{
|
|
_auctionMonitor.Stop();
|
|
_isAutomationActive = false;
|
|
Log("[STOP] Monitoraggio fermato prima della rimozione totale", LogLevel.Info);
|
|
}
|
|
|
|
// Rimuove tutte le aste dal monitor e dal ViewModel
|
|
var auctionsToRemove = _auctionViewModels.ToList(); // Copia per evitare modifiche durante iterazione
|
|
|
|
foreach (var auction in auctionsToRemove)
|
|
{
|
|
_auctionMonitor.RemoveAuction(auction.AuctionId);
|
|
}
|
|
|
|
// Pulisci la lista ViewModel
|
|
_auctionViewModels.Clear();
|
|
|
|
// Resetta selezione
|
|
_selectedAuction = null;
|
|
|
|
// Salva modifiche
|
|
SaveAuctions();
|
|
UpdateTotalCount();
|
|
UpdateGlobalControlButtons();
|
|
|
|
Log($"[REMOVE ALL] Tutte le aste rimosse: {count} aste eliminate", LogLevel.Success);
|
|
|
|
MessageBox.Show($"Tutte le {count} aste sono state rimosse dal monitoraggio.", "Rimozione Completata", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERROR] Errore rimozione totale: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante la rimozione delle aste: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private async void CopyAuctionUrlButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show(
|
|
"Seleziona un'asta dalla griglia prima di copiare l'URL.",
|
|
"Nessuna Asta Selezionata",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Information);
|
|
Log("[INFO] Tentativo di copia URL senza asta selezionata", LogLevel.Info);
|
|
return;
|
|
}
|
|
|
|
var url = _selectedAuction.AuctionInfo.OriginalUrl;
|
|
if (string.IsNullOrEmpty(url))
|
|
url = $"https://it.bidoo.com/auction.php?a=asta_{_selectedAuction.AuctionId}";
|
|
|
|
// Tenta di copiare con retry mechanism
|
|
const int maxAttempts = 3;
|
|
const int delayMs = 50;
|
|
|
|
for (int attempt = 1; attempt <= maxAttempts; attempt++)
|
|
{
|
|
try
|
|
{
|
|
Clipboard.SetText(url);
|
|
Log("URL copiato negli appunti", LogLevel.Success);
|
|
return; // Successo, esci
|
|
}
|
|
catch (System.Runtime.InteropServices.COMException ex) when (ex.ErrorCode == unchecked((int)0x800401D0)) // CLIPBRD_E_CANT_OPEN
|
|
{
|
|
if (attempt < maxAttempts)
|
|
{
|
|
// Clipboard occupato, riprova dopo un breve delay
|
|
System.Threading.Thread.Sleep(delayMs);
|
|
continue;
|
|
}
|
|
|
|
// Ultimo tentativo fallito
|
|
Log($"[WARN] Clipboard temporaneamente occupato. Il testo potrebbe essere stato copiato.", LogLevel.Warning);
|
|
return;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Altri errori
|
|
Log($"[ERRORE] Impossibile copiare URL: {ex.Message}", LogLevel.Error);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OpenAuctionInternalButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var url = _selectedAuction.AuctionInfo.OriginalUrl;
|
|
if (string.IsNullOrEmpty(url))
|
|
url = $"https://it.bidoo.com/auction.php?a=asta_{_selectedAuction.AuctionId}";
|
|
|
|
// Naviga alla scheda Browser, in modalita' browser (non catalogo)
|
|
TabBrowser.IsChecked = true;
|
|
Browser.ShowBrowser();
|
|
|
|
// Naviga all'URL
|
|
if (EmbeddedWebView?.CoreWebView2 != null)
|
|
{
|
|
EmbeddedWebView.CoreWebView2.Navigate(url);
|
|
Log($"[BROWSER] Apertura asta nel browser interno: {_selectedAuction.Name}", LogLevel.Info);
|
|
}
|
|
else
|
|
{
|
|
Log($"[WARN] Browser interno non ancora inizializzato", LogLevel.Warning);
|
|
MessageBox.Show("Il browser interno non � ancora pronto.\nRiprova tra qualche secondo.", "Browser", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Apertura nel browser interno: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante l'apertura: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private void OpenAuctionExternalButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var url = _selectedAuction.AuctionInfo.OriginalUrl;
|
|
if (string.IsNullOrEmpty(url))
|
|
url = $"https://it.bidoo.com/auction.php?a=asta_{_selectedAuction.AuctionId}";
|
|
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
|
|
{
|
|
FileName = url,
|
|
UseShellExecute = true
|
|
});
|
|
|
|
Log($"[BROWSER] Apertura asta nel browser esterno: {_selectedAuction.Name}", LogLevel.Info);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Apertura nel browser esterno: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante l'apertura: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
private async void RefreshProductInfoButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
var auction = _selectedAuction.AuctionInfo;
|
|
|
|
// Verifica che ci siano le info prodotto caricate
|
|
if (!auction.BuyNowPrice.HasValue)
|
|
{
|
|
MessageBox.Show(
|
|
"Informazioni prodotto non disponibili.\n\n" +
|
|
"Il sistema le sta caricando automaticamente.\n" +
|
|
"Riprova tra qualche secondo.",
|
|
"Info Prodotto Mancanti",
|
|
MessageBoxButton.OK,
|
|
MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
// Feedback visivo
|
|
AuctionMonitor.RefreshProductInfoButton.IsEnabled = false;
|
|
|
|
// CALCOLA LIMITI SUGGERITI (CONSERVATIVI)
|
|
double buyNowPrice = auction.BuyNowPrice.Value;
|
|
double shippingCost = auction.ShippingCost ?? 0;
|
|
double totalValue = buyNowPrice + shippingCost;
|
|
|
|
// Max EUR = 40% del valore TOTALE (pi� conservativo del 50%)
|
|
double suggestedMaxPrice = totalValue * 0.40;
|
|
suggestedMaxPrice = Math.Round(suggestedMaxPrice, 2);
|
|
|
|
// CALCOLA MAX CLICKS (numero massimo puntate conservativo)
|
|
// Formula: (Valore Totale - Max EUR) / 0.20� per puntata
|
|
// Poi riduciamo del 20% per maggiore margine di sicurezza
|
|
int maxClicksTheoretical = (int)Math.Floor((totalValue - suggestedMaxPrice) / 0.20);
|
|
int suggestedMaxClicks = (int)Math.Floor(maxClicksTheoretical * 0.80); // 80% del teorico
|
|
|
|
// Minimo 10 puntate per dare comunque una chance
|
|
if (suggestedMaxClicks < 10) suggestedMaxClicks = 10;
|
|
|
|
Log($"[LIMITI] Valore={buyNowPrice:F2}� + Extra={shippingCost:F2}� = Tot={totalValue:F2}� ? MaxEUR={suggestedMaxPrice:F2}� (40%), MaxClicks={suggestedMaxClicks}", LogLevel.Info);
|
|
|
|
// CHIEDI CONFERMA
|
|
var result = MessageBox.Show(
|
|
$"Limiti suggeriti (conservativi):\n\n" +
|
|
$"Max EUR: {suggestedMaxPrice:F2}�\n" +
|
|
$"Max Clicks: {suggestedMaxClicks}\n\n" +
|
|
$"Applicare questi valori?",
|
|
"Conferma Limiti",
|
|
MessageBoxButton.YesNo,
|
|
MessageBoxImage.Question);
|
|
|
|
if (result != MessageBoxResult.Yes)
|
|
{
|
|
Log($"[LIMITI] Annullato dall'utente", LogLevel.Info);
|
|
return;
|
|
}
|
|
|
|
// APPLICA I LIMITI
|
|
_selectedAuction.MaxPrice = suggestedMaxPrice;
|
|
_selectedAuction.MaxClicks = suggestedMaxClicks;
|
|
|
|
// AGGIORNA UI
|
|
UpdateAuctionSettingsDisplay(_selectedAuction);
|
|
|
|
// SALVA
|
|
SaveAuctions();
|
|
|
|
Log($"[LIMITI] Applicati: MaxEUR={suggestedMaxPrice:F2}�, MaxClicks={suggestedMaxClicks}", LogLevel.Success);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Calcolo limiti: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante il calcolo dei limiti:\n\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
finally
|
|
{
|
|
AuctionMonitor.RefreshProductInfoButton.IsEnabled = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sposta l'asta selezionata verso l'alto nell'elenco
|
|
/// </summary>
|
|
private void MoveUpButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var currentIndex = _auctionViewModels.IndexOf(_selectedAuction);
|
|
|
|
if (currentIndex <= 0)
|
|
{
|
|
// Gi� in cima o non trovata
|
|
Log($"[MOVE] L'asta � gi� in cima alla lista", LogLevel.Info);
|
|
return;
|
|
}
|
|
|
|
// Sposta l'elemento verso l'alto
|
|
_auctionViewModels.Move(currentIndex, currentIndex - 1);
|
|
|
|
// Mantieni la selezione
|
|
MultiAuctionsGrid.SelectedItem = _selectedAuction;
|
|
MultiAuctionsGrid.ScrollIntoView(_selectedAuction);
|
|
|
|
// Salva il nuovo ordine
|
|
SaveAuctions();
|
|
|
|
Log($"[MOVE UP] Asta spostata verso l'alto: {_selectedAuction.Name}", LogLevel.Success);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Spostamento asta verso l'alto: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante lo spostamento: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sposta l'asta selezionata verso il basso nell'elenco
|
|
/// </summary>
|
|
private void MoveDownButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_selectedAuction == null)
|
|
{
|
|
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var currentIndex = _auctionViewModels.IndexOf(_selectedAuction);
|
|
|
|
if (currentIndex < 0 || currentIndex >= _auctionViewModels.Count - 1)
|
|
{
|
|
// Gi� in fondo o non trovata
|
|
Log($"[MOVE] L'asta � gi� in fondo alla lista", LogLevel.Info);
|
|
return;
|
|
}
|
|
|
|
// Sposta l'elemento verso il basso
|
|
_auctionViewModels.Move(currentIndex, currentIndex + 1);
|
|
|
|
// Mantieni la selezione
|
|
MultiAuctionsGrid.SelectedItem = _selectedAuction;
|
|
MultiAuctionsGrid.ScrollIntoView(_selectedAuction);
|
|
|
|
// Salva il nuovo ordine
|
|
SaveAuctions();
|
|
|
|
Log($"[MOVE DOWN] Asta spostata verso il basso: {_selectedAuction.Name}", LogLevel.Success);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log($"[ERRORE] Spostamento asta verso il basso: {ex.Message}", LogLevel.Error);
|
|
MessageBox.Show($"Errore durante lo spostamento: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
}
|
|
}
|
|
}
|
|
}
|