@@ -502,14 +496,18 @@
var percentage = totalBidsCumulative > 0
? (displayCount * 100.0 / totalBidsCumulative)
: 0;
-
| #@(i + 1) |
- @bidder.Username
@if (isMe)
{
+ @bidder.Username
TU
}
+ else
+ {
+ @bidder.Username
+ }
|
@displayCount |
diff --git a/Mimante/Pages/Index.razor.cs b/Mimante/Pages/Index.razor.cs
index 8927fb4..7769eed 100644
--- a/Mimante/Pages/Index.razor.cs
+++ b/Mimante/Pages/Index.razor.cs
@@ -16,11 +16,27 @@ namespace AutoBidder.Pages
[Inject] private StatsService StatsService { get; set; } = default!;
private List auctions => AppState.Auctions.ToList();
+
private AuctionInfo? selectedAuction
{
- get => AppState.SelectedAuction;
- set => AppState.SelectedAuction = value;
+ get
+ {
+ // ?? FIX CRITICO: Ottieni sempre il riferimento dalla lista originale
+ // Questo assicura che le modifiche ai campi vengano salvate correttamente
+ var selected = AppState.SelectedAuction;
+ if (selected != null)
+ {
+ var liveReference = AppState.GetAuctionById(selected.AuctionId);
+ return liveReference;
+ }
+ return null;
+ }
+ set
+ {
+ AppState.SelectedAuction = value;
+ }
}
+
private List globalLog => AppState.GlobalLog.ToList();
private bool isMonitoringActive
{
diff --git a/Mimante/Services/ApplicationStateService.cs b/Mimante/Services/ApplicationStateService.cs
index cc4414d..2ce728d 100644
--- a/Mimante/Services/ApplicationStateService.cs
+++ b/Mimante/Services/ApplicationStateService.cs
@@ -76,6 +76,18 @@ namespace AutoBidder.Services
}
}
+ ///
+ /// Ottiene l'asta modificabile per ID.
+ /// IMPORTANTE: Dopo modifiche, chiamare PersistAuctions() per salvare!
+ ///
+ public AuctionInfo? GetAuctionById(string auctionId)
+ {
+ lock (_lock)
+ {
+ return _auctions.FirstOrDefault(a => a.AuctionId == auctionId);
+ }
+ }
+
public AuctionInfo? SelectedAuction
{
get
diff --git a/Mimante/Services/AuctionMonitor.cs b/Mimante/Services/AuctionMonitor.cs
index c10043e..f47986d 100644
--- a/Mimante/Services/AuctionMonitor.cs
+++ b/Mimante/Services/AuctionMonitor.cs
@@ -405,8 +405,6 @@ namespace AutoBidder.Services
Timestamp = lastBidTimestamp,
BidType = "Auto"
});
-
- auction.AddLog($"[FIX] Aggiunta ultima puntata mancante: {state.LastBidder} €{state.Price:F2}");
}
}
@@ -977,6 +975,7 @@ namespace AutoBidder.Services
///
/// Assicura che la puntata corrente (quella vincente) sia sempre presente nello storico.
/// Questo risolve il problema dell'API che a volte non include l'ultima puntata.
+ /// IMPORTANTE: Aggiunge solo se è una NUOVA puntata (prezzo/utente diverso dall'ultima registrata).
///
private void EnsureCurrentBidInHistory(AuctionInfo auction, AuctionState state)
{
@@ -985,41 +984,49 @@ namespace AutoBidder.Services
var statePrice = (decimal)state.Price;
var currentBidder = state.LastBidder;
- // Verifica se questa puntata non è già presente
- var alreadyExists = auction.RecentBids.Any(b =>
- Math.Abs(b.Price - statePrice) < 0.001m &&
- b.Username.Equals(currentBidder, StringComparison.OrdinalIgnoreCase));
-
- if (!alreadyExists)
+ // 🔥 VERIFICA: Controlla se è la stessa puntata che abbiamo già in cima
+ // Evitiamo di aggiungere continuamente la stessa puntata ad ogni polling
+ if (auction.RecentBids.Count > 0)
{
- var lastBidTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+ var topBid = auction.RecentBids[0]; // Prima = più recente
- auction.RecentBids.Insert(0, new BidHistoryEntry
+ // Se la puntata in cima è identica (stesso prezzo + stesso utente), salta
+ if (Math.Abs(topBid.Price - statePrice) < 0.001m &&
+ topBid.Username.Equals(currentBidder, StringComparison.OrdinalIgnoreCase))
+ {
+ return; // Già presente in cima, non serve aggiungere
+ }
+ }
+
+ // 🔥 NUOVA PUNTATA: Aggiungi solo se diversa dall'ultima
+ // Questo significa che c'è stata una nuova puntata che l'API non ha ancora segnalato
+ var lastBidTimestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
+
+ auction.RecentBids.Insert(0, new BidHistoryEntry
+ {
+ Username = currentBidder,
+ Price = statePrice,
+ Timestamp = lastBidTimestamp,
+ BidType = "Auto"
+ });
+
+ // Aggiorna anche le statistiche bidder
+ if (!auction.BidderStats.ContainsKey(currentBidder))
+ {
+ auction.BidderStats[currentBidder] = new BidderInfo
{
Username = currentBidder,
- Price = statePrice,
- Timestamp = lastBidTimestamp,
- BidType = "Auto"
- });
-
- // Aggiorna anche le statistiche bidder
- if (!auction.BidderStats.ContainsKey(currentBidder))
- {
- auction.BidderStats[currentBidder] = new BidderInfo
- {
- Username = currentBidder,
- BidCount = 1,
- RecentBidCount = 1,
- LastBidTime = DateTime.UtcNow
- };
- }
- else
- {
- var bidder = auction.BidderStats[currentBidder];
- bidder.BidCount++;
- bidder.RecentBidCount++;
- bidder.LastBidTime = DateTime.UtcNow;
- }
+ BidCount = 1,
+ RecentBidCount = 1,
+ LastBidTime = DateTime.UtcNow
+ };
+ }
+ else
+ {
+ var bidder = auction.BidderStats[currentBidder];
+ bidder.BidCount++;
+ bidder.RecentBidCount++;
+ bidder.LastBidTime = DateTime.UtcNow;
}
}
catch { /* Silenzioso */ }
diff --git a/Mimante/Services/BidStrategyService.cs b/Mimante/Services/BidStrategyService.cs
index b4c5d50..e295dae 100644
--- a/Mimante/Services/BidStrategyService.cs
+++ b/Mimante/Services/BidStrategyService.cs
@@ -248,20 +248,13 @@ namespace AutoBidder.Services
return decision;
}
- // ?? 1. ENTRY POINT - Verifica se il prezzo è conveniente
- // Punta solo se prezzo < (MaxPrice * 0.7)
- if (settings.EntryPointEnabled && auction.MaxPrice > 0)
- {
- var entryThreshold = auction.MaxPrice * 0.7;
- if (state.Price >= entryThreshold)
- {
- decision.ShouldBid = false;
- decision.Reason = $"Entry point: €{state.Price:F2} >= 70% di max €{auction.MaxPrice:F2}";
- return decision;
- }
- }
+ // ? RIMOSSO: Entry Point - Era sbagliato!
+ // I limiti MinPrice/MaxPrice impostati dall'utente sono RIGIDI.
+ // Se l'utente imposta MaxPrice=2€, vuole puntare FINO A 2€, non fino al 70%!
+ // I controlli MinPrice/MaxPrice sono già gestiti in AuctionMonitor.ShouldBid()
+ // L'Entry Point può essere usato SOLO per calcolare limiti CONSIGLIATI, non per bloccare.
- // ?? 2. ANTI-BOT - Rileva pattern bot (timing identico)
+ // ?? 1. ANTI-BOT - Rileva pattern bot (timing identico)
if (settings.AntiBotDetectionEnabled && !string.IsNullOrEmpty(state.LastBidder))
{
var botCheck = DetectBotPattern(auction, state.LastBidder, currentUsername);
@@ -273,14 +266,14 @@ namespace AutoBidder.Services
}
}
- // ?? 3. USER EXHAUSTION - Sfrutta utenti stanchi (info solo, non blocca)
+ // ?? 2. USER EXHAUSTION - Sfrutta utenti stanchi (info solo, non blocca)
if (settings.UserExhaustionEnabled && !string.IsNullOrEmpty(state.LastBidder))
{
var exhaustionCheck = CheckUserExhaustion(auction, state.LastBidder, currentUsername);
// Non blocchiamo, ma potremmo loggare per info
}
- // 4. Verifica soft retreat
+ // 3. Verifica soft retreat
if (settings.SoftRetreatEnabled || (auction.SoftRetreatEnabledOverride ?? settings.SoftRetreatEnabled))
{
if (auction.IsInSoftRetreat)
diff --git a/Mimante/Utilities/SettingsManager.cs b/Mimante/Utilities/SettingsManager.cs
index 0dd5558..c07797b 100644
--- a/Mimante/Utilities/SettingsManager.cs
+++ b/Mimante/Utilities/SettingsManager.cs
@@ -170,9 +170,9 @@ namespace AutoBidder.Utilities
// 🎯 STRATEGIE SEMPLIFICATE
///
- /// Entry Point: Punta solo se prezzo attuale è inferiore al 70% del MaxPrice.
- /// Richiede che MaxPrice sia impostato sull'asta.
- /// Default: true
+ /// Entry Point: Usato SOLO per calcolare i limiti consigliati (70% del MaxPrice storico).
+ /// NON blocca le puntate! I limiti MinPrice/MaxPrice impostati dall'utente sono RIGIDI.
+ /// Default: true (per calcolo limiti consigliati)
///
public bool EntryPointEnabled { get; set; } = true;
diff --git a/Mimante/wwwroot/css/app-wpf.css b/Mimante/wwwroot/css/app-wpf.css
index a7dd637..aca5012 100644
--- a/Mimante/wwwroot/css/app-wpf.css
+++ b/Mimante/wwwroot/css/app-wpf.css
@@ -909,6 +909,51 @@ main {
height: auto;
}
+/* 🔥 GRIGLIA IMPOSTAZIONI COMPATTA */
+.settings-grid-compact {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 0.5rem;
+ margin-bottom: 0.5rem;
+}
+
+.settings-grid-compact .setting-item {
+ display: flex;
+ flex-direction: column;
+ gap: 0.15rem;
+}
+
+.settings-grid-compact .setting-item label {
+ font-size: 0.7rem;
+ color: var(--text-secondary);
+ font-weight: 500;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.settings-grid-compact .setting-item label i {
+ margin-right: 0.2rem;
+}
+
+/* 🔥 Input stretti per valori numerici */
+.input-narrow {
+ max-width: 90px !important;
+ text-align: center;
+ padding: 0.2rem 0.4rem !important;
+ font-size: 0.8rem !important;
+}
+
+/* Responsive: su schermi piccoli, 2 colonne */
+@media (max-width: 768px) {
+ .settings-grid-compact {
+ grid-template-columns: repeat(2, 1fr);
+ }
+ .input-narrow {
+ max-width: 100% !important;
+ }
+}
+
.auction-log, .bidders-stats {
margin: 0.25rem;
}
@@ -1248,56 +1293,56 @@ main {
margin-right: 0.5rem;
}
+
/* === PRODUCT INFO COMPATTO === */
.product-info-compact {
display: flex;
flex-direction: column;
- gap: 1rem;
+ gap: 0.5rem;
}
-/* Card info principali - orizzontali */
+/* Card info principali - orizzontali compatte */
.info-cards {
display: grid;
grid-template-columns: repeat(2, 1fr);
- gap: 0.75rem;
+ gap: 0.4rem;
}
.info-card {
display: flex;
align-items: center;
- gap: 0.75rem;
- padding: 0.75rem 1rem;
- border-radius: 6px;
+ gap: 0.5rem;
+ padding: 0.4rem 0.6rem;
+ border-radius: 4px;
border: 1px solid;
- transition: all 0.2s ease;
+ transition: background-color 0.2s ease;
}
.info-card:hover {
- transform: translateY(-1px);
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
+ background: var(--bg-hover);
}
.info-card i {
- font-size: 1.75rem;
+ font-size: 1.1rem;
flex-shrink: 0;
}
.info-card div {
display: flex;
flex-direction: column;
- gap: 0.125rem;
+ gap: 0;
}
.info-card small {
- font-size: 0.688rem;
+ font-size: 0.6rem;
text-transform: uppercase;
- letter-spacing: 0.5px;
+ letter-spacing: 0.3px;
color: var(--text-muted);
font-weight: 500;
}
.info-card strong {
- font-size: 1.125rem;
+ font-size: 0.9rem;
font-weight: 700;
color: var(--text-primary);
}
@@ -1320,26 +1365,26 @@ main {
color: var(--info-color);
}
-/* Calcoli inline - 4 colonne */
+/* Calcoli inline - 4 colonne compatte */
.calc-inline {
display: grid;
grid-template-columns: repeat(4, 1fr);
- gap: 0.5rem;
- padding: 0.75rem;
+ gap: 0.3rem;
+ padding: 0.4rem;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
- border-radius: 6px;
+ border-radius: 4px;
}
.calc-item {
display: flex;
flex-direction: column;
align-items: center;
- gap: 0.25rem;
- padding: 0.5rem;
+ gap: 0.1rem;
+ padding: 0.25rem;
text-align: center;
- border-radius: 4px;
- transition: all 0.2s ease;
+ border-radius: 3px;
+ transition: background-color 0.2s ease;
}
.calc-item:hover {
@@ -1352,7 +1397,7 @@ main {
}
.calc-item i {
- font-size: 1.25rem;
+ font-size: 0.9rem;
color: var(--primary-color);
}
@@ -1361,13 +1406,13 @@ main {
}
.calc-item .label {
- font-size: 0.688rem;
+ font-size: 0.6rem;
color: var(--text-muted);
font-weight: 500;
}
.calc-item .value {
- font-size: 1rem;
+ font-size: 0.85rem;
font-weight: 700;
color: var(--text-primary);
}
@@ -1376,30 +1421,30 @@ main {
.totals-compact {
display: grid;
grid-template-columns: 1fr 1fr auto;
- gap: 0.75rem;
+ gap: 0.4rem;
align-items: center;
}
.total-item {
display: flex;
flex-direction: column;
- gap: 0.25rem;
- padding: 0.75rem;
+ gap: 0.1rem;
+ padding: 0.4rem 0.6rem;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
- border-radius: 6px;
+ border-radius: 4px;
}
.total-item span {
- font-size: 0.75rem;
+ font-size: 0.65rem;
color: var(--text-muted);
display: flex;
align-items: center;
- gap: 0.375rem;
+ gap: 0.2rem;
}
.total-item strong {
- font-size: 1.125rem;
+ font-size: 0.9rem;
font-weight: 700;
}
@@ -1419,10 +1464,10 @@ main {
display: flex;
align-items: center;
justify-content: center;
- gap: 0.5rem;
- padding: 0.75rem 1.5rem;
- border-radius: 6px;
- font-size: 1rem;
+ gap: 0.3rem;
+ padding: 0.4rem 0.8rem;
+ border-radius: 4px;
+ font-size: 0.75rem;
font-weight: 700;
white-space: nowrap;
}
@@ -1440,7 +1485,7 @@ main {
}
.verdict-badge i {
- font-size: 1.125rem;
+ font-size: 0.85rem;
}
/* === RESPONSIVE === */
|