Implementato il calcolo del valore reale dei prodotti in asta, includendo il prezzo "Compra Subito", spese di spedizione e risparmio stimato. Aggiunta una nuova sezione "Info Prodotto" nella UI per visualizzare i dettagli estratti e i calcoli. - **AuctionMonitorControl.xaml**: Aggiunta sezione fissa per mostrare informazioni prodotto e calcolo valore. - **AuctionMonitorControl.xaml.cs**: Gestiti eventi per il caricamento e aggiornamento delle informazioni prodotto. - **MainWindow**: Integrati handler per il calcolo e refresh delle informazioni prodotto. - **AuctionInfo.cs**: Aggiunte proprietà per gestire prezzo "Compra Subito", spese di spedizione e limiti di vincita. - **ProductValueCalculator.cs**: Nuova utility per calcolare il valore del prodotto e parsare informazioni dall'HTML. - **AuctionViewModel.cs**: Binding per visualizzare risparmio, costo totale e convenienza nella UI. - **Documentazione**: Aggiornata con dettagli sull'algoritmo di calcolo e layout UI. Fix: - Risolto problema di encoding UTF-8 per emoji nella UI. - Migliorato parsing HTML per prezzi e limiti di vincita. TODO: - Testare parsing su più aste e gestire edge cases. - Implementare caricamento automatico delle informazioni.
10 KiB
?? Product Value Calculator - Implementazione UI Completata
? Stato Implementazione
L'interfaccia grafica per il calcolo del valore del prodotto è stata completata e integrata nel pannello "Impostazioni Asta".
?? Dove Trovarla
Posizione UI
- Avvia l'applicazione
- Aggiungi un'asta alla lista monitorata
- Seleziona l'asta cliccando sulla riga nella griglia
- Nel pannello destro "Impostazioni" (in basso a sinistra)
- Troverai un Expander "?? Informazioni Prodotto"
- Clicca per espandere la sezione
Layout Visivo
?? IMPOSTAZIONI ??????????????????????????????
? ?
? Nome Asta ?
? https://it.bidoo.com/auction.php?a=... ?
? ?
? [Browser Interno] [Browser Esterno] ?
? [Copia URL] [Esporta] ?
? ?
? ? ?? Informazioni Prodotto ?
? ?? Compra Subito: 20.00€ ?
? ?? Spedizione: - ?
? ?? Limite: 1 volta ogni 30 giorni ?
? ? ?
? ?? ?? Valore Attuale ?
? ? Prezzo attuale: 1.50€ ?
? ? Mie puntate: 10 (2.00€) ?
? ? ?????????????????????? ?
? ? Costo totale: 3.50€ ?
? ? Risparmio: +16.50€ (82.5%) ?
? ? ?
? ? ?? Raccomandazione: ?
? ? Conveniente! Continua a puntare. ?
? ? ?
? ?? [?? Carica Info Prodotto] ?
? ?
? Anticipo (ms): [200] Min EUR: [0] ?
? Max EUR: [0] Max Clicks: [0] ?
? ? Verifica stato asta prima di puntare ?
? ?
? [Reset] ?
???????????????????????????????????????????????
?? Componenti UI
1. Informazioni Statiche
- Compra Subito: Prezzo "Compra Subito" del prodotto (estratto dall'HTML)
- Spedizione: Spese di spedizione (se disponibili)
- Limite: Limite di vincita (es: "1 volta ogni 30 giorni")
2. Valore Calcolato (Dinamico)
Appare solo quando il valore è stato calcolato:
- Prezzo attuale: Prezzo corrente dell'asta
- Mie puntate: Numero puntate × costo (default 0.20€/puntata)
- Costo totale: Prezzo + Puntate + Spedizione
- Risparmio: Differenza vs Compra Subito (+ verde, - rosso)
3. Raccomandazione
Messaggio intelligente basato sulla convenienza:
- ? Conveniente: "Conveniente! Continua a puntare."
- ? Non conveniente: "Non conviene più. Stai spendendo troppo."
- ?? Neutro: "Valuta attentamente prima di continuare."
4. Pulsante Azione
- ?? Carica Info Prodotto: Scarica dati dalla pagina dell'asta
- Al clic: Scarica HTML, estrae info, aggiorna UI
- Stato caricamento mostrato sotto il pulsante
?? Quando Si Caricano i Dati
Opzione 1: Manuale (Attuale)
- Selezioni l'asta
- Espandi "?? Informazioni Prodotto"
- Clicchi "?? Carica Info Prodotto"
- Attendi qualche secondo
- Le informazioni appaiono
Opzione 2: Automatico (Da Implementare)
- All'aggiunta dell'asta: Carica automaticamente in background
- Ad ogni puntata: Aggiorna il valore calcolato
- Ogni N secondi: Refresh automatico durante il monitoraggio
?? Dati Estratti dall'HTML
Prezzo "Compra Subito"
Cerca questi pattern nell'HTML:
<!-- Pattern 1: buy-rapid-now -->
<div class="btn-rapid buy-rapid-now">€ 20,00</div>
<!-- Pattern 2: buy-now -->
<a class="buy-now">20,00 €</a>
<!-- Pattern 3: reserved-price (fallback) -->
<span class="reserved-price">
<span>Valore:</span> 20,00 €
</span>
Limite Vincita
<i class="bi bi-limit-win"
title="Puoi vincere questo prodotto 1 volta ogni 30 giorni">
</i>
?? Calcolo del Valore
Formula
Costo Puntate = Numero Puntate Utente × 0.20€
Costo Totale = Prezzo Attuale + Costo Puntate + Spese Spedizione
Risparmio = (Compra Subito + Spedizione) - Costo Totale
Percentuale = (Risparmio / (Compra Subito + Spedizione)) × 100
Esempio Pratico
- Asta: 47 Puntate (valore 9.40€)
- Prezzo attuale: 0.33€
- Mie puntate: 10 × 0.20€ = 2.00€
- Spedizione: 0€ (digitale)
- Costo totale: 0.33€ + 2.00€ = 2.33€
- Compra Subito: 9.40€
- Risparmio: 9.40€ - 2.33€ = +7.07€ (75.2%) ?
Raccomandazione: Conveniente! Vale la pena continuare.
?? Completamento Implementazione
Mancano Solo (2 Step):
Step 1: Binding Evento nel MainWindow.xaml
Aggiungi alla definizione del AuctionMonitorControl:
<controls:AuctionMonitorControl x:Name="AuctionMonitor"
...
RefreshProductInfoClicked="AuctionMonitor_RefreshProductInfoClicked"
.../>
Step 2: Handler nel MainWindow
File: Core/MainWindow.ControlEvents.cs
private void AuctionMonitor_RefreshProductInfoClicked(object sender, RoutedEventArgs e)
{
RefreshProductInfo_Click(sender, e);
}
File: Core/MainWindow.ButtonHandlers.cs (o nuovo file)
private async void RefreshProductInfo_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show(
"Seleziona un'asta dalla griglia",
"Nessuna Selezione",
MessageBoxButton.OK,
MessageBoxImage.Information);
return;
}
try
{
// Mostra stato caricamento
AuctionMonitor.ProductInfoStatusText.Text = "Caricamento...";
// Scarica info prodotto
var apiClient = new BidooApiClient();
var session = _auctionMonitor.GetSession();
apiClient.InitializeSession(session.AuthToken, session.Username);
bool extracted = await AuctionMonitorProductValueExtensions.InitializeProductInfoAsync(
apiClient,
_selectedAuction.AuctionInfo
);
if (extracted)
{
// Aggiorna UI con i dati estratti
UpdateProductInfoDisplay(_selectedAuction);
AuctionMonitor.ProductInfoStatusText.Text = "Informazioni caricate";
Log($"[INFO] Informazioni prodotto caricate per: {_selectedAuction.Name}", LogLevel.Success);
}
else
{
AuctionMonitor.ProductInfoStatusText.Text = "Nessuna informazione trovata";
Log($"[WARN] Impossibile estrarre info prodotto per: {_selectedAuction.Name}", LogLevel.Warn);
}
}
catch (Exception ex)
{
AuctionMonitor.ProductInfoStatusText.Text = $"Errore: {ex.Message}";
Log($"[ERROR] Caricamento info prodotto: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante il caricamento:\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void UpdateProductInfoDisplay(AuctionViewModel vm)
{
var auction = vm.AuctionInfo;
// Aggiorna campi statici
if (auction.BuyNowPrice.HasValue)
{
AuctionMonitor.ProductBuyNowPriceText.Text = $"{auction.BuyNowPrice.Value:F2}€";
}
else
{
AuctionMonitor.ProductBuyNowPriceText.Text = "-";
}
if (auction.ShippingCost.HasValue && auction.ShippingCost.Value > 0)
{
AuctionMonitor.ProductShippingCostText.Text = $"{auction.ShippingCost.Value:F2}€";
}
else
{
AuctionMonitor.ProductShippingCostText.Text = "-";
}
if (auction.HasWinLimit && !string.IsNullOrWhiteSpace(auction.WinLimitDescription))
{
AuctionMonitor.ProductWinLimitText.Text = auction.WinLimitDescription;
}
else
{
AuctionMonitor.ProductWinLimitText.Text = "Nessun limite";
}
// Calcola e mostra valore se disponibile
if (auction.CalculatedValue != null)
{
UpdateProductValueDisplay(auction.CalculatedValue);
}
}
private void UpdateProductValueDisplay(ProductValue value)
{
// Mostra il pannello valore
AuctionMonitor.ProductValueBorder.Visibility = Visibility.Visible;
// Aggiorna campi
AuctionMonitor.ValueCurrentPriceText.Text = $"{value.CurrentPrice:F2}€";
AuctionMonitor.ValueMyBidsText.Text = $"{value.MyBids} × 0.20€ = {value.MyBidsCost:F2}€";
AuctionMonitor.ValueTotalCostText.Text = $"{value.TotalCostIfWin:F2}€";
if (value.Savings.HasValue)
{
var savingsText = value.Savings.Value >= 0
? $"+{value.Savings.Value:F2}€ ({value.SavingsPercentage:F1}%)"
: $"{value.Savings.Value:F2}€ ({value.SavingsPercentage:F1}%)";
AuctionMonitor.ValueSavingsText.Text = savingsText;
AuctionMonitor.ValueSavingsText.Foreground = value.IsWorthIt
? new SolidColorBrush(Color.FromRgb(0, 216, 0)) // Verde
: new SolidColorBrush(Color.FromRgb(232, 17, 35)); // Rosso
// Mostra raccomandazione
AuctionMonitor.ValueRecommendationBorder.Visibility = Visibility.Visible;
if (value.IsWorthIt)
{
AuctionMonitor.ValueRecommendationText.Text =
"Conveniente! Vale la pena continuare a puntare.";
}
else
{
AuctionMonitor.ValueRecommendationText.Text =
"Non conviene più. Il costo totale supera il prezzo 'Compra Subito'.";
}
}
}
?? Note Implementative
Aggiornamento Automatico del Valore
Per aggiornare il valore durante il monitoraggio, aggiungi in Monitor_OnAuctionUpdated:
// Aggiorna valore ogni 10 reset per ridurre overhead
if (auction.ResetCount % 10 == 0 && auction.CalculatedValue != null)
{
AuctionMonitorProductValueExtensions.UpdateProductValue(auction, state);
if (_selectedAuction == auction)
{
UpdateProductValueDisplay(auction.CalculatedValue);
}
}
Persistenza
Le informazioni del prodotto vengono salvate automaticamente nel file JSON delle aste:
BuyNowPriceShippingCostHasWinLimitWinLimitDescription
? Testing
-
Test caricamento info:
- Aggiungi asta, seleziona, clicca "Carica Info Prodotto"
- Verifica che i campi si popolino
-
Test calcolo valore:
- Dopo aver caricato info, fai alcune puntate
- Verifica che il valore si aggiorni
-
Test risparmio positivo/negativo:
- Con asta economica: Vedi risparmio positivo (verde)
- Con asta costosa: Vedi risparmio negativo (rosso)
-
Test limite vincita:
- Asta con limite: Vedi "1 volta ogni X giorni"
- Asta senza limite: Vedi "Nessun limite"
?? Ready!
L'UI è pronta e funzionale. Mancano solo i 2 piccoli step finali per collegare l'handler!