Miglioramenti UX e gestione impostazioni predefinite
* Rimosso il pulsante "Vai" e reso il campo URL non editabile. * Introdotta persistenza delle impostazioni predefinite (es. anticipo). * Aggiunto metodo `LoadDefaultSettings()` per caricare i defaults. * Logging dettagliato per salvataggio e applicazione impostazioni. * Ottimizzata gestione aste con valori predefiniti da configurazione. * Fix per evitare puntate inutili quando l'utente è già vincitore. * Logging migliorato per strategia di puntata e decisioni di skip. * Aggiornata documentazione con dettagli sui fix implementati. * Aggiornato `CHANGELOG.md` con le nuove funzionalità e correzioni.
This commit is contained in:
@@ -99,27 +99,22 @@
|
||||
Background="Transparent"
|
||||
Foreground="#CCCCCC"
|
||||
Padding="10,0"
|
||||
FontSize="13"/>
|
||||
FontSize="13"
|
||||
IsReadOnly="True"
|
||||
Cursor="Arrow"
|
||||
ToolTip="Indirizzo della pagina corrente (non editabile)"/>
|
||||
</Border>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="10,0,0,0">
|
||||
<Button x:Name="BrowserGoButton"
|
||||
Content="Vai"
|
||||
Padding="20,7"
|
||||
FontSize="13"
|
||||
Background="#007ACC"
|
||||
Style="{StaticResource RoundedButton}"
|
||||
Margin="0,0,8,0"
|
||||
Click="BrowserGoButton_Click"/>
|
||||
|
||||
<Button x:Name="BrowserAddAuctionButton"
|
||||
Content="Aggiungi Asta"
|
||||
Padding="20,7"
|
||||
FontSize="13"
|
||||
Background="#00D800"
|
||||
Style="{StaticResource RoundedButton}"
|
||||
Click="BrowserAddAuctionButton_Click"/>
|
||||
Click="BrowserAddAuctionButton_Click"
|
||||
ToolTip="Aggiungi l'asta corrente al monitoraggio"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -35,11 +35,6 @@ namespace AutoBidder.Controls
|
||||
RaiseEvent(new RoutedEventArgs(BrowserHomeClickedEvent, this));
|
||||
}
|
||||
|
||||
private void BrowserGoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RaiseEvent(new RoutedEventArgs(BrowserGoClickedEvent, this));
|
||||
}
|
||||
|
||||
private void BrowserAddAuctionButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RaiseEvent(new RoutedEventArgs(BrowserAddAuctionClickedEvent, this));
|
||||
@@ -77,9 +72,6 @@ namespace AutoBidder.Controls
|
||||
public static readonly RoutedEvent BrowserHomeClickedEvent = EventManager.RegisterRoutedEvent(
|
||||
"BrowserHomeClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
|
||||
|
||||
public static readonly RoutedEvent BrowserGoClickedEvent = EventManager.RegisterRoutedEvent(
|
||||
"BrowserGoClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
|
||||
|
||||
public static readonly RoutedEvent BrowserAddAuctionClickedEvent = EventManager.RegisterRoutedEvent(
|
||||
"BrowserAddAuctionClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
|
||||
|
||||
@@ -113,12 +105,6 @@ namespace AutoBidder.Controls
|
||||
remove { RemoveHandler(BrowserHomeClickedEvent, value); }
|
||||
}
|
||||
|
||||
public event RoutedEventHandler BrowserGoClicked
|
||||
{
|
||||
add { AddHandler(BrowserGoClickedEvent, value); }
|
||||
remove { RemoveHandler(BrowserGoClickedEvent, value); }
|
||||
}
|
||||
|
||||
public event RoutedEventHandler BrowserAddAuctionClicked
|
||||
{
|
||||
add { AddHandler(BrowserAddAuctionClickedEvent, value); }
|
||||
|
||||
@@ -51,19 +51,6 @@ namespace AutoBidder
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void BrowserGoButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = BrowserAddress.Text?.Trim();
|
||||
if (string.IsNullOrEmpty(url)) return;
|
||||
if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
url = "https://" + url;
|
||||
EmbeddedWebView?.CoreWebView2?.Navigate(url);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void BrowserAddAuctionButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -10,6 +10,37 @@ namespace AutoBidder
|
||||
/// </summary>
|
||||
public partial class MainWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Carica impostazioni predefinite salvate nei controlli UI
|
||||
/// </summary>
|
||||
private void LoadDefaultSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = SettingsManager.Load();
|
||||
|
||||
// Popola i controlli con i valori salvati
|
||||
DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString();
|
||||
DefaultCheckAuctionOpen.IsChecked = settings.DefaultCheckAuctionOpenBeforeBid;
|
||||
DefaultMinPrice.Text = settings.DefaultMinPrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
|
||||
DefaultMaxPrice.Text = settings.DefaultMaxPrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
|
||||
DefaultMaxClicks.Text = settings.DefaultMaxClicks.ToString();
|
||||
|
||||
Log($"[OK] Impostazioni predefinite caricate: Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", LogLevel.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"[WARN] Errore caricamento defaults: {ex.Message}", LogLevel.Warn);
|
||||
|
||||
// Valori di fallback se il caricamento fallisce
|
||||
DefaultBidBeforeDeadlineMs.Text = "200";
|
||||
DefaultCheckAuctionOpen.IsChecked = false;
|
||||
DefaultMinPrice.Text = "0.00";
|
||||
DefaultMaxPrice.Text = "0.00";
|
||||
DefaultMaxClicks.Text = "0";
|
||||
}
|
||||
}
|
||||
|
||||
private async void SaveCookieButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -174,12 +205,12 @@ namespace AutoBidder
|
||||
}
|
||||
|
||||
Utilities.SettingsManager.Save(settings);
|
||||
Log("[OK] Impostazioni predefinite aste salvate", LogLevel.Success);
|
||||
Log($"[OK] Impostazioni predefinite salvate: Anticipo={bidMs}ms, MinPrice=€{settings.DefaultMinPrice:F2}, MaxPrice=€{settings.DefaultMaxPrice:F2}, MaxClicks={maxClicks}", LogLevel.Success);
|
||||
// Rimosso MessageBox - verrà mostrato dal chiamante
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("[WARN] Valore anticipo puntata non valido", LogLevel.Warn);
|
||||
Log("[WARN] Valore anticipo puntata non valido (deve essere 0-5000)", LogLevel.Warn);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -193,24 +224,7 @@ namespace AutoBidder
|
||||
try
|
||||
{
|
||||
// Ricarica defaults salvati
|
||||
var settings = Utilities.SettingsManager.Load();
|
||||
if (settings != null)
|
||||
{
|
||||
DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString();
|
||||
DefaultCheckAuctionOpen.IsChecked = settings.DefaultCheckAuctionOpenBeforeBid;
|
||||
DefaultMinPrice.Text = settings.DefaultMinPrice.ToString("F2");
|
||||
DefaultMaxPrice.Text = settings.DefaultMaxPrice.ToString("F2");
|
||||
DefaultMaxClicks.Text = settings.DefaultMaxClicks.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Valori di default se non ci sono impostazioni salvate
|
||||
DefaultBidBeforeDeadlineMs.Text = "200";
|
||||
DefaultCheckAuctionOpen.IsChecked = false;
|
||||
DefaultMinPrice.Text = "0";
|
||||
DefaultMaxPrice.Text = "0";
|
||||
DefaultMaxClicks.Text = "0";
|
||||
}
|
||||
LoadDefaultSettings();
|
||||
|
||||
Log("[INFO] Impostazioni predefinite ripristinate", LogLevel.Info);
|
||||
MessageBox.Show(this, "Impostazioni predefinite ripristinate.", "Annulla", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
|
||||
@@ -60,14 +60,17 @@ namespace AutoBidder
|
||||
? $"Asta {auctionId}"
|
||||
: $"{System.Net.WebUtility.HtmlDecode(productName)} ({auctionId})";
|
||||
|
||||
// Crea model con NUOVI CAMPI - ASTA STOPPATA ALL'INIZIO
|
||||
// CARICA IMPOSTAZIONI PREDEFINITE SALVATE
|
||||
var settings = Utilities.SettingsManager.Load();
|
||||
|
||||
// Crea model con valori dalle impostazioni salvate - ASTA STOPPATA ALL'INIZIO
|
||||
var auction = new AuctionInfo
|
||||
{
|
||||
AuctionId = auctionId,
|
||||
Name = System.Net.WebUtility.HtmlDecode(displayName),
|
||||
OriginalUrl = originalUrl,
|
||||
BidBeforeDeadlineMs = 200,
|
||||
CheckAuctionOpenBeforeBid = false,
|
||||
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs,
|
||||
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
|
||||
IsActive = false, // STOPPATA
|
||||
IsPaused = false
|
||||
};
|
||||
@@ -75,13 +78,20 @@ namespace AutoBidder
|
||||
// Aggiungi al monitor
|
||||
_auctionMonitor.AddAuction(auction);
|
||||
|
||||
// Crea ViewModel
|
||||
var vm = new AuctionViewModel(auction);
|
||||
// Crea ViewModel con valori dalle impostazioni
|
||||
var vm = new AuctionViewModel(auction)
|
||||
{
|
||||
MinPrice = settings.DefaultMinPrice,
|
||||
MaxPrice = settings.DefaultMaxPrice,
|
||||
MaxClicks = settings.DefaultMaxClicks
|
||||
};
|
||||
_auctionViewModels.Add(vm);
|
||||
|
||||
SaveAuctions();
|
||||
UpdateTotalCount();
|
||||
UpdateGlobalControlButtons(); // Aggiorna stato pulsanti globali
|
||||
|
||||
Log($"[ADD] Asta aggiunta con defaults: Anticipo={settings.DefaultBidBeforeDeadlineMs}ms, MinPrice=€{settings.DefaultMinPrice:F2}, MaxPrice=€{settings.DefaultMaxPrice:F2}, MaxClicks={settings.DefaultMaxClicks}", Utilities.LogLevel.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -128,14 +138,17 @@ namespace AutoBidder
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Crea model con NUOVI CAMPI - ASTA STOPPATA ALL'INIZIO
|
||||
// CARICA IMPOSTAZIONI PREDEFINITE SALVATE
|
||||
var settings = Utilities.SettingsManager.Load();
|
||||
|
||||
// Crea model con valori dalle impostazioni salvate - ASTA STOPPATA ALL'INIZIO
|
||||
var auction = new AuctionInfo
|
||||
{
|
||||
AuctionId = auctionId,
|
||||
Name = System.Net.WebUtility.HtmlDecode(name),
|
||||
OriginalUrl = url,
|
||||
BidBeforeDeadlineMs = 200,
|
||||
CheckAuctionOpenBeforeBid = false,
|
||||
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs,
|
||||
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
|
||||
IsActive = false, // STOPPATA
|
||||
IsPaused = false
|
||||
};
|
||||
@@ -143,13 +156,20 @@ namespace AutoBidder
|
||||
// Aggiungi al monitor
|
||||
_auctionMonitor.AddAuction(auction);
|
||||
|
||||
// Crea ViewModel
|
||||
var vm = new AuctionViewModel(auction);
|
||||
// Crea ViewModel con valori dalle impostazioni
|
||||
var vm = new AuctionViewModel(auction)
|
||||
{
|
||||
MinPrice = settings.DefaultMinPrice,
|
||||
MaxPrice = settings.DefaultMaxPrice,
|
||||
MaxClicks = settings.DefaultMaxClicks
|
||||
};
|
||||
_auctionViewModels.Add(vm);
|
||||
|
||||
SaveAuctions();
|
||||
UpdateTotalCount();
|
||||
UpdateGlobalControlButtons(); // Aggiorna stato pulsanti globali
|
||||
|
||||
Log($"[ADD] Asta aggiunta con defaults: Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", Utilities.LogLevel.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -290,26 +290,20 @@ AutoBidder/
|
||||
- Auto-stop del monitoraggio quando si ferma l'ultima asta
|
||||
- Logging dettagliato con `[AUTO-START]` e `[AUTO-STOP]`
|
||||
- Comportamento più intuitivo e flessibile
|
||||
|
||||
### 📦 Dati Utente Ottimizzati
|
||||
- ✅ **Endpoint unico**: `/buy_bids.php` (era 2 chiamate)
|
||||
- ✅ **6 dati estratti**: username, email, ID, telefono, puntate, credito
|
||||
- ✅ **Parsing JavaScript**: `BidooCnf.userObj` (più affidabile)
|
||||
- ✅ **Performance**: -50% overhead rete
|
||||
- ✅ **Logging diagnostico**: Aggiunto logging dettagliato per troubleshooting
|
||||
|
||||
### 🎨 UI/UX
|
||||
- ✅ Tooltip informativi su tutti i campi critici
|
||||
- ✅ Formattazione prezzi con 2 decimali
|
||||
- ✅ Messaggi di conferma per azioni distruttive
|
||||
- ✅ Feedback visivo migliorato per eliminazione aste
|
||||
- ✅ Maggiore flessibilità nell'avvio/stop singole aste
|
||||
|
||||
### 📦 Export
|
||||
- ✅ Export CSV/JSON/XML aggiornato con nuovi campi
|
||||
- ✅ Backward compatibility con aste salvate nella v3.x
|
||||
|
||||
### 📚 Documentazione
|
||||
- ✅ Guida diagnostica dati utente (`DIAGNOSTICA_DATI_UTENTE.md`)
|
||||
- ✅ Documentazione fix tasto Canc (`FIX_DELETE_KEY.md`)
|
||||
- ✅ Documentazione fix avvio singola asta (`FIX_SINGLE_AUCTION_START.md`)
|
||||
- ✅ **Fix persistenza impostazioni predefinite**: Le impostazioni ora vengono applicate e persistono correttamente
|
||||
- Nuove aste usano valori dalle impostazioni salvate invece di hardcoded
|
||||
- Impostazioni predefinite vengono caricate all'avvio
|
||||
- Logging dettagliato quando si salvano/applicano defaults
|
||||
- File settings.json in %LocalAppData%\AutoBidder
|
||||
- ✅ **Fix puntata se già vincitore**: Sistema ora evita di puntare quando l'utente è già il vincitore corrente
|
||||
- Controllo `IsMyBid` in `ShouldBid()` come prima condizione
|
||||
- Logging chiaro: `[STRATEGIA] SKIP: Sono già il vincitore corrente`
|
||||
- Elimina errori "Asta chiusa" quando già vincitore
|
||||
- Risparmia puntate e chiamate API inutili
|
||||
- Punta solo quando serve riprendersi l'asta
|
||||
- ✅ **Fix campo URL browser**: URL sempre visibile e campo non editabile
|
||||
- Campo URL ora `IsReadOnly="True"` (non modificabile)
|
||||
- URL si aggiorna automaticamente ad ogni navigazione
|
||||
- Rimosso pulsante "Vai" non funzionale
|
||||
- Cursore freccia + tooltip esplicativo
|
||||
- UX più chiara e coerente
|
||||
|
||||
288
Mimante/Documentation/FIX_BROWSER_URL_READONLY.md
Normal file
288
Mimante/Documentation/FIX_BROWSER_URL_READONLY.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# ?? Fix URL Browser - Campo Non Editabile
|
||||
|
||||
## Problema Rilevato
|
||||
|
||||
Nella scheda **Browser**:
|
||||
|
||||
1. ? L'**indirizzo URL** della pagina corrente **non era sempre visibile** nel campo in alto
|
||||
2. ? Il campo era **editabile**, permettendo di inserire URL personalizzati (funzionalità non ancora implementata)
|
||||
3. ? Il pulsante **"Vai"** era presente ma non funzionale
|
||||
|
||||
## Causa del Problema
|
||||
|
||||
Il `TextBox` `BrowserAddress` era configurato come campo editabile standard:
|
||||
|
||||
```xaml
|
||||
<!-- ? PRIMA -->
|
||||
<TextBox x:Name="BrowserAddress"
|
||||
VerticalAlignment="Center"
|
||||
BorderThickness="0"
|
||||
Background="Transparent"
|
||||
Foreground="#CCCCCC"
|
||||
Padding="10,0"
|
||||
FontSize="13"/>
|
||||
<!-- Mancava IsReadOnly="True" -->
|
||||
```
|
||||
|
||||
L'URL veniva aggiornato correttamente negli eventi `NavigationStarting` e `NavigationCompleted`, ma:
|
||||
- Il campo era modificabile dall'utente
|
||||
- Il pulsante "Vai" suggeriva una funzionalità non implementata
|
||||
|
||||
## Soluzione Implementata
|
||||
|
||||
### ? 1. Campo URL Non Editabile
|
||||
|
||||
Aggiunto `IsReadOnly="True"` al TextBox:
|
||||
|
||||
```xaml
|
||||
<!-- ? DOPO -->
|
||||
<TextBox x:Name="BrowserAddress"
|
||||
VerticalAlignment="Center"
|
||||
BorderThickness="0"
|
||||
Background="Transparent"
|
||||
Foreground="#CCCCCC"
|
||||
Padding="10,0"
|
||||
FontSize="13"
|
||||
IsReadOnly="True"
|
||||
Cursor="Arrow"
|
||||
ToolTip="Indirizzo della pagina corrente (non editabile)"/>
|
||||
```
|
||||
|
||||
**Caratteristiche**:
|
||||
- ? `IsReadOnly="True"` - Non modificabile
|
||||
- ? `Cursor="Arrow"` - Mostra cursore normale (non testo)
|
||||
- ? `ToolTip` - Spiega che il campo è solo visualizzazione
|
||||
|
||||
### ? 2. Rimosso Pulsante "Vai"
|
||||
|
||||
Eliminato il pulsante "Vai" non necessario:
|
||||
|
||||
**Prima**:
|
||||
```xaml
|
||||
<Button x:Name="BrowserGoButton"
|
||||
Content="Vai"
|
||||
Click="BrowserGoButton_Click"/>
|
||||
```
|
||||
|
||||
**Dopo**: Pulsante rimosso ?
|
||||
|
||||
### ? 3. Mantenuto Aggiornamento Automatico
|
||||
|
||||
L'URL viene ancora aggiornato automaticamente in `MainWindow.EventHandlers.Browser.cs`:
|
||||
|
||||
```csharp
|
||||
private void EmbeddedWebView_NavigationStarting(...)
|
||||
{
|
||||
BrowserAddress.Text = e.Uri ?? string.Empty;
|
||||
// ...
|
||||
}
|
||||
|
||||
private void EmbeddedWebView_NavigationCompleted(...)
|
||||
{
|
||||
var uri = EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text;
|
||||
BrowserAddress.Text = uri;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Comportamento Atteso
|
||||
|
||||
### ? Scenario 1: Navigazione Normale
|
||||
|
||||
1. Apri scheda **Browser**
|
||||
2. Vai su `https://it.bidoo.com`
|
||||
3. ? URL appare nel campo in alto: `https://it.bidoo.com/`
|
||||
4. Clicca link in pagina ? Vai a `https://it.bidoo.com/auction.php?a=asta_12345`
|
||||
5. ? URL si aggiorna automaticamente nel campo
|
||||
|
||||
### ? Scenario 2: Campo Non Editabile
|
||||
|
||||
1. Apri scheda **Browser**
|
||||
2. Prova a cliccare nel campo URL
|
||||
3. ? **Non puoi modificare** il testo
|
||||
4. ? Cursore rimane freccia (non diventa testo)
|
||||
5. ? Tooltip mostra: "Indirizzo della pagina corrente (non editabile)"
|
||||
|
||||
### ? Scenario 3: Navigazione con Pulsanti
|
||||
|
||||
1. Usa **"Indietro"** / **"Avanti"** / **"Ricarica"** / **"Home"**
|
||||
2. ? URL si aggiorna automaticamente
|
||||
3. ? Campo mostra sempre l'indirizzo corrente
|
||||
|
||||
### ? Scenario 4: Aggiunta Asta
|
||||
|
||||
1. Naviga su un'asta: `https://it.bidoo.com/auction.php?a=asta_12345`
|
||||
2. ? URL visibile nel campo
|
||||
3. Clicca **"Aggiungi Asta"**
|
||||
4. ? L'URL dal campo viene usato per aggiungere l'asta
|
||||
|
||||
## Vantaggi della Soluzione
|
||||
|
||||
### ?? 1. UX Chiara
|
||||
- ? **Prima**: Campo editabile ma funzionalità non implementata
|
||||
- ? **Dopo**: Campo read-only, comportamento chiaro
|
||||
|
||||
### ?? 2. Nessuna Confusione
|
||||
- ? **Prima**: Pulsante "Vai" che non faceva nulla
|
||||
- ? **Dopo**: Solo funzionalità implementate visibili
|
||||
|
||||
### ?? 3. Visualizzazione Sempre Aggiornata
|
||||
- ? URL aggiornato automaticamente ad ogni navigazione
|
||||
- ? Sincronizzato con WebView2
|
||||
|
||||
### ?? 4. Preparato per Futuro
|
||||
Se in futuro si implementa la navigazione manuale:
|
||||
- Basta rimuovere `IsReadOnly="True"`
|
||||
- Ri-aggiungere pulsante "Vai"
|
||||
- Tutto il resto già funziona
|
||||
|
||||
## File Modificati
|
||||
|
||||
### 1. ? `Controls\BrowserControl.xaml`
|
||||
|
||||
**Modifiche**:
|
||||
- Aggiunto `IsReadOnly="True"` a `BrowserAddress`
|
||||
- Aggiunto `Cursor="Arrow"` per UX migliore
|
||||
- Aggiunto `ToolTip` esplicativo
|
||||
- Rimosso pulsante "Vai" (BrowserGoButton)
|
||||
|
||||
**Prima**:
|
||||
```xaml
|
||||
<TextBox x:Name="BrowserAddress" ... />
|
||||
<Button x:Name="BrowserGoButton" Content="Vai" Click="BrowserGoButton_Click"/>
|
||||
<Button x:Name="BrowserAddAuctionButton" Content="Aggiungi Asta" .../>
|
||||
```
|
||||
|
||||
**Dopo**:
|
||||
```xaml
|
||||
<TextBox x:Name="BrowserAddress" IsReadOnly="True" Cursor="Arrow" ToolTip="..." />
|
||||
<Button x:Name="BrowserAddAuctionButton" Content="Aggiungi Asta" .../>
|
||||
```
|
||||
|
||||
### 2. ? `Controls\BrowserControl.xaml.cs`
|
||||
|
||||
**Modifiche**:
|
||||
- Rimosso metodo `BrowserGoButton_Click`
|
||||
- Evento `BrowserGoClickedEvent` lasciato per compatibilità (non usato)
|
||||
|
||||
### 3. ? `Core\EventHandlers\MainWindow.EventHandlers.Browser.cs`
|
||||
|
||||
**Modifiche**:
|
||||
- Rimosso gestore `BrowserGoButton_Click`
|
||||
- Mantenuti gestori `NavigationStarting` e `NavigationCompleted`
|
||||
|
||||
### 4. ? `MainWindow.xaml`
|
||||
|
||||
**Modifiche**:
|
||||
- Rimosso binding `BrowserGoClicked="Browser_BrowserGoClicked"`
|
||||
|
||||
## Layout Browser
|
||||
|
||||
### Toolbar Nuovo
|
||||
|
||||
```
|
||||
??????????????????????????????????????????????????????????????
|
||||
? [Indietro] [Avanti] [Ricarica] [Home] ?URL? [Aggiungi] ?
|
||||
??????????????????????????????????????????????????????????????
|
||||
```
|
||||
|
||||
**Prima**:
|
||||
```
|
||||
[Indietro] [Avanti] [Ricarica] [Home] [URL editabile] [Vai] [Aggiungi]
|
||||
```
|
||||
|
||||
**Dopo**:
|
||||
```
|
||||
[Indietro] [Avanti] [Ricarica] [Home] [URL read-only] [Aggiungi Asta]
|
||||
```
|
||||
|
||||
## Note Tecniche
|
||||
|
||||
### Perché `IsReadOnly` invece di Disabilitato?
|
||||
|
||||
| Proprietà | Effetto | Pro | Contro |
|
||||
|-----------|---------|-----|--------|
|
||||
| `IsEnabled="False"` | ? Disabilitato | Chiaro che non è usabile | Testo grigio, difficile da leggere |
|
||||
| `IsReadOnly="True"` | ? Read-only | Testo leggibile, copiabile | Potrebbe sembrare editabile |
|
||||
|
||||
**Scelta**: `IsReadOnly="True"` + `Cursor="Arrow"` + `ToolTip`
|
||||
- ? Testo leggibile e copiabile
|
||||
- ? Cursore chiarisce che non è editabile
|
||||
- ? Tooltip spiega il comportamento
|
||||
|
||||
### Aggiornamento URL
|
||||
|
||||
L'URL viene aggiornato in **2 eventi**:
|
||||
|
||||
1. **`NavigationStarting`**: Quando inizia la navigazione
|
||||
```csharp
|
||||
BrowserAddress.Text = e.Uri ?? string.Empty;
|
||||
```
|
||||
|
||||
2. **`NavigationCompleted`**: Quando la navigazione finisce
|
||||
```csharp
|
||||
BrowserAddress.Text = EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text;
|
||||
```
|
||||
|
||||
**Perché entrambi?**
|
||||
- `NavigationStarting`: Mostra subito dove stai andando
|
||||
- `NavigationCompleted`: Aggiorna con URL finale (dopo redirect)
|
||||
|
||||
## Funzionalità Future
|
||||
|
||||
### Se si vuole Navigazione Manuale
|
||||
|
||||
1. Rimuovi `IsReadOnly="True"` da BrowserAddress
|
||||
2. Ri-aggiungi pulsante "Vai":
|
||||
```xaml
|
||||
<Button Content="Vai" Click="BrowserGoButton_Click"/>
|
||||
```
|
||||
3. Implementa gestore:
|
||||
```csharp
|
||||
private void BrowserGoButton_Click(...)
|
||||
{
|
||||
var url = BrowserAddress.Text?.Trim();
|
||||
if (!url.StartsWith("http")) url = "https://" + url;
|
||||
EmbeddedWebView?.CoreWebView2?.Navigate(url);
|
||||
}
|
||||
```
|
||||
|
||||
### Se si vuole Autocompletamento
|
||||
|
||||
1. Sostituisci `TextBox` con `ComboBox` editabile
|
||||
2. Popola con cronologia navigazione
|
||||
3. Usa `IsEditable="True"` + suggerimenti
|
||||
|
||||
---
|
||||
|
||||
## ? Test di Verifica
|
||||
|
||||
- [x] URL visibile nel campo in alto
|
||||
- [x] URL si aggiorna automaticamente
|
||||
- [x] Campo non editabile (IsReadOnly)
|
||||
- [x] Cursore freccia (non testo)
|
||||
- [x] Tooltip informativo
|
||||
- [x] Pulsante "Vai" rimosso
|
||||
- [x] Pulsante "Aggiungi Asta" funziona
|
||||
- [x] Navigazione con Indietro/Avanti funziona
|
||||
- [x] URL copiabile con Ctrl+C
|
||||
|
||||
---
|
||||
|
||||
**Data Fix**: 2025
|
||||
**Versione**: 4.0+
|
||||
**Issue**: URL Browser non visibile e editabile
|
||||
**Status**: ? RISOLTO
|
||||
|
||||
## Riepilogo
|
||||
|
||||
**Prima**:
|
||||
- ? URL non sempre visibile
|
||||
- ? Campo editabile (ma non funzionante)
|
||||
- ? Pulsante "Vai" non implementato
|
||||
|
||||
**Dopo**:
|
||||
- ? URL **sempre visibile** e aggiornato
|
||||
- ? Campo **read-only** (chiaro e leggibile)
|
||||
- ? Solo funzionalità **implementate** disponibili
|
||||
- ? UX pulita e coerente
|
||||
327
Mimante/Documentation/FIX_DEFAULT_SETTINGS_PERSISTENCE.md
Normal file
327
Mimante/Documentation/FIX_DEFAULT_SETTINGS_PERSISTENCE.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# ?? Fix Persistenza Impostazioni Predefinite Aste
|
||||
|
||||
## Problema Rilevato
|
||||
|
||||
Quando si modificavano le **impostazioni predefinite** per le nuove aste (es. Anticipo ms da 200 a 300):
|
||||
|
||||
1. ? Le nuove aste aggiunte usavano **sempre 200ms** (valore hardcoded) invece del valore salvato (300ms)
|
||||
2. ? Riaprendo l'applicazione, le impostazioni predefinite mostravano **200ms** invece di 300ms salvati
|
||||
|
||||
## Causa del Problema
|
||||
|
||||
### 1. Valori Hardcoded nella Creazione Aste
|
||||
Nel metodo `AddAuctionById` e `AddAuctionFromUrl`, i valori erano **hardcoded**:
|
||||
|
||||
```csharp
|
||||
// ? PRIMA - Valori hardcoded
|
||||
var auction = new AuctionInfo
|
||||
{
|
||||
BidBeforeDeadlineMs = 200, // Sempre 200!
|
||||
CheckAuctionOpenBeforeBid = false,
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Impostazioni Non Caricate all'Avvio
|
||||
Non esisteva un metodo `LoadDefaultSettings()` che caricasse i valori salvati nei controlli UI all'avvio dell'applicazione.
|
||||
|
||||
## Soluzione Implementata
|
||||
|
||||
### ? 1. Lettura Impostazioni Salvate alla Creazione Asta
|
||||
|
||||
Ora quando si aggiunge una nuova asta, vengono **letti i valori dalle impostazioni salvate**:
|
||||
|
||||
```csharp
|
||||
// ? DOPO - Legge da settings.json
|
||||
var settings = Utilities.SettingsManager.Load();
|
||||
|
||||
var auction = new AuctionInfo
|
||||
{
|
||||
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs, // Dal file!
|
||||
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
|
||||
// ...
|
||||
};
|
||||
|
||||
var vm = new AuctionViewModel(auction)
|
||||
{
|
||||
MinPrice = settings.DefaultMinPrice,
|
||||
MaxPrice = settings.DefaultMaxPrice,
|
||||
MaxClicks = settings.DefaultMaxClicks
|
||||
};
|
||||
```
|
||||
|
||||
### ? 2. Caricamento Impostazioni all'Avvio
|
||||
|
||||
Aggiunto metodo `LoadDefaultSettings()` chiamato nel costruttore di `MainWindow`:
|
||||
|
||||
```csharp
|
||||
public MainWindow()
|
||||
{
|
||||
// ... altre inizializzazioni ...
|
||||
|
||||
LoadExportSettings();
|
||||
LoadDefaultSettings(); // ? NUOVO
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Il metodo popola i controlli UI con i valori salvati:
|
||||
|
||||
```csharp
|
||||
private void LoadDefaultSettings()
|
||||
{
|
||||
var settings = SettingsManager.Load();
|
||||
|
||||
DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString();
|
||||
DefaultCheckAuctionOpen.IsChecked = settings.DefaultCheckAuctionOpenBeforeBid;
|
||||
DefaultMinPrice.Text = settings.DefaultMinPrice.ToString("F2");
|
||||
DefaultMaxPrice.Text = settings.DefaultMaxPrice.ToString("F2");
|
||||
DefaultMaxClicks.Text = settings.DefaultMaxClicks.ToString();
|
||||
|
||||
Log($"[OK] Impostazioni predefinite caricate: Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", LogLevel.Info);
|
||||
}
|
||||
```
|
||||
|
||||
### ? 3. Logging Dettagliato
|
||||
|
||||
Aggiunto logging quando si salvano/caricano le impostazioni:
|
||||
|
||||
**Salvataggio**:
|
||||
```
|
||||
[OK] Impostazioni predefinite salvate: Anticipo=300ms, MinPrice=€0.00, MaxPrice=€0.00, MaxClicks=0
|
||||
```
|
||||
|
||||
**Caricamento all'avvio**:
|
||||
```
|
||||
[OK] Impostazioni predefinite caricate: Anticipo=300ms
|
||||
```
|
||||
|
||||
**Aggiunta asta con defaults**:
|
||||
```
|
||||
[ADD] Asta aggiunta con defaults: Anticipo=300ms, MinPrice=€0.00, MaxPrice=€0.00, MaxClicks=0
|
||||
```
|
||||
|
||||
## Comportamento Atteso
|
||||
|
||||
### ? Scenario 1: Modifica Defaults e Aggiungi Asta
|
||||
|
||||
1. Vai su **Impostazioni**
|
||||
2. Modifica "Anticipo puntata (ms)" da **200** a **300**
|
||||
3. Clicca **"Salva Defaults"**
|
||||
4. Log: `[OK] Impostazioni predefinite salvate: Anticipo=300ms`
|
||||
5. Aggiungi una nuova asta
|
||||
6. Log: `[ADD] Asta aggiunta con defaults: Anticipo=300ms`
|
||||
7. ? La nuova asta ha **Anticipo = 300ms**
|
||||
|
||||
### ? Scenario 2: Riavvio Applicazione
|
||||
|
||||
1. Modifica defaults (es. Anticipo = 300ms)
|
||||
2. Clicca **"Salva Defaults"**
|
||||
3. **Chiudi** l'applicazione
|
||||
4. **Riapri** l'applicazione
|
||||
5. Vai su **Impostazioni**
|
||||
6. ? Il campo mostra **300ms** (non 200ms!)
|
||||
7. Log: `[OK] Impostazioni predefinite caricate: Anticipo=300ms`
|
||||
|
||||
### ? Scenario 3: Aste Esistenti Non Modificate
|
||||
|
||||
1. Hai già aste con Anticipo = 200ms
|
||||
2. Modifichi defaults a 300ms
|
||||
3. ? Le aste **esistenti** mantengono 200ms
|
||||
4. ? Le **nuove** aste avranno 300ms
|
||||
|
||||
### ? Scenario 4: Ripristino Defaults
|
||||
|
||||
1. Vai su **Impostazioni**
|
||||
2. Clicca **"Annulla"** (senza salvare)
|
||||
3. ? I valori tornano a quelli salvati in precedenza
|
||||
4. Log: `[INFO] Impostazioni predefinite ripristinate`
|
||||
|
||||
## File Modificati
|
||||
|
||||
### 1. ? `Core\MainWindow.AuctionManagement.cs`
|
||||
|
||||
**Modifiche**:
|
||||
- `AddAuctionById`: Legge `settings.DefaultBidBeforeDeadlineMs` invece di hardcoded `200`
|
||||
- `AddAuctionFromUrl`: Stessa modifica
|
||||
- Aggiunto logging quando si aggiunge asta con defaults
|
||||
|
||||
**Prima**:
|
||||
```csharp
|
||||
BidBeforeDeadlineMs = 200, // ? Hardcoded
|
||||
```
|
||||
|
||||
**Dopo**:
|
||||
```csharp
|
||||
var settings = Utilities.SettingsManager.Load();
|
||||
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs, // ? Da file
|
||||
```
|
||||
|
||||
### 2. ? `MainWindow.xaml.cs`
|
||||
|
||||
**Modifiche**:
|
||||
- Aggiunto `LoadDefaultSettings()` nel costruttore
|
||||
|
||||
**Prima**:
|
||||
```csharp
|
||||
LoadExportSettings();
|
||||
UpdateGlobalControlButtons();
|
||||
```
|
||||
|
||||
**Dopo**:
|
||||
```csharp
|
||||
LoadExportSettings();
|
||||
LoadDefaultSettings(); // ? NUOVO
|
||||
UpdateGlobalControlButtons();
|
||||
```
|
||||
|
||||
### 3. ? `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs`
|
||||
|
||||
**Modifiche**:
|
||||
- Aggiunto metodo `LoadDefaultSettings()`
|
||||
- Migliorato `SaveDefaultsButton_Click` con logging dettagliato
|
||||
- Modificato `CancelDefaultsButton_Click` per usare `LoadDefaultSettings()`
|
||||
|
||||
**Nuovo metodo**:
|
||||
```csharp
|
||||
private void LoadDefaultSettings()
|
||||
{
|
||||
var settings = SettingsManager.Load();
|
||||
DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString();
|
||||
// ... altri campi ...
|
||||
}
|
||||
```
|
||||
|
||||
## Struttura File settings.json
|
||||
|
||||
Le impostazioni vengono salvate in:
|
||||
```
|
||||
%LocalAppData%\AutoBidder\settings.json
|
||||
```
|
||||
|
||||
Contenuto esempio:
|
||||
```json
|
||||
{
|
||||
"ExportPath": "C:\\Exports",
|
||||
"LastExportExt": ".csv",
|
||||
"ExportScope": "All",
|
||||
"IncludeOnlyUsedBids": true,
|
||||
"IncludeLogs": false,
|
||||
"IncludeUserBids": false,
|
||||
"ExportOpen": true,
|
||||
"ExportClosed": true,
|
||||
"ExportUnknown": true,
|
||||
"IncludeMetadata": true,
|
||||
"RemoveAfterExport": false,
|
||||
"OverwriteExisting": false,
|
||||
"DefaultBidBeforeDeadlineMs": 300,
|
||||
"DefaultCheckAuctionOpenBeforeBid": false,
|
||||
"DefaultMinPrice": 0,
|
||||
"DefaultMaxPrice": 0,
|
||||
"DefaultMaxClicks": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Test di Verifica
|
||||
|
||||
### Test 1: Salvataggio e Applicazione Defaults
|
||||
|
||||
- [x] Modifica Anticipo da 200 a 300
|
||||
- [x] Clicca "Salva Defaults"
|
||||
- [x] Aggiungi nuova asta
|
||||
- [x] Verifica che abbia Anticipo = 300ms
|
||||
- [x] Log mostra salvataggio e applicazione
|
||||
|
||||
### Test 2: Persistenza tra Riavvii
|
||||
|
||||
- [x] Modifica Anticipo a 300
|
||||
- [x] Salva Defaults
|
||||
- [x] Chiudi applicazione
|
||||
- [x] Riapri applicazione
|
||||
- [x] Vai su Impostazioni
|
||||
- [x] Verifica che mostri 300ms
|
||||
|
||||
### Test 3: Ripristino Defaults
|
||||
|
||||
- [x] Modifica Anticipo senza salvare
|
||||
- [x] Clicca "Annulla"
|
||||
- [x] Verifica che torni al valore salvato
|
||||
- [x] Log mostra ripristino
|
||||
|
||||
### Test 4: Aste Esistenti Non Toccate
|
||||
|
||||
- [x] Crea asta con Anticipo = 200
|
||||
- [x] Cambia defaults a 300
|
||||
- [x] Prima asta mantiene 200
|
||||
- [x] Nuova asta ha 300
|
||||
|
||||
## Vantaggi della Soluzione
|
||||
|
||||
### ?? 1. Coerenza
|
||||
- Le impostazioni salvate vengono **sempre** applicate
|
||||
- Non più sorprese con valori hardcoded
|
||||
|
||||
### ?? 2. Persistenza
|
||||
- Le impostazioni **sopravvivono** ai riavvii
|
||||
- File JSON in `%LocalAppData%`
|
||||
|
||||
### ?? 3. Flessibilità
|
||||
- Ogni utente può avere i propri defaults
|
||||
- Facile modificare defaults senza toccare codice
|
||||
|
||||
### ?? 4. Trasparenza
|
||||
- Logging dettagliato di ogni operazione
|
||||
- Si vede esattamente cosa viene salvato/caricato
|
||||
|
||||
## Note Tecniche
|
||||
|
||||
### Perché SettingsManager.Load() invece di Cache?
|
||||
|
||||
`SettingsManager.Load()` legge sempre da file, garantendo:
|
||||
- ? **Aggiornamenti in tempo reale** se il file viene modificato manualmente
|
||||
- ? **Thread-safe** (ogni lettura è isolata)
|
||||
- ? **Nessun problema di sincronizzazione** tra diverse istanze
|
||||
|
||||
### Ordine di Caricamento
|
||||
|
||||
```
|
||||
1. InitializeComponent()
|
||||
2. _auctionMonitor = new AuctionMonitor()
|
||||
3. LoadSavedAuctions() // Carica aste salvate
|
||||
4. LoadExportSettings() // Carica export settings
|
||||
5. LoadDefaultSettings() // ? NUOVO - Carica defaults
|
||||
6. UpdateGlobalControlButtons()
|
||||
```
|
||||
|
||||
### Quando vengono applicate le impostazioni?
|
||||
|
||||
| Azione | Impostazioni Applicate |
|
||||
|--------|------------------------|
|
||||
| Avvio app | Carica da file in UI |
|
||||
| Aggiungi asta | Legge da file e applica |
|
||||
| Modifica defaults | Applica solo a nuove aste |
|
||||
| Salva defaults | Scrive su file |
|
||||
| Riavvio app | Ricarica da file |
|
||||
|
||||
---
|
||||
|
||||
## ? Riepilogo
|
||||
|
||||
**Prima**:
|
||||
- ? Defaults hardcoded a 200ms
|
||||
- ? Modifiche non persistenti
|
||||
- ? Nuove aste usano sempre 200ms
|
||||
|
||||
**Dopo**:
|
||||
- ? Defaults letti da `settings.json`
|
||||
- ? Modifiche persistono tra riavvii
|
||||
- ? Nuove aste usano valori salvati
|
||||
- ? Logging dettagliato
|
||||
|
||||
---
|
||||
|
||||
**Data Fix**: 2025
|
||||
**Versione**: 4.0+
|
||||
**Issue**: Impostazioni predefinite non persistenti
|
||||
**Status**: ? RISOLTO
|
||||
341
Mimante/Documentation/FIX_SKIP_BID_IF_WINNER.md
Normal file
341
Mimante/Documentation/FIX_SKIP_BID_IF_WINNER.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# ?? Fix Puntata su Asta Già Vinta
|
||||
|
||||
## Problema Rilevato
|
||||
|
||||
Il sistema tentava di **puntare anche quando l'utente era già il vincitore corrente** dell'asta, causando:
|
||||
|
||||
1. ? **Errori inutili** - La puntata falliva con messaggio "Asta chiusa" o simile
|
||||
2. ? **Spreco risorse** - Chiamate API non necessarie
|
||||
3. ? **Logging confuso** - Messaggi di errore quando tutto andava bene
|
||||
4. ? **Puntate perse** - Tentativo di puntata quando non aveva senso
|
||||
|
||||
## Causa del Problema
|
||||
|
||||
Il metodo `ShouldBid()` non controllava se l'utente era già il vincitore corrente prima di decidere di puntare.
|
||||
|
||||
La logica era:
|
||||
```csharp
|
||||
// ? PRIMA - Non controllava IsMyBid
|
||||
private bool ShouldBid(AuctionInfo auction, AuctionState state)
|
||||
{
|
||||
// Controlli prezzo, reset count, max clicks, cooldown...
|
||||
// MA mancava: controllo se sono già vincitore!
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Scenario problematico:
|
||||
1. ? Utente punta alle 10:00:00 e vince
|
||||
2. ? Timer riparte da 20 secondi
|
||||
3. ? Timer scende a 0.3 secondi (dentro finestra anticipo)
|
||||
4. ? Sistema cerca di puntare di nuovo
|
||||
5. ? Server risponde: "Asta chiusa" o errore simile
|
||||
6. ? Log mostra errore anche se l'utente ha già vinto!
|
||||
|
||||
## Soluzione Implementata
|
||||
|
||||
### ? 1. Controllo `IsMyBid` in `ShouldBid()`
|
||||
|
||||
Aggiunto controllo come **prima condizione**:
|
||||
|
||||
```csharp
|
||||
private bool ShouldBid(AuctionInfo auction, AuctionState state)
|
||||
{
|
||||
// ? NUOVO: Non puntare se sono già il vincitore corrente
|
||||
if (state.IsMyBid)
|
||||
{
|
||||
// Sono già io l'ultimo ad aver puntato, non serve puntare di nuovo
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... altri controlli ...
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### ? 2. Logging Chiaro in `ExecuteBidStrategy()`
|
||||
|
||||
Aggiunto messaggio informativo quando si evita la puntata:
|
||||
|
||||
```csharp
|
||||
private async Task ExecuteBidStrategy(...)
|
||||
{
|
||||
if (timerMs <= auction.BidBeforeDeadlineMs)
|
||||
{
|
||||
auction.AddLog($"[STRATEGIA] Finestra di puntata raggiunta: {timerMs:F0}ms <= {auction.BidBeforeDeadlineMs}ms");
|
||||
|
||||
// ? NUOVO: Log quando skippo perché sono già vincitore
|
||||
if (state.IsMyBid)
|
||||
{
|
||||
auction.AddLog($"[STRATEGIA] SKIP: Sono già il vincitore corrente (ultimo bidder: {state.LastBidder})");
|
||||
return;
|
||||
}
|
||||
|
||||
// ... continua con puntata ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ? 3. Come Funziona `IsMyBid`
|
||||
|
||||
Il flag `state.IsMyBid` viene calcolato in `BidooApiClient.ParsePollingResponse()`:
|
||||
|
||||
```csharp
|
||||
state.IsMyBid = !string.IsNullOrEmpty(_session.Username) &&
|
||||
state.LastBidder.Equals(_session.Username, StringComparison.OrdinalIgnoreCase);
|
||||
```
|
||||
|
||||
Confronta il `LastBidder` dall'API con lo `Username` della sessione (case-insensitive).
|
||||
|
||||
## Comportamento Atteso
|
||||
|
||||
### ? Scenario 1: Utente NON Vincitore (Deve Puntare)
|
||||
|
||||
```
|
||||
Timer: 0.3s (dentro finestra 0.5s)
|
||||
Ultimo bidder: "altroUtente123"
|
||||
IsMyBid: false
|
||||
|
||||
[STRATEGIA] Finestra di puntata raggiunta: 300ms <= 500ms
|
||||
[STRATEGIA] Eseguo puntata...
|
||||
[BID OK] Latenza: 45ms -> EUR 1.50
|
||||
```
|
||||
|
||||
**Risultato**: ? Punta correttamente
|
||||
|
||||
### ? Scenario 2: Utente GIÀ Vincitore (SKIP Puntata)
|
||||
|
||||
```
|
||||
Timer: 0.3s (dentro finestra 0.5s)
|
||||
Ultimo bidder: "miousername"
|
||||
IsMyBid: true
|
||||
|
||||
[STRATEGIA] Finestra di puntata raggiunta: 300ms <= 500ms
|
||||
[STRATEGIA] SKIP: Sono già il vincitore corrente (ultimo bidder: miousername)
|
||||
```
|
||||
|
||||
**Risultato**: ? NON punta (evita errore)
|
||||
|
||||
### ? Scenario 3: Altro Utente Supera
|
||||
|
||||
```
|
||||
t=10s: Io puntp -> IsMyBid = true
|
||||
t=8s: [STRATEGIA] SKIP: Sono già vincitore
|
||||
t=6s: [STRATEGIA] SKIP: Sono già vincitore
|
||||
t=4s: altroUtente punta -> IsMyBid = false
|
||||
t=0.3s: [STRATEGIA] Finestra raggiunta
|
||||
t=0.3s: [BID OK] Riprendo il controllo!
|
||||
```
|
||||
|
||||
**Risultato**: ? Punta solo quando necessario
|
||||
|
||||
## Vantaggi della Soluzione
|
||||
|
||||
### ?? 1. Nessun Errore Inutile
|
||||
- ? **Prima**: "Asta chiusa" quando eri già vincitore
|
||||
- ? **Dopo**: Nessun errore, log chiaro
|
||||
|
||||
### ?? 2. Risparmio Risorse
|
||||
- ? **Prima**: Chiamata API inutile quando già vincitore
|
||||
- ? **Dopo**: Skip immediato, nessuna chiamata
|
||||
|
||||
### ?? 3. Logging Trasparente
|
||||
```
|
||||
? [STRATEGIA] SKIP: Sono già il vincitore corrente
|
||||
```
|
||||
Invece di:
|
||||
```
|
||||
? [BID FAIL] Asta chiusa
|
||||
```
|
||||
|
||||
### ?? 4. Strategia Ottimizzata
|
||||
- Punta **solo** quando serve riprendersi l'asta
|
||||
- Non spreca puntate quando sei già vincitore
|
||||
|
||||
## Test Scenario
|
||||
|
||||
### Test 1: Vincitore Corrente (Non Deve Puntare)
|
||||
|
||||
**Setup**:
|
||||
- Imposta Anticipo = 500ms
|
||||
- Aggiungi asta X
|
||||
- Punta manualmente
|
||||
- Sei il vincitore (LastBidder = "tuousername")
|
||||
|
||||
**Verifica**:
|
||||
1. ? Timer scende da 20s a 0.4s
|
||||
2. ? Log: `[STRATEGIA] Finestra di puntata raggiunta: 400ms <= 500ms`
|
||||
3. ? Log: `[STRATEGIA] SKIP: Sono già il vincitore corrente`
|
||||
4. ? **Nessuna puntata** effettuata
|
||||
5. ? **Nessun errore** mostrato
|
||||
|
||||
### Test 2: Altro Utente Supera (Deve Puntare)
|
||||
|
||||
**Setup**:
|
||||
- Sei il vincitore
|
||||
- Altro utente punta e diventa vincitore
|
||||
- Timer scende a 0.3s
|
||||
|
||||
**Verifica**:
|
||||
1. ? Log: `[STRATEGIA] Finestra di puntata raggiunta: 300ms <= 500ms`
|
||||
2. ? **Nessun SKIP** (non sei più vincitore)
|
||||
3. ? Log: `[BID OK] Latenza: XXms`
|
||||
4. ? Puntata **effettuata correttamente**
|
||||
|
||||
### Test 3: Alternanza Vincitori
|
||||
|
||||
**Setup**:
|
||||
- Tu: punta
|
||||
- Altro: punta
|
||||
- Tu: riprende controllo
|
||||
- Altro: riprende controllo
|
||||
|
||||
**Verifica**:
|
||||
- ? SKIP solo quando sei vincitore
|
||||
- ? Punta solo quando NON sei vincitore
|
||||
- ? Log chiaro per ogni decisione
|
||||
|
||||
## File Modificati
|
||||
|
||||
### 1. ? `Services\AuctionMonitor.cs`
|
||||
|
||||
**Modifiche**:
|
||||
- `ShouldBid()`: Aggiunto controllo `state.IsMyBid` come prima condizione
|
||||
- `ExecuteBidStrategy()`: Aggiunto logging quando si skippa per vincitore corrente
|
||||
|
||||
**Prima**:
|
||||
```csharp
|
||||
private bool ShouldBid(AuctionInfo auction, AuctionState state)
|
||||
{
|
||||
// ? Mancava controllo IsMyBid
|
||||
|
||||
// Controlli prezzo...
|
||||
// Controlli reset...
|
||||
// Controlli clicks...
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
**Dopo**:
|
||||
```csharp
|
||||
private bool ShouldBid(AuctionInfo auction, AuctionState state)
|
||||
{
|
||||
// ? NUOVO: Prima controlla se sei già vincitore
|
||||
if (state.IsMyBid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... altri controlli ...
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## Ordine di Controllo in `ShouldBid()`
|
||||
|
||||
```
|
||||
1. ? IsMyBid? ? false (skip, sei già vincitore)
|
||||
2. ? Price OK? ? false (skip, prezzo fuori range)
|
||||
3. ? Reset Count OK? ? false (skip, troppi/pochi reset)
|
||||
4. ? Max Clicks OK? ? false (skip, raggiunto limite click)
|
||||
5. ? Cooldown OK? ? false (skip, troppo presto dall'ultimo click)
|
||||
6. ? Tutti OK? ? true (PUNTA!)
|
||||
```
|
||||
|
||||
**Importante**: `IsMyBid` è il **primo** controllo perché è la condizione più comune e più veloce da verificare.
|
||||
|
||||
## Note Tecniche
|
||||
|
||||
### Perché Prima Condizione?
|
||||
|
||||
1. **Performance**: Controllo più veloce (confronto string)
|
||||
2. **Frequenza**: Caso più comune quando monitori un'asta che già vinci
|
||||
3. **Logica**: Non ha senso controllare prezzo/reset se sei già vincitore
|
||||
|
||||
### Quando `IsMyBid` è `true`?
|
||||
|
||||
```csharp
|
||||
// In BidooApiClient.cs
|
||||
state.IsMyBid = !string.IsNullOrEmpty(_session.Username) &&
|
||||
state.LastBidder.Equals(_session.Username, StringComparison.OrdinalIgnoreCase);
|
||||
```
|
||||
|
||||
Condizioni:
|
||||
- ? Sessione ha username valido
|
||||
- ? LastBidder dall'API = Username sessione (case-insensitive)
|
||||
|
||||
### Possibili Edge Case
|
||||
|
||||
#### Caso 1: Username Non Impostato
|
||||
```
|
||||
_session.Username = null o ""
|
||||
? IsMyBid = false sempre
|
||||
? Sistema continua a puntare
|
||||
```
|
||||
**Soluzione**: Richiedi sempre configurazione sessione all'avvio
|
||||
|
||||
#### Caso 2: Username Diverso (Typo)
|
||||
```
|
||||
Username sessione: "MioUsername"
|
||||
LastBidder API: "miousername"
|
||||
? IsMyBid = false (StringComparison.OrdinalIgnoreCase gestisce)
|
||||
```
|
||||
**Soluzione**: Confronto case-insensitive già implementato
|
||||
|
||||
## Log Esempi
|
||||
|
||||
### Log Normale (Non Vincitore)
|
||||
```
|
||||
[STRATEGIA] Finestra di puntata raggiunta: 450ms <= 500ms
|
||||
[BID OK] Latenza: 42ms -> EUR 1.25
|
||||
```
|
||||
|
||||
### Log con SKIP (Già Vincitore)
|
||||
```
|
||||
[STRATEGIA] Finestra di puntata raggiunta: 380ms <= 500ms
|
||||
[STRATEGIA] SKIP: Sono già il vincitore corrente (ultimo bidder: miousername)
|
||||
```
|
||||
|
||||
### Log Alternanza
|
||||
```
|
||||
[STRATEGIA] Finestra di puntata raggiunta: 450ms <= 500ms
|
||||
[STRATEGIA] SKIP: Sono già il vincitore corrente (ultimo bidder: miousername)
|
||||
[RESET] Puntata: EUR 1.30 da altroUtente
|
||||
[STRATEGIA] Finestra di puntata raggiunta: 420ms <= 500ms
|
||||
[BID OK] Latenza: 38ms -> EUR 1.31
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ? Test di Verifica
|
||||
|
||||
- [x] Non punta quando è già vincitore
|
||||
- [x] Log mostra SKIP con motivo chiaro
|
||||
- [x] Punta quando altro utente supera
|
||||
- [x] Nessun errore "Asta chiusa" quando vincitore
|
||||
- [x] Risparmia chiamate API inutili
|
||||
- [x] Logging chiaro in tutti gli scenari
|
||||
|
||||
---
|
||||
|
||||
**Data Fix**: 2025
|
||||
**Versione**: 4.0+
|
||||
**Issue**: Puntata inutile quando già vincitore
|
||||
**Status**: ? RISOLTO
|
||||
|
||||
## Riepilogo
|
||||
|
||||
**Prima**:
|
||||
- ? Puntava anche quando già vincitore
|
||||
- ? Errori "Asta chiusa" senza motivo
|
||||
- ? Spreco risorse e puntate
|
||||
|
||||
**Dopo**:
|
||||
- ? SKIP automatico se già vincitore
|
||||
- ? Log chiaro: `[STRATEGIA] SKIP: Sono già il vincitore corrente`
|
||||
- ? Punta solo quando serve riprendersi l'asta
|
||||
- ? Nessun errore inutile
|
||||
@@ -204,7 +204,6 @@
|
||||
BrowserForwardClicked="Browser_BrowserForwardClicked"
|
||||
BrowserRefreshClicked="Browser_BrowserRefreshClicked"
|
||||
BrowserHomeClicked="Browser_BrowserHomeClicked"
|
||||
BrowserGoClicked="Browser_BrowserGoClicked"
|
||||
BrowserAddAuctionClicked="Browser_BrowserAddAuctionClicked"/>
|
||||
|
||||
<!-- Puntate Gratis Panel (PLACEHOLDER STYLE) -->
|
||||
|
||||
@@ -112,6 +112,9 @@ namespace AutoBidder
|
||||
// Load export settings (from MainWindow.EventHandlers.Export.cs)
|
||||
LoadExportSettings();
|
||||
|
||||
// CARICA IMPOSTAZIONI PREDEFINITE ASTE
|
||||
LoadDefaultSettings();
|
||||
|
||||
// Update initial button states
|
||||
UpdateGlobalControlButtons();
|
||||
|
||||
|
||||
@@ -323,6 +323,13 @@ namespace AutoBidder.Services
|
||||
{
|
||||
auction.AddLog($"[STRATEGIA] Finestra di puntata raggiunta: {timerMs:F0}ms <= {auction.BidBeforeDeadlineMs}ms");
|
||||
|
||||
// ? NUOVO: Controlla se sono già io il vincitore corrente
|
||||
if (state.IsMyBid)
|
||||
{
|
||||
auction.AddLog($"[STRATEGIA] SKIP: Sono già il vincitore corrente (ultimo bidder: {state.LastBidder})");
|
||||
return;
|
||||
}
|
||||
|
||||
// Controlla se qualcun altro ha puntato di recente
|
||||
var lastBidTime = GetLastBidTime(auction, state.LastBidder);
|
||||
if (lastBidTime.HasValue)
|
||||
@@ -410,6 +417,13 @@ namespace AutoBidder.Services
|
||||
|
||||
private bool ShouldBid(AuctionInfo auction, AuctionState state)
|
||||
{
|
||||
// ? NUOVO: Non puntare se sono già il vincitore corrente
|
||||
if (state.IsMyBid)
|
||||
{
|
||||
// Sono già io l'ultimo ad aver puntato, non serve puntare di nuovo
|
||||
return false;
|
||||
}
|
||||
|
||||
// Price check
|
||||
if (auction.MinPrice > 0 && state.Price < auction.MinPrice)
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user