Aggiunto limite configurabile storia puntate

Introdotta la possibilità di configurare un limite massimo di puntate visualizzabili nella scheda "Storia Puntate" tramite l'interfaccia utente. La nuova proprietà `MaxBidHistoryEntries` è stata aggiunta alle impostazioni e salvata in modo persistente.

- Aggiunti controlli UI per configurare il limite.
- Implementata persistenza della lista `RecentBids` con serializzazione JSON.
- Introdotto il metodo `MergeBidHistory` per unire puntate evitando duplicati e mantenendo ordine cronologico decrescente.
- Sincronizzate le statistiche utenti (`BidderStats`) con la lista `RecentBids`.
- Ripristinata la proprietà `IsMyBid` al caricamento delle aste salvate.
- Ottimizzate le performance con `HashSet` per deduplicazione e limite configurabile.
- Creato il file `FIX_BID_HISTORY_PERSISTENCE.md` per documentare il problema e la soluzione.
- Garantita compatibilità retroattiva con aste salvate.

Questi aggiornamenti migliorano la gestione, la visualizzazione e la persistenza della storia delle puntate, offrendo un'esperienza utente più robusta e intuitiva.
This commit is contained in:
2025-11-26 10:44:04 +01:00
parent d99b5ec923
commit c199e542ba
12 changed files with 622 additions and 7 deletions
+142 -2
View File
@@ -249,10 +249,10 @@ namespace AutoBidder.Services
auction.PollingLatencyMs = state.PollingLatencyMs;
// ? NUOVO: Aggiorna storia puntate da API
// ? AGGIORNATO: Aggiorna storia puntate mantenendo quelle vecchie
if (state.RecentBidsHistory != null && state.RecentBidsHistory.Count > 0)
{
auction.RecentBids = state.RecentBidsHistory;
MergeBidHistory(auction, state.RecentBidsHistory);
}
if (state.Status == AuctionStatus.EndedWon ||
@@ -563,6 +563,146 @@ namespace AutoBidder.Services
return lastEntry?.Timer ?? 999;
}
/// <summary>
/// Unisce la storia puntate ricevuta dall'API con quella esistente,
/// mantenendo le puntate più vecchie e aggiungendo solo le nuove.
/// Le puntate sono ordinate con le più RECENTI in CIMA.
/// </summary>
private void MergeBidHistory(AuctionInfo auction, List<BidHistoryEntry> newBids)
{
try
{
// Carica impostazioni per limite massimo
var settings = Utilities.SettingsManager.Load();
var maxEntries = settings?.MaxBidHistoryEntries ?? 20;
// Se la lista esistente è vuota, semplicemente copia le nuove
if (auction.RecentBids.Count == 0)
{
auction.RecentBids = newBids.ToList();
// Ordina per timestamp DECRESCENTE (più recenti in cima)
auction.RecentBids = auction.RecentBids
.OrderByDescending(b => b.Timestamp)
.ToList();
// Limita se necessario
if (maxEntries > 0 && auction.RecentBids.Count > maxEntries)
{
auction.RecentBids = auction.RecentBids
.Take(maxEntries)
.ToList();
}
// Aggiorna statistiche bidder basandosi su RecentBids
UpdateBidderStatsFromRecentBids(auction);
return;
}
// Crea un HashSet delle puntate esistenti per ricerca veloce
// Usiamo una chiave composta: timestamp + username + price per identificare univocamente una puntata
var existingBidsKeys = new HashSet<string>(
auction.RecentBids.Select(b => $"{b.Timestamp}_{b.Username}_{b.Price:F2}")
);
// Aggiungi solo le puntate nuove (non duplicate)
var bidsToAdd = newBids
.Where(b => !existingBidsKeys.Contains($"{b.Timestamp}_{b.Username}_{b.Price:F2}"))
.ToList();
if (bidsToAdd.Count > 0)
{
auction.RecentBids.AddRange(bidsToAdd);
// Ordina per timestamp DECRESCENTE (più recenti in cima)
auction.RecentBids = auction.RecentBids
.OrderByDescending(b => b.Timestamp)
.ToList();
// Limita al numero massimo di puntate (mantieni le più recenti = prime della lista)
if (maxEntries > 0 && auction.RecentBids.Count > maxEntries)
{
auction.RecentBids = auction.RecentBids
.Take(maxEntries)
.ToList();
}
// Aggiorna statistiche bidder basandosi su RecentBids
UpdateBidderStatsFromRecentBids(auction);
}
}
catch (Exception ex)
{
auction.AddLog($"[WARN] Errore merge storia puntate: {ex.Message}");
}
}
/// <summary>
/// Aggiorna le statistiche dei bidder basandosi sulla lista RecentBids (fonte ufficiale).
/// Raggruppa le puntate per utente e conta il numero di puntate per ciascuno.
/// </summary>
private void UpdateBidderStatsFromRecentBids(AuctionInfo auction)
{
try
{
// Raggruppa puntate per username
var bidsByUser = auction.RecentBids
.GroupBy(b => b.Username, StringComparer.OrdinalIgnoreCase)
.ToDictionary(
g => g.Key,
g => new
{
Count = g.Count(),
LastBidTime = DateTimeOffset.FromUnixTimeSeconds(g.Max(b => b.Timestamp)).DateTime
},
StringComparer.OrdinalIgnoreCase
);
// Aggiorna o crea BidderInfo per ogni utente
foreach (var kvp in bidsByUser)
{
var username = kvp.Key;
var stats = kvp.Value;
if (!auction.BidderStats.ContainsKey(username))
{
auction.BidderStats[username] = new BidderInfo
{
Username = username,
BidCount = stats.Count,
LastBidTime = stats.LastBidTime
};
}
else
{
// Aggiorna statistiche esistenti
var existing = auction.BidderStats[username];
existing.BidCount = stats.Count;
existing.LastBidTime = stats.LastBidTime;
}
}
// Rimuovi bidder che non sono più in RecentBids
var usersInRecentBids = new HashSet<string>(
auction.RecentBids.Select(b => b.Username),
StringComparer.OrdinalIgnoreCase
);
var usersToRemove = auction.BidderStats.Keys
.Where(u => !usersInRecentBids.Contains(u))
.ToList();
foreach (var user in usersToRemove)
{
auction.BidderStats.Remove(user);
}
}
catch (Exception ex)
{
auction.AddLog($"[WARN] Errore aggiornamento statistiche bidder: {ex.Message}");
}
}
public void Dispose()
{
Stop();
+8
View File
@@ -344,11 +344,19 @@ namespace AutoBidder.Services
if (!int.TryParse(currentPriceStr, out var currentPriceIndex))
return null;
// 📊 NUOVO: Carica impostazione limite visualizzazione puntate
var settings = Utilities.SettingsManager.Load();
var maxEntries = settings?.MaxBidHistoryEntries ?? 20; // Default 20 se non impostato
foreach (var record in records)
{
if (string.IsNullOrWhiteSpace(record))
continue;
// 📊 Limita il numero di puntate basandosi sulle impostazioni
if (maxEntries > 0 && entries.Count >= maxEntries)
break;
var parts = record.Split(';');
if (parts.Length < 4)
continue;