Compare commits
4 Commits
114697a1b2
...
fef7b909e7
| Author | SHA1 | Date | |
|---|---|---|---|
| fef7b909e7 | |||
| 139a9d62b7 | |||
| 4e16f50aeb | |||
| db1d99d424 |
+5
-1
@@ -4,6 +4,10 @@
|
|||||||
xmlns:local="clr-namespace:Mimante"
|
xmlns:local="clr-namespace:Mimante"
|
||||||
StartupUri="MainWindow.xaml">
|
StartupUri="MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="Converters/Converters.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
[Binary ICO placeholder removed in this environment]
|
||||||
@@ -15,4 +15,9 @@
|
|||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Ensure the application icon is included as a WPF Resource so Icon="Assets/app.ico" resolves -->
|
||||||
|
<Resource Include="Assets\app.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<Window x:Class="AutoBidder.BrowserWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
|
||||||
|
Title="Browser - Bidoo"
|
||||||
|
Height="800" Width="1200"
|
||||||
|
Background="#101219" Foreground="#E6EDF3">
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<Style x:Key="AddressBarStyle" TargetType="TextBox">
|
||||||
|
<Setter Property="Background" Value="#0B1220" />
|
||||||
|
<Setter Property="Foreground" Value="#E6EDF3" />
|
||||||
|
<Setter Property="BorderBrush" Value="#263143" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="Padding" Value="8,6" />
|
||||||
|
<Setter Property="FontSize" Value="13" />
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Barra navigazione -->
|
||||||
|
<Grid Grid.Row="0" Margin="12,12,12,6" Background="#0B1015">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button x:Name="BackButton" Grid.Column="0" Content="?" Click="BackButton_Click"
|
||||||
|
Background="#374151" Foreground="White" Padding="12,8" Margin="8,8,6,8"
|
||||||
|
BorderThickness="0" FontWeight="Bold" FontSize="14" MinWidth="40" Height="38" IsEnabled="False">
|
||||||
|
<Button.Template>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}" CornerRadius="6">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Button.Template>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button x:Name="RefreshButton" Grid.Column="1" Content="?" Click="RefreshButton_Click"
|
||||||
|
Background="#0EA5E9" Foreground="White" Padding="12,8" Margin="0,8,8,8"
|
||||||
|
BorderThickness="0" FontWeight="Bold" FontSize="16" MinWidth="40" Height="38">
|
||||||
|
<Button.Template>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}" CornerRadius="6">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Button.Template>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<TextBox x:Name="AddressBar" Grid.Column="2" Style="{StaticResource AddressBarStyle}"
|
||||||
|
Text="https://it.bidoo.com" KeyDown="AddressBar_KeyDown" Margin="0,8,8,8" />
|
||||||
|
|
||||||
|
<Button x:Name="NavigateButton" Grid.Column="3" Content="Vai" Click="NavigateButton_Click"
|
||||||
|
Background="#16A34A" Foreground="White" Padding="20,8" Margin="0,8,8,8"
|
||||||
|
BorderThickness="0" FontWeight="Bold" FontSize="14" Height="38">
|
||||||
|
<Button.Template>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}" CornerRadius="6">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Button.Template>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button x:Name="AddCurrentPageButton" Grid.Column="4" Content="? Aggiungi Asta" Click="AddCurrentPageButton_Click"
|
||||||
|
Background="#8B5CF6" Foreground="White" Padding="16,8" Margin="0,8,8,8"
|
||||||
|
BorderThickness="0" FontWeight="SemiBold" FontSize="13" Height="38">
|
||||||
|
<Button.Template>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}" CornerRadius="6">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Button.Template>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- WebView -->
|
||||||
|
<Border Grid.Row="1" Margin="12,0,12,12" CornerRadius="8" Background="#0B1015">
|
||||||
|
<wv2:WebView2 x:Name="webView" Source="https://it.bidoo.com" Margin="2" />
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Microsoft.Web.WebView2.Core;
|
||||||
|
|
||||||
|
namespace AutoBidder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Finestra browser separata per navigazione Bidoo
|
||||||
|
/// </summary>
|
||||||
|
public partial class BrowserWindow : Window
|
||||||
|
{
|
||||||
|
public event Action<string>? OnAddAuction;
|
||||||
|
|
||||||
|
public BrowserWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
Loaded += BrowserWindow_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void BrowserWindow_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (webView.CoreWebView2 == null)
|
||||||
|
{
|
||||||
|
await webView.EnsureCoreWebView2Async();
|
||||||
|
}
|
||||||
|
|
||||||
|
webView.NavigationCompleted += WebView_NavigationCompleted;
|
||||||
|
webView.NavigationStarting += WebView_NavigationStarting;
|
||||||
|
|
||||||
|
// Context menu per aggiungere asta
|
||||||
|
if (webView.CoreWebView2 != null)
|
||||||
|
{
|
||||||
|
webView.CoreWebView2.ContextMenuRequested += CoreWebView2_ContextMenuRequested;
|
||||||
|
webView.CoreWebView2.Navigate("https://it.bidoo.com");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Errore inizializzazione: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CoreWebView2_ContextMenuRequested(object? sender, CoreWebView2ContextMenuRequestedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentUrl = webView.CoreWebView2?.Source ?? "";
|
||||||
|
|
||||||
|
if (IsValidAuctionUrl(currentUrl) && webView.CoreWebView2 != null)
|
||||||
|
{
|
||||||
|
// Aggiungi voce menu contestuale
|
||||||
|
var menuItem = webView.CoreWebView2.Environment.CreateContextMenuItem(
|
||||||
|
"Aggiungi asta al monitoraggio",
|
||||||
|
null,
|
||||||
|
CoreWebView2ContextMenuItemKind.Command);
|
||||||
|
|
||||||
|
menuItem.CustomItemSelected += (s, args) =>
|
||||||
|
{
|
||||||
|
OnAddAuction?.Invoke(currentUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
e.MenuItems.Insert(0, menuItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WebView_NavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs e)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(e.Uri) && !IsBidooUrl(e.Uri))
|
||||||
|
{
|
||||||
|
e.Cancel = true;
|
||||||
|
MessageBox.Show("Solo domini Bidoo consentiti!", "Navigazione Bloccata", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WebView_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
BackButton.IsEnabled = webView.CoreWebView2?.CanGoBack ?? false;
|
||||||
|
|
||||||
|
var url = webView.CoreWebView2?.Source ?? "";
|
||||||
|
if (!string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
AddressBar.Text = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsBidooUrl(string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(url)) return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
var host = uri.Host.ToLowerInvariant();
|
||||||
|
|
||||||
|
return host.Contains("bidoo.com") || host.Contains("bidoo.it") ||
|
||||||
|
host.Contains("bidoo.fr") || host.Contains("bidoo.es") ||
|
||||||
|
host.Contains("bidoo.de");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValidAuctionUrl(string url)
|
||||||
|
{
|
||||||
|
if (!IsBidooUrl(url)) return false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
return uri.AbsolutePath.Contains("/asta/") || uri.Query.Contains("?a=");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BackButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
webView.CoreWebView2?.GoBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
webView.CoreWebView2?.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigateButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
NavigateToAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddressBar_KeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
NavigateToAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigateToAddress()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = AddressBar.Text.Trim();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(url)) return;
|
||||||
|
|
||||||
|
if (!url.StartsWith("http"))
|
||||||
|
{
|
||||||
|
url = "https://" + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsBidooUrl(url))
|
||||||
|
{
|
||||||
|
MessageBox.Show("Solo URL Bidoo consentiti!", "URL Non Valido", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webView.CoreWebView2?.Navigate(url);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Errore navigazione: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddCurrentPageButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var currentUrl = webView.CoreWebView2?.Source ?? "";
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(currentUrl) || !IsValidAuctionUrl(currentUrl))
|
||||||
|
{
|
||||||
|
MessageBox.Show("La pagina corrente non � un'asta valida!", "URL Non Valido", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnAddAuction?.Invoke(currentUrl);
|
||||||
|
MessageBox.Show("Asta aggiunta al monitoraggio!", "Successo", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
# ?? Changelog - AutoBidder
|
|
||||||
|
|
||||||
Tutte le modifiche significative a questo progetto saranno documentate in questo file.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [2.0.0] - 2024 - Multi-Auction Release ??
|
|
||||||
|
|
||||||
### ? Nuove Funzionalità
|
|
||||||
|
|
||||||
#### ?? Modalità Multi-Asta
|
|
||||||
- **Monitoraggio simultaneo** di tutte le aste nei preferiti di Bidoo
|
|
||||||
- **Selezione intelligente** dell'asta con timer più basso (priorità automatica)
|
|
||||||
- **Navigazione automatica** alla pagina preferiti (`https://it.bidoo.com/?tab=FAV`)
|
|
||||||
- **Scansione periodica** delle aste (ogni 5 secondi) per rilevare nuove aggiunte
|
|
||||||
- **Ottimizzazione risorse**: Una sola WebView invece di finestre multiple (~70% risparmio memoria)
|
|
||||||
|
|
||||||
#### ?? Interfaccia Utente
|
|
||||||
- Nuovo **selettore modalità**: `[Asta Singola]` / `[Multi-Asta]`
|
|
||||||
- Pannello **"Asta Attiva"** mostra:
|
|
||||||
- Nome dell'asta su cui AutoBidder sta puntando
|
|
||||||
- Numero totale di aste monitorate nei preferiti
|
|
||||||
- Indicatori visuali per modalità attiva (pulsante verde)
|
|
||||||
- Layout riorganizzato con spazio per nuovi elementi
|
|
||||||
|
|
||||||
#### ?? Funzionalità Asta Multipla
|
|
||||||
- **Algoritmo priorità**: Seleziona automaticamente asta più urgente
|
|
||||||
- **Gestione reset per asta**: Rilevamento e log specifico per ogni asta
|
|
||||||
- **Tracciamento bidder per asta**: Monitora chi punta su quale asta
|
|
||||||
- **Limiti applicati globalmente**: Max clicks, max resets, min/max price funzionano su tutte le aste
|
|
||||||
- **Click intelligente**: Punta sull'asta prioritaria al momento giusto
|
|
||||||
|
|
||||||
#### ? Performance
|
|
||||||
- **Polling dinamico multi-asta**: Adatta frequenza lettura basandosi sul timer più basso
|
|
||||||
- **Script ottimizzati**: Lettura elementi DOM specifica per ID invece di query generiche
|
|
||||||
- **Cache elementi**: Riutilizzo bottoni e timer per velocità
|
|
||||||
- **Log dettagliato**: Ogni evento indica il nome dell'asta specifica
|
|
||||||
|
|
||||||
### ?? Miglioramenti
|
|
||||||
|
|
||||||
#### Codice
|
|
||||||
- Refactoring metodo `StartButton_Click` per supportare doppio loop
|
|
||||||
- Estratti metodi helper per gestione modalità:
|
|
||||||
- `SingleAuctionButton_Click()`
|
|
||||||
- `MultiAuctionButton_Click()`
|
|
||||||
- `UpdateModeButtons()`
|
|
||||||
- `UpdateActiveAuctionDisplay()`
|
|
||||||
- Nuove classi dati:
|
|
||||||
- `AuctionInfo`: Metadati permanenti asta
|
|
||||||
- `AuctionState`: Stato temporaneo snapshot
|
|
||||||
- Metodi core Multi-Asta:
|
|
||||||
- `MultiAuctionLoop()`: Loop principale multi-asta
|
|
||||||
- `ScanFavoriteAuctions()`: Scansione preferiti
|
|
||||||
- `ReadAllAuctionStates()`: Lettura stati parallela
|
|
||||||
- `PerformMultiAuctionClick()`: Click su asta specifica
|
|
||||||
|
|
||||||
#### Automazione Loop
|
|
||||||
- `AutomationLoop()` ora logga "Modalità: Asta Singola" per chiarezza
|
|
||||||
- `MultiAuctionLoop()` implementa strategia intelligente di selezione
|
|
||||||
- Gestione errori migliorata con timeout specifici per operazione
|
|
||||||
- Fallback su errori: continua operazione invece di crash
|
|
||||||
|
|
||||||
### ?? Documentazione
|
|
||||||
|
|
||||||
#### Nuovi File
|
|
||||||
- **`README.md`**: Documentazione completa progetto (overview, guide, FAQ)
|
|
||||||
- **`MULTI_AUCTION_GUIDE.md`**: Guida dettagliata modalità Multi-Asta
|
|
||||||
- **`IMPLEMENTATION_SUMMARY.md`**: Riepilogo tecnico implementazione
|
|
||||||
- **`QUICK_REFERENCE.md`**: Carta di riferimento rapido per utenti
|
|
||||||
- **`CHANGELOG.md`**: Questo file
|
|
||||||
|
|
||||||
#### Contenuti
|
|
||||||
- Guide passo-passo per entrambe le modalità
|
|
||||||
- Spiegazione algoritmo priorità con esempi
|
|
||||||
- Troubleshooting completo
|
|
||||||
- Strategie vincenti e best practices
|
|
||||||
- Dettagli tecnici architettura
|
|
||||||
- Diagrammi flusso operativo
|
|
||||||
|
|
||||||
### ?? Bug Fix
|
|
||||||
- Fix contatore reset: Ora confronta timer PRIMA di aggiornarlo (risolve conteggio doppio)
|
|
||||||
- Fix tracciamento bidder: Non registra più "AutoBidder" se nome utente disponibile
|
|
||||||
- Fix sincronizzazione UI: Usa `BeginInvoke` invece di `Invoke` per evitare deadlock
|
|
||||||
- Fix cache timer: Timeout corretto (20ms invece di indefinito)
|
|
||||||
|
|
||||||
### ?? Modifiche Tecniche
|
|
||||||
|
|
||||||
#### XAML (MainWindow.xaml)
|
|
||||||
- Aggiunta Row 0: Grid con pulsanti modalità
|
|
||||||
- Row 4 modificata: Incluso pannello "Asta Attiva" (visibile solo in Multi-Asta)
|
|
||||||
- Aggiornati indici Grid.Row per tutti gli elementi successivi (shift +1)
|
|
||||||
- Nuovo elemento `ActiveAuctionPanel` con Visibility bindata
|
|
||||||
|
|
||||||
#### C# (MainWindow.xaml.cs)
|
|
||||||
- Variabili di stato:
|
|
||||||
```csharp
|
|
||||||
private bool _isMultiAuctionMode = false;
|
|
||||||
private List<AuctionInfo> _monitoredAuctions = new();
|
|
||||||
private string _currentActiveAuction = "";
|
|
||||||
```
|
|
||||||
- Classi helper per gestione dati aste multiple
|
|
||||||
- Script JavaScript per interazione DOM Bidoo:
|
|
||||||
- Scansione: Trova `div[id^="divAsta"]`
|
|
||||||
- Lettura: Estrae prezzo, timer, bidder da ID specifici
|
|
||||||
- Click: Punta su pulsante `mehodkbdkbd{ID}`
|
|
||||||
|
|
||||||
### ?? Breaking Changes
|
|
||||||
- **Nessuno**: La modalità Asta Singola funziona esattamente come prima
|
|
||||||
- Retrocompatibilità completa con configurazioni esistenti
|
|
||||||
|
|
||||||
### ?? Casi d'Uso Supportati
|
|
||||||
|
|
||||||
#### Asta Singola (Esistente)
|
|
||||||
- Focus massima precisione su un prodotto specifico
|
|
||||||
- Configurazione manuale URL asta
|
|
||||||
- Comportamento identico a versione precedente
|
|
||||||
|
|
||||||
#### Multi-Asta (Nuovo)
|
|
||||||
- Monitoraggio automatico tutti i preferiti
|
|
||||||
- Selezione dinamica asta più urgente
|
|
||||||
- Filtro automatico per limiti prezzo
|
|
||||||
- Rotazione intelligente tra aste multiple
|
|
||||||
|
|
||||||
### ?? Metriche Performance
|
|
||||||
|
|
||||||
| Aspetto | v1.x (Singola) | v2.0 (Multi) | Variazione |
|
|
||||||
|---------|---------------|--------------|------------|
|
|
||||||
| **Memoria** | ~150MB | ~150-180MB | +20% |
|
|
||||||
| **CPU (idle)** | 2-5% | 3-6% | +1-2% |
|
|
||||||
| **CPU (attivo)** | 5-10% | 8-12% | +2-3% |
|
|
||||||
| **Polling min** | 20ms | 20ms | Uguale |
|
|
||||||
| **Aste gestite** | 1 | Illimitate* | ? |
|
|
||||||
|
|
||||||
*Raccomandato max 10-15 per performance ottimali
|
|
||||||
|
|
||||||
### ?? Miglioramenti Futuri Pianificati
|
|
||||||
|
|
||||||
#### v2.1 (Patch)
|
|
||||||
- [ ] Persistenza configurazione (salvataggio automatico impostazioni)
|
|
||||||
- [ ] Notifiche audio/visive su eventi
|
|
||||||
- [ ] Export log in CSV/JSON
|
|
||||||
- [ ] Profili configurazione salvabili
|
|
||||||
|
|
||||||
#### v2.2 (Minor)
|
|
||||||
- [ ] Modalità "Smart Auto": Switch automatico Single/Multi
|
|
||||||
- [ ] Grafici real-time (timer, prezzi)
|
|
||||||
- [ ] Statistiche avanzate (vincite, percentuali)
|
|
||||||
- [ ] Dark/Light theme toggle
|
|
||||||
|
|
||||||
#### v3.0 (Major)
|
|
||||||
- [ ] Predizione timer con Machine Learning
|
|
||||||
- [ ] WebSocket real-time invece di polling
|
|
||||||
- [ ] Cross-platform (Avalonia/MAUI)
|
|
||||||
- [ ] Cloud sync configurazioni
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [1.x] - 2024 - Initial Releases
|
|
||||||
|
|
||||||
### Funzionalità Base
|
|
||||||
- ? Modalità Asta Singola
|
|
||||||
- ? Click automatico su timer
|
|
||||||
- ? Lettura diretta variabili JavaScript Bidoo
|
|
||||||
- ? Multi-click opzionale
|
|
||||||
- ? Limiti prezzo (min/max)
|
|
||||||
- ? Limiti operativi (max clicks, max resets)
|
|
||||||
- ? Tracciamento puntatori
|
|
||||||
- ? Log operazioni dettagliato
|
|
||||||
- ? Browser integrato (WebView2)
|
|
||||||
- ? Navigazione sicura (solo domini Bidoo)
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
- ? Polling dinamico (20-400ms)
|
|
||||||
- ? Cache bottone click (500ms)
|
|
||||||
- ? Script ultra-veloce lettura timer
|
|
||||||
- ? Update UI asincrono non-bloccante
|
|
||||||
|
|
||||||
### Interfaccia
|
|
||||||
- ?? Dark theme moderno
|
|
||||||
- ?? Pulsanti con border radius
|
|
||||||
- ?? DataGrid puntatori
|
|
||||||
- ?? Log scrollabile auto-pulizia
|
|
||||||
- ?? Barra navigazione integrata
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Formato Versione
|
|
||||||
|
|
||||||
Questo progetto usa [Semantic Versioning](https://semver.org/):
|
|
||||||
- **MAJOR**: Modifiche incompatibili API/comportamento
|
|
||||||
- **MINOR**: Nuove funzionalità retrocompatibili
|
|
||||||
- **PATCH**: Bug fix retrocompatibili
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Link Utili
|
|
||||||
|
|
||||||
- [README.md](README.md) - Documentazione principale
|
|
||||||
- [MULTI_AUCTION_GUIDE.md](MULTI_AUCTION_GUIDE.md) - Guida Multi-Asta
|
|
||||||
- [QUICK_REFERENCE.md](QUICK_REFERENCE.md) - Riferimento rapido
|
|
||||||
- [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) - Dettagli tecnici
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**AutoBidder Team** - *Making Bidoo automation smarter, one release at a time* ??
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace AutoBidder.Converters
|
||||||
|
{
|
||||||
|
public class AndNotPausedConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (values.Length == 2 && values[0] is bool isActive && values[1] is bool isPaused)
|
||||||
|
{
|
||||||
|
return isActive && !isPaused;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace AutoBidder.Converters
|
||||||
|
{
|
||||||
|
// Converte bool in Opacity: true -> 0.5 (disabilitato), false -> 1.0 (abilitato)
|
||||||
|
public class BoolToOpacityConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
bool inverse = parameter?.ToString() == "Inverse";
|
||||||
|
if (value is bool b)
|
||||||
|
{
|
||||||
|
if (inverse)
|
||||||
|
return b ? 0.5 : 1.0;
|
||||||
|
else
|
||||||
|
return b ? 1.0 : 0.5;
|
||||||
|
}
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converte (IsActive, IsPaused) in Opacity per il pulsante Pausa
|
||||||
|
public class PauseButtonOpacityConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (values.Length == 2 && values[0] is bool isActive && values[1] is bool isPaused)
|
||||||
|
{
|
||||||
|
return (isActive && !isPaused) ? 1.0 : 0.5;
|
||||||
|
}
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:AutoBidder.Converters">
|
||||||
|
<local:InverseBoolConverter x:Key="InverseBoolConverter"/>
|
||||||
|
<local:AndNotPausedConverter x:Key="AndNotPausedConverter"/>
|
||||||
|
<local:StartResumeConverter x:Key="StartResumeConverter"/>
|
||||||
|
<local:BoolToOpacityConverter x:Key="BoolToOpacityConverter"/>
|
||||||
|
<local:PauseButtonOpacityConverter x:Key="PauseButtonOpacityConverter"/>
|
||||||
|
<local:StartButtonOpacityConverter x:Key="StartButtonOpacityConverter"/>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace AutoBidder.Converters
|
||||||
|
{
|
||||||
|
public class InverseBoolConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is bool b)
|
||||||
|
return !b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is bool b)
|
||||||
|
return !b;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace AutoBidder.Converters
|
||||||
|
{
|
||||||
|
public class StartButtonOpacityConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (values.Length == 2 && values[0] is bool isActive && values[1] is bool isPaused)
|
||||||
|
{
|
||||||
|
// Bright (1.0) when not active (can start) or when paused (can resume)
|
||||||
|
return (!isActive || isPaused) ? 1.0 : 0.5;
|
||||||
|
}
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace AutoBidder.Converters
|
||||||
|
{
|
||||||
|
// Returns true when the Start/Resume button for a row should be enabled:
|
||||||
|
// Enabled when NOT active (stopped) OR when paused (to resume).
|
||||||
|
public class StartResumeConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (values.Length >= 2 && values[0] is bool isActive && values[1] is bool isPaused)
|
||||||
|
{
|
||||||
|
return (!isActive) || isPaused;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace AutoBidder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dialog per inizializzare sessione Bidoo
|
||||||
|
/// Richiede: Auth Token + Username
|
||||||
|
/// </summary>
|
||||||
|
public class SessionDialog : Window
|
||||||
|
{
|
||||||
|
private readonly TextBox _tokenTextBox;
|
||||||
|
private readonly TextBox _usernameTextBox;
|
||||||
|
|
||||||
|
public string AuthToken => _tokenTextBox.Text.Trim();
|
||||||
|
public string Username => _usernameTextBox.Text.Trim();
|
||||||
|
|
||||||
|
public SessionDialog(string existingToken = "", string existingUsername = "")
|
||||||
|
{
|
||||||
|
Title = "Configura Sessione Bidoo";
|
||||||
|
Width = 680;
|
||||||
|
Height = 420;
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
ResizeMode = ResizeMode.NoResize;
|
||||||
|
Background = System.Windows.Media.Brushes.Black;
|
||||||
|
Foreground = System.Windows.Media.Brushes.White;
|
||||||
|
|
||||||
|
var grid = new Grid { Margin = new Thickness(20) };
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(10) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(140) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(15) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(10) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(40) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(20) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||||
|
|
||||||
|
var label1 = new TextBlock
|
||||||
|
{
|
||||||
|
Text = "Cookie __stattrb (F12 > Application > Cookies > __stattrb):",
|
||||||
|
FontWeight = FontWeights.SemiBold,
|
||||||
|
Foreground = System.Windows.Media.Brushes.White,
|
||||||
|
TextWrapping = TextWrapping.Wrap
|
||||||
|
};
|
||||||
|
Grid.SetRow(label1, 0);
|
||||||
|
|
||||||
|
_tokenTextBox = new TextBox
|
||||||
|
{
|
||||||
|
Text = existingToken,
|
||||||
|
Padding = new Thickness(10),
|
||||||
|
TextWrapping = TextWrapping.Wrap,
|
||||||
|
AcceptsReturn = false,
|
||||||
|
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
|
||||||
|
VerticalContentAlignment = VerticalAlignment.Top,
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(15, 15, 15)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.LightGray,
|
||||||
|
FontFamily = new System.Windows.Media.FontFamily("Consolas"),
|
||||||
|
FontSize = 11,
|
||||||
|
ToolTip = "Esempio: eyJVU0VSSUQiOiI2NzA3NjY0Ii..."
|
||||||
|
};
|
||||||
|
Grid.SetRow(_tokenTextBox, 2);
|
||||||
|
|
||||||
|
var label2 = new TextBlock
|
||||||
|
{
|
||||||
|
Text = "Username Bidoo:",
|
||||||
|
FontWeight = FontWeights.SemiBold,
|
||||||
|
Foreground = System.Windows.Media.Brushes.White
|
||||||
|
};
|
||||||
|
Grid.SetRow(label2, 4);
|
||||||
|
|
||||||
|
_usernameTextBox = new TextBox
|
||||||
|
{
|
||||||
|
Text = existingUsername,
|
||||||
|
Padding = new Thickness(10),
|
||||||
|
FontSize = 14,
|
||||||
|
VerticalContentAlignment = VerticalAlignment.Center,
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(15, 15, 15)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.LightGray
|
||||||
|
};
|
||||||
|
Grid.SetRow(_usernameTextBox, 6);
|
||||||
|
|
||||||
|
var buttonPanel = new StackPanel
|
||||||
|
{
|
||||||
|
Orientation = Orientation.Horizontal,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right
|
||||||
|
};
|
||||||
|
Grid.SetRow(buttonPanel, 8);
|
||||||
|
|
||||||
|
var okButton = new Button
|
||||||
|
{
|
||||||
|
Content = "Conferma",
|
||||||
|
Width = 120,
|
||||||
|
Height = 40,
|
||||||
|
Margin = new Thickness(0, 0, 10, 0),
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 204, 102)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.White,
|
||||||
|
FontWeight = FontWeights.Bold,
|
||||||
|
FontSize = 14
|
||||||
|
};
|
||||||
|
var cancelButton = new Button
|
||||||
|
{
|
||||||
|
Content = "Annulla",
|
||||||
|
Width = 120,
|
||||||
|
Height = 40,
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(204, 0, 0)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.White,
|
||||||
|
FontWeight = FontWeights.Bold,
|
||||||
|
FontSize = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
okButton.Click += (s, e) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(AuthToken) || string.IsNullOrWhiteSpace(Username))
|
||||||
|
{
|
||||||
|
MessageBox.Show("Inserisci Token e Username!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DialogResult = true;
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
cancelButton.Click += (s, e) => { DialogResult = false; Close(); };
|
||||||
|
|
||||||
|
buttonPanel.Children.Add(okButton);
|
||||||
|
buttonPanel.Children.Add(cancelButton);
|
||||||
|
|
||||||
|
grid.Children.Add(label1);
|
||||||
|
grid.Children.Add(_tokenTextBox);
|
||||||
|
grid.Children.Add(label2);
|
||||||
|
grid.Children.Add(_usernameTextBox);
|
||||||
|
grid.Children.Add(buttonPanel);
|
||||||
|
|
||||||
|
Content = grid;
|
||||||
|
|
||||||
|
Loaded += (s, e) => _tokenTextBox.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dialog semplificato per aggiungere asta (ID o URL completo)
|
||||||
|
/// </summary>
|
||||||
|
public class AddAuctionSimpleDialog : Window
|
||||||
|
{
|
||||||
|
private readonly TextBox _auctionIdTextBox;
|
||||||
|
public string AuctionId => _auctionIdTextBox.Text.Trim();
|
||||||
|
|
||||||
|
public AddAuctionSimpleDialog()
|
||||||
|
{
|
||||||
|
Title = "Aggiungi Asta";
|
||||||
|
Width = 680;
|
||||||
|
Height = 280;
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
ResizeMode = ResizeMode.NoResize;
|
||||||
|
Background = System.Windows.Media.Brushes.Black;
|
||||||
|
Foreground = System.Windows.Media.Brushes.White;
|
||||||
|
|
||||||
|
var grid = new Grid { Margin = new Thickness(20) };
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(10) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(50) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(10) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(20) });
|
||||||
|
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(50) });
|
||||||
|
|
||||||
|
var label = new TextBlock
|
||||||
|
{
|
||||||
|
Text = "URL Asta o ID:",
|
||||||
|
FontWeight = FontWeights.SemiBold,
|
||||||
|
Foreground = System.Windows.Media.Brushes.White
|
||||||
|
};
|
||||||
|
Grid.SetRow(label, 0);
|
||||||
|
|
||||||
|
_auctionIdTextBox = new TextBox
|
||||||
|
{
|
||||||
|
Text = "",
|
||||||
|
Padding = new Thickness(10),
|
||||||
|
FontSize = 13,
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(15, 15, 15)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.LightGray,
|
||||||
|
VerticalContentAlignment = VerticalAlignment.Center
|
||||||
|
};
|
||||||
|
Grid.SetRow(_auctionIdTextBox, 2);
|
||||||
|
|
||||||
|
var hintLabel = new TextBlock
|
||||||
|
{
|
||||||
|
Text = "Esempio: https://it.bidoo.com/auction.php?a=Galaxy_S25_Ultra_256GB_81204324\nOppure: 81204324",
|
||||||
|
FontSize = 11,
|
||||||
|
Foreground = System.Windows.Media.Brushes.Gray,
|
||||||
|
TextWrapping = TextWrapping.Wrap
|
||||||
|
};
|
||||||
|
Grid.SetRow(hintLabel, 4);
|
||||||
|
|
||||||
|
var buttonPanel = new StackPanel
|
||||||
|
{
|
||||||
|
Orientation = Orientation.Horizontal,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right
|
||||||
|
};
|
||||||
|
Grid.SetRow(buttonPanel, 6);
|
||||||
|
|
||||||
|
var okButton = new Button
|
||||||
|
{
|
||||||
|
Content = "Aggiungi",
|
||||||
|
Width = 120,
|
||||||
|
Height = 40,
|
||||||
|
Margin = new Thickness(0, 0, 10, 0),
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 204, 102)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.White,
|
||||||
|
FontWeight = FontWeights.Bold,
|
||||||
|
FontSize = 14
|
||||||
|
};
|
||||||
|
var cancelButton = new Button
|
||||||
|
{
|
||||||
|
Content = "Annulla",
|
||||||
|
Width = 120,
|
||||||
|
Height = 40,
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(204, 0, 0)),
|
||||||
|
Foreground = System.Windows.Media.Brushes.White,
|
||||||
|
FontWeight = FontWeights.Bold,
|
||||||
|
FontSize = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
okButton.Click += (s, e) => { DialogResult = true; Close(); };
|
||||||
|
cancelButton.Click += (s, e) => { DialogResult = false; Close(); };
|
||||||
|
_auctionIdTextBox.KeyDown += (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.Key == System.Windows.Input.Key.Enter)
|
||||||
|
{
|
||||||
|
DialogResult = true;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
buttonPanel.Children.Add(okButton);
|
||||||
|
buttonPanel.Children.Add(cancelButton);
|
||||||
|
|
||||||
|
grid.Children.Add(label);
|
||||||
|
grid.Children.Add(_auctionIdTextBox);
|
||||||
|
grid.Children.Add(hintLabel);
|
||||||
|
grid.Children.Add(buttonPanel);
|
||||||
|
|
||||||
|
Content = grid;
|
||||||
|
|
||||||
|
Loaded += (s, e) => _auctionIdTextBox.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,565 +0,0 @@
|
|||||||
# ?? Riepilogo Implementazione Multi-Asta
|
|
||||||
|
|
||||||
## ? Modifiche Completate
|
|
||||||
|
|
||||||
### ?? File Modificati
|
|
||||||
|
|
||||||
#### 1. `MainWindow.xaml` - Interfaccia Utente
|
|
||||||
**Modifiche principali:**
|
|
||||||
- ? Aggiunto selettore modalità "Asta Singola" / "Multi-Asta"
|
|
||||||
- ? Nuovo pannello "Asta Attiva" (visibile solo in Multi-Asta)
|
|
||||||
- ? Contatore "Aste monitorate"
|
|
||||||
- ?? Aggiornati indici Grid.Row per nuovi elementi
|
|
||||||
- ?? Stili visuali migliorati per indicatori di stato
|
|
||||||
|
|
||||||
**Struttura pannello sinistro:**
|
|
||||||
```
|
|
||||||
Row 0: [Asta Singola] [Multi-Asta] ? NUOVO
|
|
||||||
Row 1: [Avvia]
|
|
||||||
Row 2: [Pausa]
|
|
||||||
Row 3: [Stop]
|
|
||||||
Row 4: Stats + Asta Attiva Panel ? MODIFICATO
|
|
||||||
Row 5: Settings Row 1
|
|
||||||
Row 6: Settings Row 2
|
|
||||||
Row 7: Bidders header
|
|
||||||
Row 8: Bidders grid
|
|
||||||
Row 9: Log header
|
|
||||||
Row 10: Log box
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. `MainWindow.xaml.cs` - Logica Business
|
|
||||||
**Nuove funzionalità:**
|
|
||||||
|
|
||||||
##### A. Variabili e Classi
|
|
||||||
```csharp
|
|
||||||
// Modalità operative
|
|
||||||
private bool _isMultiAuctionMode = false;
|
|
||||||
|
|
||||||
// Gestione aste multiple
|
|
||||||
private List<AuctionInfo> _monitoredAuctions = new();
|
|
||||||
private string _currentActiveAuction = "";
|
|
||||||
|
|
||||||
// Classe info asta
|
|
||||||
class AuctionInfo {
|
|
||||||
string AuctionId, Name, PriceElementId,
|
|
||||||
TimerElementId, BidderElementId, ButtonId
|
|
||||||
double LastKnownTimer
|
|
||||||
string LastKnownBidder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Classe stato temporaneo
|
|
||||||
class AuctionState {
|
|
||||||
string AuctionId, Name, Price, Bidder
|
|
||||||
double Timer
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
##### B. Nuovi Metodi
|
|
||||||
|
|
||||||
**1. Gestione Modalità**
|
|
||||||
- `SingleAuctionButton_Click()` - Attiva modalità singola
|
|
||||||
- `MultiAuctionButton_Click()` - Attiva multi-asta + naviga a preferiti
|
|
||||||
- `UpdateModeButtons()` - Aggiorna UI pulsanti modalità
|
|
||||||
- `UpdateActiveAuctionDisplay()` - Mostra asta corrente
|
|
||||||
|
|
||||||
**2. Loop Multi-Asta**
|
|
||||||
- `MultiAuctionLoop(token)` - Loop principale multi-asta
|
|
||||||
- Scansiona preferiti ogni 5 secondi
|
|
||||||
- Legge stato tutte le aste
|
|
||||||
- Seleziona asta con timer più basso
|
|
||||||
- Gestisce click, reset, limiti
|
|
||||||
|
|
||||||
**3. Scansione e Lettura**
|
|
||||||
- `ScanFavoriteAuctions(token)` - Trova aste nei preferiti
|
|
||||||
- Cerca `div[id^="divAsta"]`
|
|
||||||
- Estrae ID, nome, elementi DOM
|
|
||||||
- Popola `_monitoredAuctions`
|
|
||||||
|
|
||||||
- `ReadAllAuctionStates(token)` - Legge stato di tutte le aste
|
|
||||||
- Itera su `_monitoredAuctions`
|
|
||||||
- Legge prezzo, timer, bidder per ognuna
|
|
||||||
- Ritorna `List<AuctionState>`
|
|
||||||
|
|
||||||
**4. Click Multi-Asta**
|
|
||||||
- `PerformMultiAuctionClick(auctionId, ...)` - Click su asta specifica
|
|
||||||
- Trova pulsante tramite `buttonId`
|
|
||||||
- Doppio click per affidabilità
|
|
||||||
- Supporta multi-click opzionale
|
|
||||||
|
|
||||||
##### C. Modifiche Metodi Esistenti
|
|
||||||
- `StartButton_Click()` - Sceglie loop basato su modalità
|
|
||||||
```csharp
|
|
||||||
_automationTask = Task.Run(() =>
|
|
||||||
_isMultiAuctionMode ? MultiAuctionLoop(_cts.Token)
|
|
||||||
: AutomationLoop(_cts.Token)
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
- `AutomationLoop()` - Aggiunto log "Modalità: Asta Singola"
|
|
||||||
|
|
||||||
### ?? File Creati
|
|
||||||
|
|
||||||
#### 1. `MULTI_AUCTION_GUIDE.md`
|
|
||||||
Guida dettagliata per utenti:
|
|
||||||
- ?? Panoramica modalità
|
|
||||||
- ?? Tutorial step-by-step
|
|
||||||
- ?? Spiegazione algoritmo priorità
|
|
||||||
- ?? Descrizione interfaccia
|
|
||||||
- ? Ottimizzazioni e performance
|
|
||||||
- ?? Troubleshooting completo
|
|
||||||
|
|
||||||
#### 2. `README.md`
|
|
||||||
Documentazione completa progetto:
|
|
||||||
- ? Overview caratteristiche
|
|
||||||
- ?? Quick start guide
|
|
||||||
- ?? Guida dettagliata entrambe modalità
|
|
||||||
- ?? Configurazioni avanzate
|
|
||||||
- ?? Spiegazione interfaccia
|
|
||||||
- ?? FAQ e troubleshooting
|
|
||||||
- ?? Strategie vincenti
|
|
||||||
- ?? Performance tuning
|
|
||||||
|
|
||||||
#### 3. `IMPLEMENTATION_SUMMARY.md` (questo file)
|
|
||||||
Riepilogo tecnico modifiche
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Flusso Operativo Multi-Asta
|
|
||||||
|
|
||||||
### Inizializzazione
|
|
||||||
1. Utente clicca "Multi-Asta"
|
|
||||||
2. `_isMultiAuctionMode = true`
|
|
||||||
3. `UpdateModeButtons()` ? UI verde su Multi-Asta
|
|
||||||
4. Navigazione automatica a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
5. Pannello "Asta Attiva" diventa visibile
|
|
||||||
|
|
||||||
### Loop Principale
|
|
||||||
```
|
|
||||||
???????????????????????????????????????
|
|
||||||
? while (!token.IsCancellationRequested) ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Ogni 5s: ScanFavoriteAuctions() ?
|
|
||||||
? - Trova div[id^="divAsta"] ?
|
|
||||||
? - Estrae metadati (ID, nome, etc.) ?
|
|
||||||
? - Popola _monitoredAuctions ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? ReadAllAuctionStates() ?
|
|
||||||
? - Itera su _monitoredAuctions ?
|
|
||||||
? - Legge prezzo, timer, bidder ?
|
|
||||||
? - Ritorna List<AuctionState> ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Selezione Priorità ?
|
|
||||||
? auctionStates ?
|
|
||||||
? .Where(timer > 0 && < 999) ?
|
|
||||||
? .OrderBy(timer) ?
|
|
||||||
? .FirstOrDefault() ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Aggiorna UI ?
|
|
||||||
? - UpdateActiveAuctionDisplay() ?
|
|
||||||
? - SetCurrentPriceText() ?
|
|
||||||
? - Log focus asta ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Rileva Reset ?
|
|
||||||
? if (timer > lastTimer + 0.5) ?
|
|
||||||
? ? resetCount++ ?
|
|
||||||
? ? Log reset + winner ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Verifica Condizioni Click ?
|
|
||||||
? shouldClick = timer in range ?
|
|
||||||
? && !pauseBids ?
|
|
||||||
? && prezzo OK ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
?
|
|
||||||
shouldClick?
|
|
||||||
? ?
|
|
||||||
SI NO
|
|
||||||
? ?
|
|
||||||
? ?
|
|
||||||
??????????? ??????????????
|
|
||||||
? Click! ? ? Delay X ms ?
|
|
||||||
? +1 ? ? Continue ?
|
|
||||||
??????????? ??????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
### Algoritmo Priorità
|
|
||||||
```javascript
|
|
||||||
// Pseudo-codice semplificato
|
|
||||||
function SelectTargetAuction(auctions) {
|
|
||||||
let candidates = auctions
|
|
||||||
.filter(a => a.timer > 0 && a.timer < 999)
|
|
||||||
.filter(a => a.price >= minPrice && a.price <= maxPrice);
|
|
||||||
|
|
||||||
return candidates.sort((a, b) => a.timer - b.timer)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Esempio
|
|
||||||
Auctions: [
|
|
||||||
{name: "Galaxy S25", timer: 7.2},
|
|
||||||
{name: "RTX 5080", timer: 1.8}, ? SELEZIONATA (timer più basso)
|
|
||||||
{name: "MacBook", timer: 4.5}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Struttura Dati HTML Bidoo
|
|
||||||
|
|
||||||
### Pagina Preferiti: `https://it.bidoo.com/?tab=FAV`
|
|
||||||
|
|
||||||
#### Container Principale
|
|
||||||
```html
|
|
||||||
<div class="bids">
|
|
||||||
<div id="auctions" class="container">
|
|
||||||
<!-- Aste qui -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Singola Asta
|
|
||||||
```html
|
|
||||||
<div id="divAsta81043969"
|
|
||||||
data-id="81043969"
|
|
||||||
data-url="Galaxy_S25_512GB_81043969">
|
|
||||||
|
|
||||||
<div class="bid-box">
|
|
||||||
<!-- Nome -->
|
|
||||||
<a class="name">Galaxy S25 512GB</a>
|
|
||||||
|
|
||||||
<!-- Prezzo -->
|
|
||||||
<span id="PrezzoAsta81043969">29.21</span>
|
|
||||||
|
|
||||||
<!-- Timer -->
|
|
||||||
<h4 id="TempoMancante81043969">00:05</h4>
|
|
||||||
|
|
||||||
<!-- Vincitore corrente -->
|
|
||||||
<span id="Vincitore81043969">username</span>
|
|
||||||
|
|
||||||
<!-- Pulsante punta -->
|
|
||||||
<a id="mehodkbdkbd81043969">PUNTA</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Elementi Chiave Estratti
|
|
||||||
| Dato | Selector | ID Pattern |
|
|
||||||
|------|----------|------------|
|
|
||||||
| **Container** | `div[id^="divAsta"]` | `divAsta{ID}` |
|
|
||||||
| **Auction ID** | `data-id` attribute | Numerico |
|
|
||||||
| **Nome** | `.name` | - |
|
|
||||||
| **Prezzo** | `span#PrezzoAsta{ID}` | `PrezzoAsta{ID}` |
|
|
||||||
| **Timer** | `h4#TempoMancante{ID}` | `TempoMancante{ID}` |
|
|
||||||
| **Bidder** | `span#Vincitore{ID}` | `Vincitore{ID}` |
|
|
||||||
| **Button** | `a#mehodkbdkbd{ID}` | `mehodkbdkbd{ID}` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Script JavaScript Utilizzati
|
|
||||||
|
|
||||||
### 1. Scansione Aste (`ScanFavoriteAuctions`)
|
|
||||||
```javascript
|
|
||||||
(function() {
|
|
||||||
var auctions = [];
|
|
||||||
var auctionDivs = document.querySelectorAll('div[id^="divAsta"]');
|
|
||||||
|
|
||||||
for (var i = 0; i < auctionDivs.length; i++) {
|
|
||||||
var div = auctionDivs[i];
|
|
||||||
var auctionId = div.getAttribute('data-id');
|
|
||||||
var nameEl = div.querySelector('.name');
|
|
||||||
var name = nameEl ? nameEl.textContent.trim() : 'Asta ' + auctionId;
|
|
||||||
|
|
||||||
auctions.push({
|
|
||||||
auctionId: auctionId,
|
|
||||||
name: name,
|
|
||||||
priceElementId: 'PrezzoAsta' + auctionId,
|
|
||||||
timerElementId: 'TempoMancante' + auctionId,
|
|
||||||
bidderElementId: 'Vincitore' + auctionId,
|
|
||||||
buttonId: 'mehodkbdkbd' + auctionId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.stringify({success: true, auctions: auctions});
|
|
||||||
})();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Lettura Stato Asta (`ReadAllAuctionStates`)
|
|
||||||
```javascript
|
|
||||||
(function() {
|
|
||||||
var priceEl = document.getElementById('PrezzoAsta12345');
|
|
||||||
var timerEl = document.getElementById('TempoMancante12345');
|
|
||||||
var bidderEl = document.getElementById('Vincitore12345');
|
|
||||||
|
|
||||||
var price = priceEl ? priceEl.textContent.trim().replace('€','') : null;
|
|
||||||
var timer = timerEl ? timerEl.textContent.trim() : null;
|
|
||||||
var bidder = bidderEl ? bidderEl.textContent.trim() : null;
|
|
||||||
|
|
||||||
// Conversione timer
|
|
||||||
var timerValue = 999;
|
|
||||||
if (timer) {
|
|
||||||
var parts = timer.split(':');
|
|
||||||
if (parts.length === 2) {
|
|
||||||
timerValue = parseInt(parts[0]) * 60 + parseInt(parts[1]);
|
|
||||||
} else {
|
|
||||||
var match = timer.match(/(\d+(?:\.\d+)?)/);
|
|
||||||
if (match) timerValue = parseFloat(match[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.stringify({
|
|
||||||
auctionId: '12345',
|
|
||||||
price: price,
|
|
||||||
timer: timerValue,
|
|
||||||
bidder: bidder
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Click Asta (`PerformMultiAuctionClick`)
|
|
||||||
```javascript
|
|
||||||
(function() {
|
|
||||||
var btn = document.getElementById('mehodkbdkbd12345');
|
|
||||||
if (!btn) return JSON.stringify({success: false});
|
|
||||||
|
|
||||||
btn.click();
|
|
||||||
btn.click(); // doppio click
|
|
||||||
|
|
||||||
return JSON.stringify({success: true});
|
|
||||||
})();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Casi d'Uso Principali
|
|
||||||
|
|
||||||
### Caso 1: Focus su Asta Più Urgente
|
|
||||||
**Scenario:**
|
|
||||||
- 3 aste nei preferiti
|
|
||||||
- Timer diversi: 8s, 2s, 5s
|
|
||||||
|
|
||||||
**Comportamento:**
|
|
||||||
1. Scansione ? 3 aste trovate
|
|
||||||
2. Lettura stati ? Timer: [8, 2, 5]
|
|
||||||
3. **Priorità: Asta con timer 2s**
|
|
||||||
4. Click quando timer in range (es. 0-1s)
|
|
||||||
5. Dopo click, ri-valuta ? Focus su timer 5s
|
|
||||||
6. E così via...
|
|
||||||
|
|
||||||
### Caso 2: Filtro Prezzo
|
|
||||||
**Configurazione:**
|
|
||||||
- Min Price: 10€
|
|
||||||
- Max Price: 50€
|
|
||||||
|
|
||||||
**Scenario:**
|
|
||||||
- Asta A: 8€, timer 1s ? ? Saltata (sotto min)
|
|
||||||
- Asta B: 35€, timer 2s ? ? Selezionata
|
|
||||||
- Asta C: 60€, timer 1.5s ? ? Saltata (sopra max)
|
|
||||||
|
|
||||||
### Caso 3: Gestione Reset
|
|
||||||
**Sequenza:**
|
|
||||||
1. Timer asta A: 1.2s
|
|
||||||
2. **Click!** (utente AutoBidder)
|
|
||||||
3. Timer asta A: 8.0s ? Reset rilevato!
|
|
||||||
4. Log: "Reset #1 - Winner: AutoBidder"
|
|
||||||
5. Focus passa ad asta B (timer 3s)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Parametri Configurabili
|
|
||||||
|
|
||||||
### Multi-Asta Specifici
|
|
||||||
| Parametro | Valore | Descrizione |
|
|
||||||
|-----------|--------|-------------|
|
|
||||||
| **Scan Interval** | 5s | Frequenza scansione preferiti |
|
|
||||||
| **Polling Dinamico** | 20-400ms | Basato su timer asta prioritaria |
|
|
||||||
| **Cache Bottone** | 500ms | Riutilizzo elemento click |
|
|
||||||
|
|
||||||
### Condivisi (Asta Singola + Multi)
|
|
||||||
| Parametro | Range | Default | Effetto |
|
|
||||||
|-----------|-------|---------|---------|
|
|
||||||
| **Max Clicks** | 0-? | 0 (?) | Limite click totali |
|
|
||||||
| **Max Resets** | 0-? | 0 (?) | Limite reset |
|
|
||||||
| **Min Price** | 0-? | 0 (no limit) | Soglia minima prezzo |
|
|
||||||
| **Max Price** | 0-? | 0 (no limit) | Soglia massima prezzo |
|
|
||||||
| **Timer Click** | 0-8 | 0 | Secondo del click |
|
|
||||||
| **Ritardo** | 0-2000ms | 0 | Delay aggiuntivo |
|
|
||||||
| **Multi-Click** | On/Off | Off | Doppio click a 20ms |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Performance e Ottimizzazioni
|
|
||||||
|
|
||||||
### Polling Adattivo Multi-Asta
|
|
||||||
```csharp
|
|
||||||
int pollDelay = targetAuction.Timer < 1.5 ? 20 :
|
|
||||||
targetAuction.Timer < 2.5 ? 40 :
|
|
||||||
targetAuction.Timer < 3.5 ? 80 :
|
|
||||||
targetAuction.Timer < 5.0 ? 150 :
|
|
||||||
targetAuction.Timer < 8.0 ? 250 : 400;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Vantaggi:**
|
|
||||||
- ? Reattività massima quando necessario (20ms @ <1.5s)
|
|
||||||
- ?? Risparmio risorse quando non urgente (400ms @ >8s)
|
|
||||||
- ?? Adattamento automatico in base a situazione
|
|
||||||
|
|
||||||
### Confronto Risorse: Singola WebView vs Multiple Finestre
|
|
||||||
|
|
||||||
| Metodo | Memoria | CPU | Aste Max | Performance |
|
|
||||||
|--------|---------|-----|----------|-------------|
|
|
||||||
| **WebView Singola** (Multi-Asta) | ~150MB | 5-10% | 15+ | ????? |
|
|
||||||
| **Finestre Multiple** (Vecchio) | ~500MB+ | 20-40% | 5-6 | ??? |
|
|
||||||
|
|
||||||
**Risparmio stimato:** ~70% memoria, ~60% CPU
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Testing e Validazione
|
|
||||||
|
|
||||||
### Test Eseguiti
|
|
||||||
- ? Build senza errori
|
|
||||||
- ? Compilazione Release OK
|
|
||||||
- ? Nessun warning critico
|
|
||||||
- ? Entrambe modalità funzionanti
|
|
||||||
- ? Switch modalità senza restart
|
|
||||||
|
|
||||||
### Da Testare (Utente Finale)
|
|
||||||
- [ ] Scansione preferiti reale
|
|
||||||
- [ ] Click multi-asta su Bidoo live
|
|
||||||
- [ ] Performance con 10+ aste
|
|
||||||
- [ ] Rilevamento reset accurato
|
|
||||||
- [ ] Limiti prezzo funzionanti
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Miglioramenti Possibili
|
|
||||||
|
|
||||||
### Funzionalità
|
|
||||||
- [ ] Modalità "Smart": Auto-switch tra Single/Multi
|
|
||||||
- [ ] Profili salvabili (configurazioni predefinite)
|
|
||||||
- [ ] Notifiche audio/visive su evento
|
|
||||||
- [ ] Statistiche avanzate (vincite, percentuali, etc.)
|
|
||||||
- [ ] Export log CSV/JSON
|
|
||||||
|
|
||||||
### Ottimizzazioni
|
|
||||||
- [ ] WebWorkers per script JS parallelo
|
|
||||||
- [ ] Caching più aggressivo elementi DOM
|
|
||||||
- [ ] Predizione timer con ML
|
|
||||||
- [ ] Compressione log in background
|
|
||||||
|
|
||||||
### UI/UX
|
|
||||||
- [ ] Dark/Light theme toggle
|
|
||||||
- [ ] Grafici real-time (timer, prezzi)
|
|
||||||
- [ ] Minimap aste (thumbnail grid)
|
|
||||||
- [ ] Shortcuts tastiera personalizzabili
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Note per Sviluppatori
|
|
||||||
|
|
||||||
### Architettura Codice
|
|
||||||
```
|
|
||||||
MainWindow.xaml.cs
|
|
||||||
??? Modalità Management
|
|
||||||
? ??? SingleAuctionButton_Click()
|
|
||||||
? ??? MultiAuctionButton_Click()
|
|
||||||
? ??? UpdateModeButtons()
|
|
||||||
?
|
|
||||||
??? Loop Automazione
|
|
||||||
? ??? AutomationLoop() [Single]
|
|
||||||
? ??? MultiAuctionLoop() [Multi]
|
|
||||||
?
|
|
||||||
??? Multi-Asta Core
|
|
||||||
? ??? ScanFavoriteAuctions()
|
|
||||||
? ??? ReadAllAuctionStates()
|
|
||||||
? ??? PerformMultiAuctionClick()
|
|
||||||
?
|
|
||||||
??? Utilities
|
|
||||||
??? ExecuteScriptWithTimeoutAsync()
|
|
||||||
??? RegisterBidder()
|
|
||||||
??? Log()
|
|
||||||
??? UpdateBiddersGrid()
|
|
||||||
```
|
|
||||||
|
|
||||||
### Classi Dati
|
|
||||||
```csharp
|
|
||||||
// Permanente (lista monitorata)
|
|
||||||
class AuctionInfo {
|
|
||||||
string AuctionId, Name
|
|
||||||
string PriceElementId, TimerElementId,
|
|
||||||
BidderElementId, ButtonId
|
|
||||||
double LastKnownTimer
|
|
||||||
string LastKnownBidder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporaneo (snapshot stato)
|
|
||||||
class AuctionState {
|
|
||||||
string AuctionId, Name
|
|
||||||
string? Price, Bidder
|
|
||||||
double Timer
|
|
||||||
string LastKnownBidder
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pattern Utilizzati
|
|
||||||
- **Observer**: UI aggiornata via Dispatcher
|
|
||||||
- **Strategy**: Modalità Single vs Multi
|
|
||||||
- **Factory**: Creazione AuctionInfo/State
|
|
||||||
- **Cache**: Bottoni e timer
|
|
||||||
- **Async/Await**: Operazioni non-bloccanti
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Checklist Implementazione
|
|
||||||
|
|
||||||
### Completato ?
|
|
||||||
- [x] Aggiunto UI selettore modalità
|
|
||||||
- [x] Implementato MultiAuctionLoop
|
|
||||||
- [x] Script scansione preferiti
|
|
||||||
- [x] Script lettura stato aste
|
|
||||||
- [x] Script click specifico asta
|
|
||||||
- [x] Algoritmo priorità timer
|
|
||||||
- [x] Rilevamento reset per asta
|
|
||||||
- [x] Tracciamento bidder per asta
|
|
||||||
- [x] Pannello "Asta Attiva"
|
|
||||||
- [x] Polling dinamico multi-asta
|
|
||||||
- [x] Limiti prezzo applicati
|
|
||||||
- [x] Log dettagliato eventi
|
|
||||||
- [x] Documentazione completa (README)
|
|
||||||
- [x] Guida utente (MULTI_AUCTION_GUIDE)
|
|
||||||
- [x] Build senza errori
|
|
||||||
|
|
||||||
### Non Implementato (Out of Scope)
|
|
||||||
- ? Gestione errori rete avanzata
|
|
||||||
- ? Retry automatico su fail
|
|
||||||
- ? Persistenza configurazione
|
|
||||||
- ? Statistiche persistenti
|
|
||||||
- ? Unit tests
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
### Obiettivi Raggiunti
|
|
||||||
? **Modalità Multi-Asta completamente funzionale**
|
|
||||||
? **Ottimizzazione risorse** (singola WebView)
|
|
||||||
? **Interfaccia intuitiva** con switch modalità
|
|
||||||
? **Algoritmo intelligente** di selezione priorità
|
|
||||||
? **Documentazione completa** per utenti e sviluppatori
|
|
||||||
|
|
||||||
### Risultato Finale
|
|
||||||
AutoBidder ora supporta:
|
|
||||||
1. **Asta Singola**: Massima precisione su un prodotto
|
|
||||||
2. **Multi-Asta**: Monitoraggio simultaneo preferiti con selezione intelligente
|
|
||||||
|
|
||||||
**Sistema pronto per il deploy e testing utente finale!** ??
|
|
||||||
@@ -1,413 +0,0 @@
|
|||||||
# ?? Guida Griglia Multi-Asta - AutoBidder v2.1
|
|
||||||
|
|
||||||
## ?? Nuova Interfaccia Multi-Asta
|
|
||||||
|
|
||||||
### Panoramica Modifiche
|
|
||||||
|
|
||||||
La modalità Multi-Asta ora presenta una **griglia in tempo reale** che mostra lo stato di tutte le aste simultaneamente, eliminando la necessità di seguire un'asta alla volta.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Interfaccia Griglia
|
|
||||||
|
|
||||||
### Layout Griglia Aste
|
|
||||||
|
|
||||||
Quando attivi la modalità **Multi-Asta**, vedrai una griglia con queste colonne:
|
|
||||||
|
|
||||||
| Colonna | Descrizione | Esempio |
|
|
||||||
|---------|-------------|---------|
|
|
||||||
| **Asta** | Nome del prodotto | "Galaxy S25 512GB" |
|
|
||||||
| **Timer** | Timer in tempo reale | "2.3s" |
|
|
||||||
| **Prezzo** | Prezzo corrente | "15.50€" |
|
|
||||||
| **Vincitore** | Utente che sta vincendo | "user123" |
|
|
||||||
| **Stato** | Stato asta | ?? Attiva / ?? Pausa / ? Attesa |
|
|
||||||
|
|
||||||
### Esempio Visivo
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????????????
|
|
||||||
? ?? Aste Monitorate Totale: 3 ?
|
|
||||||
???????????????????????????????????????????????????????????????
|
|
||||||
? Asta Timer Prezzo Vincitore Stato ?
|
|
||||||
? Galaxy S25 512GB 2.3s 15.50€ user123 ?? Attiva ?
|
|
||||||
? RTX 5080 5.1s 45.20€ user456 ? Attesa ?
|
|
||||||
? MacBook Pro 8.0s 120.00€ user789 ? Attesa ?
|
|
||||||
???????????????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Aggiornamenti in Tempo Reale
|
|
||||||
|
|
||||||
### Cosa Vedi Cambiare
|
|
||||||
|
|
||||||
La griglia si aggiorna **automaticamente ogni ciclo di polling** (20-400ms basato sul timer):
|
|
||||||
|
|
||||||
1. **Timer** ? Si aggiorna continuamente mostrando il countdown
|
|
||||||
2. **Prezzo** ? Cambia quando qualcuno punta
|
|
||||||
3. **Vincitore** ? Mostra l'utente che ha fatto l'ultima puntata
|
|
||||||
4. **Stato** ? Indica quale asta è più vicina al click
|
|
||||||
|
|
||||||
### Stati Asta
|
|
||||||
|
|
||||||
- **?? Attiva** ? Asta con timer < 3s (priorità click)
|
|
||||||
- **? Attesa** ? Asta con timer > 3s (in monitoraggio)
|
|
||||||
- **?? Pausa** ? Asta messa in pausa manualmente (feature futura)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Funziona
|
|
||||||
|
|
||||||
### Strategia Automatica
|
|
||||||
|
|
||||||
1. **Scansione**: Ogni 5 secondi, AutoBidder cerca nuove aste nei preferiti
|
|
||||||
2. **Monitoraggio**: Tutte le aste vengono monitorate simultaneamente
|
|
||||||
3. **Priorità**: L'asta con timer più basso diventa ?? Attiva
|
|
||||||
4. **Click**: AutoBidder punta sull'asta Attiva al momento giusto
|
|
||||||
5. **Rotazione**: Dopo il click, la priorità si sposta sull'asta successiva
|
|
||||||
|
|
||||||
### Esempio Pratico
|
|
||||||
|
|
||||||
```
|
|
||||||
Situazione iniziale:
|
|
||||||
?? Galaxy S25 Timer: 8.0s ? ? Attesa
|
|
||||||
?? RTX 5080 Timer: 2.1s ? ?? Attiva (priorità!)
|
|
||||||
?? MacBook Pro Timer: 5.3s ? ? Attesa
|
|
||||||
|
|
||||||
AutoBidder punta su RTX 5080 a 0-1s
|
|
||||||
|
|
||||||
Dopo il click (RTX resettato a 8s):
|
|
||||||
?? Galaxy S25 Timer: 7.5s ? ? Attesa
|
|
||||||
?? RTX 5080 Timer: 8.0s ? ? Attesa (appena resettata)
|
|
||||||
?? MacBook Pro Timer: 4.8s ? ?? Attiva (nuova priorità!)
|
|
||||||
|
|
||||||
AutoBidder ora punta su MacBook Pro
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Gestione Impostazioni
|
|
||||||
|
|
||||||
### Impostazioni Globali (Applicate a Tutte le Aste)
|
|
||||||
|
|
||||||
Le seguenti impostazioni si applicano a **tutte le aste** nella griglia:
|
|
||||||
|
|
||||||
- **Timer Click** ? Tutte le aste cliccano allo stesso secondo
|
|
||||||
- **Ritardo (ms)** ? Stesso delay per tutte
|
|
||||||
- **Max Clicks** ? Limite totale su tutte le aste
|
|
||||||
- **Max Resets** ? Limite totale reset
|
|
||||||
- **Multi-Click** ? Attivo/disattivo per tutte
|
|
||||||
|
|
||||||
### Limiti Prezzo Intelligenti
|
|
||||||
|
|
||||||
- **Min Price**: Le aste sotto il minimo vengono **saltate** automaticamente
|
|
||||||
- **Max Price**: Le aste sopra il massimo vengono **saltate** automaticamente
|
|
||||||
|
|
||||||
**Esempio:**
|
|
||||||
```
|
|
||||||
Impostazioni:
|
|
||||||
- Min Price: 10€
|
|
||||||
- Max Price: 100€
|
|
||||||
|
|
||||||
Aste:
|
|
||||||
? Galaxy S25 (15€) ? OK, punta
|
|
||||||
? iPhone 16 (8€) ? Saltata (sotto minimo)
|
|
||||||
? RTX 5080 (45€) ? OK, punta
|
|
||||||
? MacBook Pro (150€) ? Saltata (sopra massimo)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Vantaggi Nuova Interfaccia
|
|
||||||
|
|
||||||
### Rispetto alla Versione Precedente
|
|
||||||
|
|
||||||
| Aspetto | Vecchia (v2.0) | Nuova (v2.1) | Miglioramento |
|
|
||||||
|---------|---------------|-------------|---------------|
|
|
||||||
| **Visibilità** | Una per volta | Tutte simultanee | ????? |
|
|
||||||
| **Informazioni** | Solo asta attiva | Tutti i dati in tempo reale | ????? |
|
|
||||||
| **Controllo** | Automatico | Visibile + automatico | ???? |
|
|
||||||
| **Comprensione** | Limitata | Completa | ????? |
|
|
||||||
|
|
||||||
### Cosa Puoi Fare Ora
|
|
||||||
|
|
||||||
? **Vedere** lo stato di tutte le aste contemporaneamente
|
|
||||||
? **Capire** quale asta è prioritaria (?? Attiva)
|
|
||||||
? **Monitorare** timer, prezzi e vincitori in tempo reale
|
|
||||||
? **Tracciare** chi punta su quale asta (nel log)
|
|
||||||
? **Decidere** meglio quali aste aggiungere ai preferiti
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Workflow Ottimale
|
|
||||||
|
|
||||||
### Setup Iniziale
|
|
||||||
|
|
||||||
1. **Accedi a Bidoo** tramite AutoBidder
|
|
||||||
2. **Esplora le aste** e trova quelle interessanti
|
|
||||||
3. **Aggiungi ai Preferiti** (?) le aste che vuoi monitorare
|
|
||||||
- Consiglio: Max 5-10 aste per performance ottimali
|
|
||||||
4. **Torna su AutoBidder**
|
|
||||||
|
|
||||||
### Attivazione Multi-Asta
|
|
||||||
|
|
||||||
1. Clicca **[Multi-Asta]** nel pannello sinistro
|
|
||||||
2. AutoBidder naviga automaticamente ai preferiti
|
|
||||||
3. Attendi 5 secondi per la scansione iniziale
|
|
||||||
4. Vedrai la griglia popolarsi con le aste
|
|
||||||
|
|
||||||
### Configurazione
|
|
||||||
|
|
||||||
1. Imposta **Timer Click** (es: 0 o 1)
|
|
||||||
2. Imposta **Ritardo** (es: 0-50ms)
|
|
||||||
3. Configura **limiti prezzo** (opzionale)
|
|
||||||
- Min Price: Soglia minima
|
|
||||||
- Max Price: Soglia massima
|
|
||||||
4. Imposta **Max Clicks** (es: 100-200)
|
|
||||||
|
|
||||||
### Avvio
|
|
||||||
|
|
||||||
1. Clicca **[Avvia]**
|
|
||||||
2. **Osserva la griglia**:
|
|
||||||
- Timer si aggiornano in tempo reale
|
|
||||||
- Stato cambia (? ? ??) quando un'asta diventa prioritaria
|
|
||||||
- Prezzo e Vincitore cambiano ad ogni puntata
|
|
||||||
3. **Monitora il Log** per eventi dettagliati
|
|
||||||
4. **Controlla Elenco Utenti** per vedere chi punta di più
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Interpretare la Griglia
|
|
||||||
|
|
||||||
### Colori e Simboli
|
|
||||||
|
|
||||||
- **?? Attiva** ? Verde, asta su cui AutoBidder punterà
|
|
||||||
- **? Attesa** ? Grigio, asta in monitoraggio
|
|
||||||
- **?? Pausa** ? Giallo, asta sospesa (feature futura)
|
|
||||||
|
|
||||||
### Timer
|
|
||||||
|
|
||||||
- **< 1s** ? Click imminente
|
|
||||||
- **1-3s** ? Preparazione click
|
|
||||||
- **3-8s** ? Monitoraggio normale
|
|
||||||
- **> 8s** ? Polling lento
|
|
||||||
|
|
||||||
### Prezzo
|
|
||||||
|
|
||||||
- **Verde** ? Entro limiti configurati
|
|
||||||
- **Rosso** ? Fuori limiti (saltata automaticamente)
|
|
||||||
- **"-"** ? Dato non disponibile
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Troubleshooting
|
|
||||||
|
|
||||||
### La griglia è vuota
|
|
||||||
|
|
||||||
**Possibili cause:**
|
|
||||||
1. Nessuna asta nei preferiti
|
|
||||||
2. Pagina preferiti non caricata
|
|
||||||
3. Scansione non ancora eseguita
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Aggiungi aste ai preferiti su Bidoo (?)
|
|
||||||
2. Verifica URL: deve essere `https://it.bidoo.com/?tab=FAV`
|
|
||||||
3. Attendi 5 secondi per scansione automatica
|
|
||||||
4. Clicca [Aggiorna] se necessario
|
|
||||||
|
|
||||||
### Timer non si aggiornano
|
|
||||||
|
|
||||||
**Causa:** Problemi JavaScript o pagina non risponde
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Clicca [Aggiorna] per ricaricare la pagina
|
|
||||||
2. Verifica connessione internet
|
|
||||||
3. Controlla il log per errori
|
|
||||||
|
|
||||||
### AutoBidder punta sull'asta sbagliata
|
|
||||||
|
|
||||||
**Causa:** Algoritmo priorità seleziona timer più basso
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Verifica che i limiti prezzo siano corretti
|
|
||||||
2. Rimuovi dai preferiti le aste indesiderate
|
|
||||||
3. Usa Max/Min Price per filtrare automaticamente
|
|
||||||
|
|
||||||
### Troppe aste nella griglia
|
|
||||||
|
|
||||||
**Causa:** Troppi preferiti, performance degradate
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Riduci preferiti a 5-10 aste
|
|
||||||
2. Rimuovi aste non interessanti
|
|
||||||
3. Filtra con limiti prezzo
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Suggerimenti Pro
|
|
||||||
|
|
||||||
### Selezione Aste Ottimale
|
|
||||||
|
|
||||||
- ? **Preferisci aste simili**: Stesso timer (tutte 8s o 10s)
|
|
||||||
- ? **Range prezzo ristretto**: Es. 10-50€ invece di 0-500€
|
|
||||||
- ? **Prodotti diversi**: Aumenta probabilità vincita
|
|
||||||
- ? **Evita troppi preferiti**: Max 10 per performance
|
|
||||||
|
|
||||||
### Configurazione Timer
|
|
||||||
|
|
||||||
- **Timer Click = 0**: Massima aggressività, tutte le aste
|
|
||||||
- **Timer Click = 1**: Bilanciato, tutte le aste
|
|
||||||
- **Limiti prezzo**: Filtra automaticamente aste indesiderate
|
|
||||||
|
|
||||||
### Monitoraggio Efficace
|
|
||||||
|
|
||||||
1. **Osserva la griglia** per capire dinamica aste
|
|
||||||
2. **Controlla il log** per vedere su quale asta si clicca
|
|
||||||
3. **Elenco utenti** per identificare competitor
|
|
||||||
4. **Adatta strategia** basandoti sui dati
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Strategie Avanzate
|
|
||||||
|
|
||||||
### Strategia "Spread" (Massima Copertura)
|
|
||||||
|
|
||||||
```
|
|
||||||
Obiettivo: Massimizzare vincite su aste diverse
|
|
||||||
|
|
||||||
Setup:
|
|
||||||
- Preferiti: 8-10 aste diverse
|
|
||||||
- Timer Click: 0
|
|
||||||
- Min Price: 5€
|
|
||||||
- Max Price: 100€
|
|
||||||
- Max Clicks: 200
|
|
||||||
|
|
||||||
Risultato: Click distribuiti su tutte le aste, aumenta probabilità vincita
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategia "Focus" (Range Prezzo)
|
|
||||||
|
|
||||||
```
|
|
||||||
Obiettivo: Vincere solo aste convenienti
|
|
||||||
|
|
||||||
Setup:
|
|
||||||
- Preferiti: 5-6 aste interessanti
|
|
||||||
- Timer Click: 1
|
|
||||||
- Min Price: 10€
|
|
||||||
- Max Price: 50€
|
|
||||||
- Max Clicks: 100
|
|
||||||
|
|
||||||
Risultato: Click solo su aste in range prezzo vantaggioso
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategia "Sniper" (Massima Velocità)
|
|
||||||
|
|
||||||
```
|
|
||||||
Obiettivo: Vincere asta specifica il più velocemente possibile
|
|
||||||
|
|
||||||
Setup:
|
|
||||||
- Preferiti: 1 asta target + 2-3 alternative
|
|
||||||
- Timer Click: 0
|
|
||||||
- Ritardo: 0ms
|
|
||||||
- Multi-Click: ?
|
|
||||||
- Max Clicks: 150
|
|
||||||
|
|
||||||
Risultato: Massima reattività sull'asta prioritaria
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Statistiche e Metriche
|
|
||||||
|
|
||||||
### Dati Visibili
|
|
||||||
|
|
||||||
**Griglia Multi-Asta:**
|
|
||||||
- Totale aste monitorate
|
|
||||||
- Timer in tempo reale per ogni asta
|
|
||||||
- Prezzo corrente per ogni asta
|
|
||||||
- Vincitore attuale per ogni asta
|
|
||||||
- Stato priorità (??/?)
|
|
||||||
|
|
||||||
**Pannello Statistiche (Invariato):**
|
|
||||||
- Auto-click: Totale click effettuati
|
|
||||||
- Resets: Totale reset rilevati
|
|
||||||
- Elenco Utenti: Chi punta e quante volte
|
|
||||||
- Log: Cronologia eventi dettagliata
|
|
||||||
|
|
||||||
### Informazioni Aggregate
|
|
||||||
|
|
||||||
Nel log vedrai:
|
|
||||||
```
|
|
||||||
?? Ricerca aste nei preferiti...
|
|
||||||
? Trovate 3 aste nei preferiti
|
|
||||||
?? Focus su: Galaxy S25 512GB (Timer: 1.8s)
|
|
||||||
?? Puntata di: user123 su Galaxy S25 512GB
|
|
||||||
? Click #1 (TuoNome) su Galaxy S25 512GB - Timer: 1.50s
|
|
||||||
?? Reset #1 su Galaxy S25 512GB - Winner: user123
|
|
||||||
?? Focus su: RTX 5080 (Timer: 2.3s)
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Confronto Modalità
|
|
||||||
|
|
||||||
### Asta Singola vs Multi-Asta (Griglia)
|
|
||||||
|
|
||||||
| Caratteristica | Asta Singola | Multi-Asta Griglia |
|
|
||||||
|----------------|-------------|-------------------|
|
|
||||||
| **Aste visibili** | 1 | Tutte simultanee |
|
|
||||||
| **Info real-time** | Timer, prezzo | Timer, prezzo, vincitore per tutte |
|
|
||||||
| **Priorità** | Fissa | Dinamica (timer più basso) |
|
|
||||||
| **Impostazioni** | Per asta | Globali + filtri |
|
|
||||||
| **Visibilità** | Limitata | Completa |
|
|
||||||
| **Complessità** | Bassa | Media |
|
|
||||||
| **Efficacia** | Alta (focus) | Altissima (opportunistica) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Personalizzazione Futura (v2.2+)
|
|
||||||
|
|
||||||
### Feature in Sviluppo
|
|
||||||
|
|
||||||
- [ ] **Impostazioni per asta**: Config individuali (Timer, limiti)
|
|
||||||
- [ ] **Pause per asta**: Disattiva singole aste temporaneamente
|
|
||||||
- [ ] **Click manuale**: Forza click su asta specifica
|
|
||||||
- [ ] **Priorità custom**: Ordina aste manualmente
|
|
||||||
- [ ] **Filtri avanzati**: Per categoria, prezzo, timer
|
|
||||||
- [ ] **Statistiche per asta**: Click, reset, vincite per asta
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Supporto
|
|
||||||
|
|
||||||
### Problemi Comuni
|
|
||||||
|
|
||||||
**Q: La griglia non mostra tutte le aste**
|
|
||||||
A: Attendi 5s per scansione, poi clicca [Aggiorna]
|
|
||||||
|
|
||||||
**Q: Timer troppo veloce, non leggo i dati**
|
|
||||||
A: Normale, la griglia si aggiorna velocemente. Usa il log per dettagli
|
|
||||||
|
|
||||||
**Q: Voglio disattivare una singola asta**
|
|
||||||
A: Rimuovila dai preferiti su Bidoo (temporaneamente)
|
|
||||||
|
|
||||||
**Q: Come vedo su quale asta sta cliccando?**
|
|
||||||
A: Guarda il log, ogni click indica il nome dell'asta
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
La **griglia Multi-Asta** porta AutoBidder a un nuovo livello:
|
|
||||||
|
|
||||||
? **Visibilità completa** di tutte le aste
|
|
||||||
? **Dati in tempo reale** per decisioni informate
|
|
||||||
? **Gestione automatica** intelligente
|
|
||||||
? **Log e statistiche** invariati per analisi
|
|
||||||
|
|
||||||
**Sperimenta, osserva la griglia, adatta la strategia e vinci di più!** ??
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.1 - Grid-Based Multi-Auction Monitoring*
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
# ?? Guida Multi-Asta AutoBidder
|
|
||||||
|
|
||||||
## ?? Panoramica
|
|
||||||
|
|
||||||
AutoBidder ora supporta **due modalità operative**:
|
|
||||||
|
|
||||||
### ?? Modalità Asta Singola
|
|
||||||
- Monitora e punta su **una singola asta**
|
|
||||||
- Comportamento classico, ottimizzato per massima precisione
|
|
||||||
- Ideale per focus su un prodotto specifico
|
|
||||||
|
|
||||||
### ?? Modalità Multi-Asta (NUOVO!)
|
|
||||||
- Monitora **tutte le aste nei preferiti** contemporaneamente
|
|
||||||
- Punta automaticamente sull'asta più vicina al momento del click
|
|
||||||
- **Ottimizza le risorse** usando una sola WebView invece di finestre multiple
|
|
||||||
- Perfetto per massimizzare le opportunità di vincita
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Usare la Modalità Multi-Asta
|
|
||||||
|
|
||||||
### 1. Preparazione
|
|
||||||
1. Accedi a **Bidoo** tramite AutoBidder
|
|
||||||
2. Aggiungi ai **Preferiti** tutte le aste che vuoi monitorare
|
|
||||||
- Clicca sulla stella ? nelle aste desiderate
|
|
||||||
3. Torna su AutoBidder
|
|
||||||
|
|
||||||
### 2. Attivazione
|
|
||||||
1. Clicca sul pulsante **"Multi-Asta"** nel pannello sinistro
|
|
||||||
- Il pulsante diventerà verde
|
|
||||||
- Il pannello "Asta Attiva" apparirà sotto le statistiche
|
|
||||||
- AutoBidder navigherà automaticamente a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
|
|
||||||
### 3. Configurazione
|
|
||||||
- Imposta i **parametri come al solito**:
|
|
||||||
- Max Clicks
|
|
||||||
- Max Resets
|
|
||||||
- Min/Max Price
|
|
||||||
- Timer Click
|
|
||||||
- Ritardo (ms)
|
|
||||||
- Multi-Click (opzionale)
|
|
||||||
|
|
||||||
### 4. Avvio
|
|
||||||
1. Clicca su **"Avvia"**
|
|
||||||
2. AutoBidder eseguirà:
|
|
||||||
- ? Scansione di tutte le aste nei preferiti (ogni 5 secondi)
|
|
||||||
- ? Monitoraggio real-time dei timer di ogni asta
|
|
||||||
- ? Selezione automatica dell'asta più vicina al momento del click
|
|
||||||
- ? Click automatico sull'asta prioritaria
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Funzionamento Intelligente
|
|
||||||
|
|
||||||
### Algoritmo di Priorità
|
|
||||||
AutoBidder analizza **tutte le aste monitorate** e seleziona quella con:
|
|
||||||
- ?? **Timer più basso** (più vicina al momento del click)
|
|
||||||
- ? **Prezzo entro i limiti** configurati (se impostati)
|
|
||||||
- ?? **Stato attivo** (non venduta, non chiusa)
|
|
||||||
|
|
||||||
### Esempio Pratico
|
|
||||||
```
|
|
||||||
Aste nei preferiti:
|
|
||||||
?? Galaxy S25 512GB ? Timer: 7.2s ? ? Troppo lontano
|
|
||||||
?? RTX 5080 ? Timer: 1.8s ? ? SELEZIONATA!
|
|
||||||
?? Galaxy S25 Ultra ? Timer: 4.5s ? ? Non prioritaria
|
|
||||||
|
|
||||||
? AutoBidder punta su "RTX 5080" (timer più basso)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Interfaccia Pannello Multi-Asta
|
|
||||||
|
|
||||||
### Indicatori Visivi
|
|
||||||
- **Asta Attiva**: Mostra il nome dell'asta su cui AutoBidder sta puntando
|
|
||||||
- **Aste monitorate**: Contatore delle aste totali nei preferiti
|
|
||||||
- **Prezzo corrente**: Prezzo dell'asta attiva corrente
|
|
||||||
- **Log dettagliato**: Eventi di ogni asta con nome specifico
|
|
||||||
|
|
||||||
### Messaggi Log
|
|
||||||
```
|
|
||||||
?? Ricerca aste nei preferiti...
|
|
||||||
? Trovate 3 aste nei preferiti
|
|
||||||
?? Focus su: Galaxy S25 512GB (Timer: 1.8s)
|
|
||||||
?? Puntata di: utente123 su Galaxy S25 512GB
|
|
||||||
? Click #1 (TuoNome) su Galaxy S25 512GB - Timer: 1.50s
|
|
||||||
?? Reset #1 su Galaxy S25 512GB - Winner: utente123
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Ottimizzazioni e Performance
|
|
||||||
|
|
||||||
### Vantaggi Multi-Asta
|
|
||||||
- ?? **Una sola WebView** invece di finestre multiple
|
|
||||||
- ?? **Riduzione uso memoria** (~70% rispetto a finestre separate)
|
|
||||||
- ? **Polling dinamico** basato sul timer più urgente
|
|
||||||
- ?? **Scansione periodica** per rilevare nuove aste
|
|
||||||
|
|
||||||
### Polling Intelligente
|
|
||||||
- Timer < 1.5s ? Polling ogni **20ms** (ultra-reattivo)
|
|
||||||
- Timer < 2.5s ? Polling ogni **40ms** (molto veloce)
|
|
||||||
- Timer < 3.5s ? Polling ogni **80ms** (veloce)
|
|
||||||
- Timer < 5.0s ? Polling ogni **150ms** (normale)
|
|
||||||
- Timer > 8.0s ? Polling ogni **400ms** (risparmio risorse)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Impostazioni e Limiti
|
|
||||||
|
|
||||||
### Funzionano in Multi-Asta
|
|
||||||
? Max Clicks (globale su tutte le aste)
|
|
||||||
? Max Resets (globale)
|
|
||||||
? Min/Max Price (applicate a ogni asta)
|
|
||||||
? Timer Click (0-8 secondi)
|
|
||||||
? Ritardo click (ms)
|
|
||||||
? Multi-Click
|
|
||||||
? Pausa/Riprendi
|
|
||||||
|
|
||||||
### Strategia Prezzi
|
|
||||||
- **Min Price**: AutoBidder **non punterà** su aste sotto il minimo
|
|
||||||
- **Max Price**: AutoBidder **non punterà** su aste sopra il massimo
|
|
||||||
- Se **nessuna asta** rispetta i limiti, AutoBidder aspetta
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Risoluzione Problemi
|
|
||||||
|
|
||||||
### "Nessuna asta trovata nei preferiti"
|
|
||||||
- ? Verifica di essere sulla pagina `https://it.bidoo.com/?tab=FAV`
|
|
||||||
- ? Assicurati di aver aggiunto aste ai preferiti (stella ?)
|
|
||||||
- ? Ricarica la pagina (pulsante "Aggiorna")
|
|
||||||
|
|
||||||
### "AutoBidder non punta"
|
|
||||||
- ? Controlla i limiti Min/Max Price
|
|
||||||
- ? Verifica che Timer Click sia impostato correttamente (0-8)
|
|
||||||
- ? Assicurati che "Pausa" non sia attiva
|
|
||||||
- ? Controlla il log per messaggi "Click bloccato"
|
|
||||||
|
|
||||||
### Performance degradate
|
|
||||||
- ? Riduci il numero di aste nei preferiti (< 10 ideale)
|
|
||||||
- ? Chiudi altre applicazioni pesanti
|
|
||||||
- ? Usa "Pulisci" sul log periodicamente
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Asta Singola vs Multi-Asta
|
|
||||||
|
|
||||||
| Caratteristica | Asta Singola | Multi-Asta |
|
|
||||||
|---------------|-------------|------------|
|
|
||||||
| **Aste monitorate** | 1 | Illimitate (preferiti) |
|
|
||||||
| **Uso memoria** | Basso | Medio |
|
|
||||||
| **Precisione click** | Massima | Alta |
|
|
||||||
| **Flessibilità** | Focus | Opportunistica |
|
|
||||||
| **Configurazione** | Semplice | Automatica |
|
|
||||||
| **Ideale per** | Prodotto specifico | Massimizzare vincite |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Suggerimenti Pro
|
|
||||||
|
|
||||||
### Strategia Ottimale
|
|
||||||
1. **Seleziona aste simili** nei preferiti (stesso timer, stessa categoria)
|
|
||||||
2. **Imposta Min/Max Price** per filtrare opportunità
|
|
||||||
3. **Usa Timer Click = 0-1** per massima aggressività
|
|
||||||
4. **Attiva Multi-Click** se la connessione è instabile
|
|
||||||
|
|
||||||
### Best Practices
|
|
||||||
- ?? **Non eccedere 10-15 aste** nei preferiti (performance)
|
|
||||||
- ?? **Preferisci aste con timer simili** (8s o 10s)
|
|
||||||
- ?? **Imposta limiti prezzo realistici**
|
|
||||||
- ?? **Ricarica periodicamente** la pagina preferiti (ogni 2-3 minuti)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Sicurezza e Conformità
|
|
||||||
|
|
||||||
### Rispetto dei Limiti Bidoo
|
|
||||||
- ? AutoBidder **non aggira** limiti di Bidoo
|
|
||||||
- ? Rispetta vincoli "1 vincita ogni 30 giorni"
|
|
||||||
- ? Non modifica comportamento del sito
|
|
||||||
- ? Opera solo tramite **interfaccia ufficiale**
|
|
||||||
|
|
||||||
### Privacy
|
|
||||||
- ?? Nessun dato inviato esternamente
|
|
||||||
- ?? Funzionamento 100% locale
|
|
||||||
- ?? Nessun tracciamento o telemetria
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Registro Modifiche
|
|
||||||
|
|
||||||
### v2.0 - Multi-Asta Release
|
|
||||||
- ? Nuova modalità Multi-Asta
|
|
||||||
- ? Monitoraggio simultaneo aste preferiti
|
|
||||||
- ? Selezione intelligente asta prioritaria
|
|
||||||
- ? Pannello "Asta Attiva" dinamico
|
|
||||||
- ? Ottimizzazione risorse (singola WebView)
|
|
||||||
- ? Log dettagliato per asta
|
|
||||||
- ? Rilevamento automatico reset per asta
|
|
||||||
- ? Tracciamento bidder per asta
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Supporto
|
|
||||||
|
|
||||||
Per problemi o domande:
|
|
||||||
1. Controlla questa guida
|
|
||||||
2. Verifica i log di AutoBidder
|
|
||||||
3. Riavvia l'applicazione
|
|
||||||
4. Prova prima in modalità Asta Singola
|
|
||||||
|
|
||||||
**Buone aste! ??**
|
|
||||||
+379
-542
@@ -1,609 +1,446 @@
|
|||||||
<Window x:Class="AutoBidder.MainWindow"
|
<Window x:Class="AutoBidder.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:local="clr-namespace:AutoBidder.Converters"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
Title="AutoBidder v3.0" Height="800" Width="1400"
|
||||||
xmlns:local="clr-namespace:AutoBidder"
|
Background="#0a0a0a" Foreground="#FFFFFF"
|
||||||
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
|
WindowStartupLocation="CenterScreen">
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="AutoBidder - Bidoo Auto Bid"
|
|
||||||
Height="700" Width="1100"
|
|
||||||
MinHeight="600" MinWidth="900"
|
|
||||||
Background="#101219" Foreground="#E6EDF3">
|
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<Style x:Key="PrimaryButtonStyle" TargetType="Button">
|
<!-- Stile pulsanti stile vecchia versione -->
|
||||||
|
<Style x:Key="MainButtonStyle" TargetType="Button">
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
<Setter Property="FontWeight" Value="SemiBold" />
|
<Setter Property="FontWeight" Value="Bold" />
|
||||||
<Setter Property="Padding" Value="10,6" />
|
<Setter Property="FontSize" Value="14" />
|
||||||
<Setter Property="Margin" Value="0,6,0,0" />
|
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
<Setter Property="Height" Value="40" />
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="Button">
|
<ControlTemplate TargetType="Button">
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="8" SnapsToDevicePixels="True">
|
<Border Background="{TemplateBinding Background}"
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" />
|
CornerRadius="8"
|
||||||
|
Padding="{TemplateBinding Padding}">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="StartButtonStyle" TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}">
|
<Style x:Key="SmallButtonStyle" TargetType="Button">
|
||||||
<Setter Property="Background" Value="#16A34A" /> <!-- green -->
|
<Setter Property="Foreground" Value="White" />
|
||||||
</Style>
|
|
||||||
<Style x:Key="StopButtonStyle" TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}">
|
|
||||||
<Setter Property="Background" Value="#DC2626" /> <!-- red -->
|
|
||||||
<Setter Property="Opacity" Value="0.6" />
|
|
||||||
</Style>
|
|
||||||
<Style x:Key="PauseButtonStyle" TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}">
|
|
||||||
<Setter Property="Background" Value="#F59E0B" /> <!-- yellow -->
|
|
||||||
<Setter Property="Height" Value="40" />
|
|
||||||
</Style>
|
|
||||||
<Style x:Key="RefreshButtonStyle" TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}">
|
|
||||||
<Setter Property="Background" Value="#0EA5E9" /> <!-- blue -->
|
|
||||||
<Setter Property="Height" Value="30" />
|
|
||||||
<Setter Property="Padding" Value="8,4" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style TargetType="TextBlock">
|
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="LogBoxStyle" TargetType="TextBox">
|
|
||||||
<Setter Property="Background" Value="#0F1720" />
|
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
|
||||||
<Setter Property="BorderBrush" Value="#263143" />
|
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
|
||||||
<Setter Property="Padding" Value="8" />
|
|
||||||
<Setter Property="FontFamily" Value="Consolas" />
|
|
||||||
<Setter Property="FontSize" Value="12" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style x:Key="NumericBoxStyle" TargetType="TextBox">
|
|
||||||
<Setter Property="Background" Value="#0B1220" />
|
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
|
||||||
<Setter Property="BorderBrush" Value="#263143" />
|
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
|
||||||
<Setter Property="Padding" Value="6" />
|
|
||||||
<Setter Property="Width" Value="80" />
|
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
|
||||||
<Setter Property="FontWeight" Value="SemiBold" />
|
<Setter Property="FontWeight" Value="SemiBold" />
|
||||||
</Style>
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
<Style x:Key="AddressBarStyle" TargetType="TextBox">
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
<Setter Property="Background" Value="#0B1220" />
|
<Setter Property="Template">
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
<Setter.Value>
|
||||||
<Setter Property="BorderBrush" Value="#263143" />
|
<ControlTemplate TargetType="Button">
|
||||||
<Setter Property="BorderThickness" Value="1" />
|
<Border Background="{TemplateBinding Background}"
|
||||||
<Setter Property="Padding" Value="8,6" />
|
CornerRadius="6"
|
||||||
<Setter Property="FontSize" Value="13" />
|
Padding="{TemplateBinding Padding}">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid>
|
<Grid Margin="12" Background="#0a0a0a">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<ColumnDefinition Width="1*" MinWidth="260" />
|
<RowDefinition Height="Auto" />
|
||||||
<ColumnDefinition Width="6" />
|
<RowDefinition Height="Auto" />
|
||||||
<ColumnDefinition Width="2*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.ColumnDefinitions>
|
<RowDefinition Height="8" />
|
||||||
|
<RowDefinition Height="*" MinHeight="200" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Left panel: fixed height, resizable width -->
|
<!-- Header Compatto -->
|
||||||
<Border Grid.Column="0" Margin="12" Background="#0B1015" CornerRadius="6">
|
<Border Grid.Row="0" Background="#1a1a1a" Padding="12" CornerRadius="8" Margin="0,0,0,12">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Mode selector -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Start -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Pause -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Stop -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Stats globali -->
|
|
||||||
<RowDefinition Height="*" /> <!-- Griglia Aste Multi (resizable) oppure Settings/Bidders/Log Singola -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Modalità Asta Singola / Multi-Asta -->
|
|
||||||
<Grid Grid.Row="0" Margin="12,12,12,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Button x:Name="SingleAuctionButton" Grid.Column="0" Click="SingleAuctionButton_Click"
|
|
||||||
Background="#16A34A" Foreground="White" Padding="10,6" BorderThickness="0"
|
|
||||||
Height="40" FontWeight="SemiBold" Margin="0,0,4,0">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="8" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
Asta Singola
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button x:Name="MultiAuctionButton" Grid.Column="1" Click="MultiAuctionButton_Click"
|
|
||||||
Background="#374151" Foreground="White" Padding="10,6" BorderThickness="0"
|
|
||||||
Height="40" FontWeight="SemiBold" Margin="4,0,0,0" Opacity="0.6">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="8" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
Multi-Asta
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Button x:Name="StartButton" Grid.Row="1" Style="{StaticResource StartButtonStyle}" Click="StartButton_Click" Margin="12,6,12,0">Avvia</Button>
|
|
||||||
|
|
||||||
<Button x:Name="PauseBidButton" Grid.Row="2" Style="{StaticResource PauseButtonStyle}" Click="PauseBidButton_Click" Margin="12,6,12,0">Pausa</Button>
|
|
||||||
|
|
||||||
<Button x:Name="StopButton" Grid.Row="3" Style="{StaticResource StopButtonStyle}" Click="StopButton_Click" IsEnabled="False" Margin="12,6,12,0">Stop</Button>
|
|
||||||
|
|
||||||
<!-- Stats Globali (solo Asta Singola) -->
|
|
||||||
<Grid x:Name="SingleAuctionStatsPanel" Grid.Row="4" Margin="12,8,12,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Column="0" Orientation="Vertical">
|
<!-- Info Utente -->
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,20,0">
|
||||||
|
<TextBlock Text="User" FontSize="16" Margin="0,0,8,0" Foreground="#00CC66" FontWeight="Bold" />
|
||||||
|
<TextBlock x:Name="UsernameText" Text="Non configurato" FontSize="13" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" />
|
||||||
|
<TextBlock Text=" | Bids " FontSize="13" Foreground="#666" Margin="12,0,8,0" />
|
||||||
|
<TextBlock x:Name="RemainingBidsText" Text="--" FontSize="13" FontWeight="Bold" Foreground="#0099FF" VerticalAlignment="Center" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Pulsanti Centrali -->
|
||||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<Button x:Name="ConfigSessionButton" Content="Configura" Click="ConfigSessionButton_Click"
|
||||||
|
Style="{StaticResource SmallButtonStyle}"
|
||||||
|
Background="#8B5CF6" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" />
|
||||||
|
<Button x:Name="StartButton" Content="Avvia Tutti" Click="StartButton_Click" IsEnabled="False"
|
||||||
|
Style="{StaticResource SmallButtonStyle}"
|
||||||
|
Background="#00CC66" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" />
|
||||||
|
<Button x:Name="PauseAllButton" Content="Pausa Tutti" Click="PauseAllButton_Click" IsEnabled="True"
|
||||||
|
Style="{StaticResource SmallButtonStyle}"
|
||||||
|
Background="#FF9933" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" />
|
||||||
|
<Button x:Name="StopButton" Content="Ferma Tutti" Click="StopButton_Click" IsEnabled="False"
|
||||||
|
Style="{StaticResource SmallButtonStyle}"
|
||||||
|
Background="#CC0000" Padding="20,10" Opacity="0.5" Height="40" MinWidth="110" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Contatore Aste -->
|
||||||
|
<Border Grid.Column="2" Background="#0f0f0f" CornerRadius="6" Padding="16,8" VerticalAlignment="Center">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="Auto-click:" Margin="0,0,8,0" />
|
<TextBlock Text="Aste:" FontSize="12" Foreground="#999" Margin="0,0,8,0" VerticalAlignment="Center" />
|
||||||
<TextBlock x:Name="ClickCountText" Text="0" FontWeight="Bold" Margin="0,0,16,0" />
|
<TextBlock x:Name="TotalAuctionsText" Text="0" FontWeight="Bold" FontSize="18" Foreground="#00CC66" VerticalAlignment="Center" />
|
||||||
<TextBlock Text="Resets:" Margin="0,0,8,0" />
|
|
||||||
<TextBlock x:Name="ResetCountText" Text="0" FontWeight="Bold" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel x:Name="SingleAuctionPricePanel" Orientation="Horizontal" Margin="0,6,0,0">
|
</Border>
|
||||||
<TextBlock Text="Prezzo corrente:" Margin="0,0,8,0" VerticalAlignment="Center" />
|
|
||||||
<TextBlock x:Name="CurrentPriceText" Text="-" FontWeight="Bold" FontSize="14" Foreground="#10B981" VerticalAlignment="Center" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- Multi-Click a destra -->
|
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
|
|
||||||
<CheckBox x:Name="MultiClickCheckBox" IsChecked="False" VerticalAlignment="Center" ToolTip="Click multipli per maggiore affidabilità" />
|
|
||||||
<TextBlock Text="Multi-Click" FontSize="11" Margin="6,0,0,0" VerticalAlignment="Center" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- CONTENUTO DINAMICO: Asta Singola oppure Multi-Asta -->
|
<!-- Riga vuota (toolbar rimossa) -->
|
||||||
|
<Grid Grid.Row="1" Height="0" />
|
||||||
|
|
||||||
<!-- Pannello Asta Singola (Settings, Bidders, Log) -->
|
<!-- Griglia Aste + Log -->
|
||||||
<Grid x:Name="SingleAuctionPanel" Grid.Row="5" Margin="0,8,0,0">
|
<Grid Grid.Row="2">
|
||||||
<Grid.RowDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<RowDefinition Height="Auto" /> <!-- Settings Row 1 -->
|
<ColumnDefinition Width="2*" />
|
||||||
<RowDefinition Height="Auto" /> <!-- Settings Row 2 -->
|
<ColumnDefinition Width="8" />
|
||||||
<RowDefinition Height="Auto" /> <!-- Bidders label -->
|
<ColumnDefinition Width="*" MinWidth="200" />
|
||||||
<RowDefinition Height="Auto" /> <!-- Bidders grid -->
|
</Grid.ColumnDefinitions>
|
||||||
<RowDefinition Height="Auto" /> <!-- Log label -->
|
|
||||||
<RowDefinition Height="*" /> <!-- Log box expands -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Settings Row 1 -->
|
<!-- Box Aste Monitorate -->
|
||||||
<Grid Grid.Row="0" Margin="12,0,12,0">
|
<Border Grid.Column="0" Background="#1a1a1a" Padding="12" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid>
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="8" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="8" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Vertical">
|
<!-- Header con titolo e pulsanti -->
|
||||||
<TextBlock Text="Max Clicks" FontSize="11" />
|
<Grid Grid.Row="0" Margin="0,0,0,12">
|
||||||
<TextBox x:Name="MaxClicksBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="0 = nessun limite" TextChanged="MaxClicksBox_TextChanged" />
|
<TextBlock Text="Aste Monitorate" FontSize="14" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" />
|
||||||
</StackPanel>
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button x:Name="AddUrlButton" Content="+ Aggiungi" Click="AddUrlButton_Click"
|
||||||
|
Style="{StaticResource SmallButtonStyle}"
|
||||||
|
Background="#00CC66" Padding="12,6" Margin="0,0,6,0" Height="28" MinWidth="80" FontSize="11" />
|
||||||
|
<Button x:Name="RemoveUrlButton" Content="- Rimuovi" Click="RemoveUrlButton_Click"
|
||||||
|
Style="{StaticResource SmallButtonStyle}"
|
||||||
|
Background="#CC0000" Padding="12,6" Height="28" MinWidth="80" FontSize="11" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Vertical">
|
<!-- Griglia Aste -->
|
||||||
<TextBlock Text="Max Resets" FontSize="11" />
|
<DataGrid x:Name="MultiAuctionsGrid" Grid.Row="1" AutoGenerateColumns="False"
|
||||||
<TextBox x:Name="MaxResetsBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="0 = nessun limite" TextChanged="MaxResetsBox_TextChanged" />
|
Background="#1a1a1a" Foreground="#FFFFFF" SelectionChanged="MultiAuctionsGrid_SelectionChanged"
|
||||||
</StackPanel>
|
BorderBrush="#333333" BorderThickness="1" GridLinesVisibility="Horizontal"
|
||||||
|
HorizontalGridLinesBrush="#333333" RowBackground="#1a1a1a" AlternatingRowBackground="#222222">
|
||||||
<StackPanel Grid.Row="2" Grid.Column="0" Orientation="Vertical">
|
<DataGrid.Resources>
|
||||||
<TextBlock Text="Min Price €" FontSize="11" />
|
<Style TargetType="DataGridColumnHeader">
|
||||||
<TextBox x:Name="MinPriceBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="0 = nessun limite" TextChanged="MinPriceBox_TextChanged" />
|
<Setter Property="Background" Value="#2a2a2a" />
|
||||||
</StackPanel>
|
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||||
|
<Setter Property="FontWeight" Value="Bold" />
|
||||||
<StackPanel Grid.Row="2" Grid.Column="2" Orientation="Vertical">
|
<Setter Property="Padding" Value="10,8" />
|
||||||
<TextBlock Text="Max Price €" FontSize="11" />
|
<Setter Property="BorderThickness" Value="0,0,0,2" />
|
||||||
<TextBox x:Name="MaxPriceBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="0 = nessun limite" TextChanged="MaxPriceBox_TextChanged" />
|
<Setter Property="BorderBrush" Value="#00CC66" />
|
||||||
</StackPanel>
|
</Style>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<Setter Property="Height" Value="36" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<!-- Colore basato sullo stato dell'asta -->
|
||||||
|
<DataTrigger Binding="{Binding StatusDisplay}" Value="VINTA">
|
||||||
|
<Setter Property="Background" Value="#1B5E20" />
|
||||||
|
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding StatusDisplay}" Value="Persa">
|
||||||
|
<Setter Property="Background" Value="#B71C1C" />
|
||||||
|
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding StatusDisplay}" Value="In Corso">
|
||||||
|
<Setter Property="Background" Value="#1a1a1a" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding StatusDisplay}" Value="Inizia presto">
|
||||||
|
<Setter Property="Background" Value="#FF6F00" />
|
||||||
|
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding StatusDisplay}" Value="Programmata">
|
||||||
|
<Setter Property="Background" Value="#424242" />
|
||||||
|
<Setter Property="Foreground" Value="#AAAAAA" />
|
||||||
|
</DataTrigger>
|
||||||
|
<!-- Override quando selezionata -->
|
||||||
|
<Trigger Property="IsSelected" Value="True">
|
||||||
|
<Setter Property="Background" Value="#0099FF" />
|
||||||
|
<Setter Property="Foreground" Value="White" />
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="DataGridCell">
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Padding" Value="10,6" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Asta" Binding="{Binding Name, Mode=OneWay}" Width="2*" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Stato" Binding="{Binding StatusDisplay, Mode=OneWay}" Width="90" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Timer" Binding="{Binding TimerDisplay, Mode=OneWay}" Width="70" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Prezzo" Binding="{Binding PriceDisplay, Mode=OneWay}" Width="85" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Ultimo" Binding="{Binding LastBidder, Mode=OneWay}" Width="100" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Clicks" Binding="{Binding MyClicks, Mode=OneWay}" Width="60" IsReadOnly="True" />
|
||||||
|
<DataGridTextColumn Header="Resets" Binding="{Binding ResetCount, Mode=OneWay}" Width="60" IsReadOnly="True" />
|
||||||
|
<DataGridTemplateColumn Header="Azioni" Width="260">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<Button Content="Avvia" CommandParameter="{Binding}" Click="GridStartAuction_Click" Style="{StaticResource SmallButtonStyle}" Background="#00CC66" Padding="6,2" MinWidth="40" Margin="0,0,4,0">
|
||||||
|
<Button.Opacity>
|
||||||
|
<MultiBinding Converter="{StaticResource StartButtonOpacityConverter}">
|
||||||
|
<Binding Path="IsActive" />
|
||||||
|
<Binding Path="IsPaused" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Button.Opacity>
|
||||||
|
<Button.IsEnabled>
|
||||||
|
<MultiBinding Converter="{StaticResource StartResumeConverter}">
|
||||||
|
<Binding Path="IsActive" />
|
||||||
|
<Binding Path="IsPaused" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Button.IsEnabled>
|
||||||
|
</Button>
|
||||||
|
<Button Content="Pausa" CommandParameter="{Binding}" Click="GridPauseAuction_Click" Style="{StaticResource SmallButtonStyle}" Background="#FF9933" Padding="6,2" MinWidth="40" Margin="0,0,4,0">
|
||||||
|
<Button.IsEnabled>
|
||||||
|
<MultiBinding Converter="{StaticResource AndNotPausedConverter}">
|
||||||
|
<Binding Path="IsActive" />
|
||||||
|
<Binding Path="IsPaused" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Button.IsEnabled>
|
||||||
|
<Button.Opacity>
|
||||||
|
<MultiBinding Converter="{StaticResource PauseButtonOpacityConverter}">
|
||||||
|
<Binding Path="IsActive" />
|
||||||
|
<Binding Path="IsPaused" />
|
||||||
|
</MultiBinding>
|
||||||
|
</Button.Opacity>
|
||||||
|
</Button>
|
||||||
|
<Button Content="Ferma" CommandParameter="{Binding}" Click="GridStopAuction_Click" Style="{StaticResource SmallButtonStyle}" Background="#CC0000" Padding="6,2" MinWidth="40" Margin="0,0,4,0"
|
||||||
|
IsEnabled="{Binding IsActive}"
|
||||||
|
Opacity="{Binding IsActive, Converter={StaticResource BoolToOpacityConverter}}" />
|
||||||
|
<Button Content="Punta" CommandParameter="{Binding}" Click="GridManualBid_Click" Style="{StaticResource SmallButtonStyle}" Background="#8B5CF6" Padding="6,2" MinWidth="40" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<!-- Settings Row 2 -->
|
<GridSplitter Grid.Column="1" Width="8" HorizontalAlignment="Stretch" Background="#333333" />
|
||||||
<Grid Grid.Row="1" Margin="12,6,12,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="8" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="0" Orientation="Vertical">
|
<!-- Log Globale -->
|
||||||
<TextBlock Text="Timer Click" FontSize="11" />
|
<Border Grid.Column="2" Background="#1a1a1a" Padding="12" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
|
||||||
<TextBox x:Name="ClickTimerBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="Secondo del timer per il click (0-8)" TextChanged="ClickTimerBox_TextChanged" />
|
<Grid>
|
||||||
</StackPanel>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
<StackPanel Grid.Column="2" Orientation="Vertical">
|
<RowDefinition Height="*" />
|
||||||
<TextBlock Text="Ritardo (ms)" FontSize="11" />
|
<RowDefinition Height="Auto" />
|
||||||
<TextBox x:Name="ClickDelayBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="Ritardo aggiuntivo in millisecondi" TextChanged="ClickDelayBox_TextChanged" />
|
</Grid.RowDefinitions>
|
||||||
</StackPanel>
|
<TextBlock Grid.Row="0" Text="Log Globale" FontWeight="Bold" Margin="0,0,0,10" FontSize="14" Foreground="#00CC66" />
|
||||||
|
<RichTextBox x:Name="LogBox" Grid.Row="1" IsReadOnly="True" VerticalScrollBarVisibility="Auto"
|
||||||
|
Background="#0f0f0f" Foreground="#CCCCCC" Padding="8"
|
||||||
|
FontFamily="Consolas" FontSize="11" BorderBrush="#333333" BorderThickness="1" />
|
||||||
|
<Button x:Name="ClearGlobalLogButton" Grid.Row="2" Content="Pulisci Log" Click="ClearGlobalLogButton_Click"
|
||||||
|
Style="{StaticResource SmallButtonStyle}" IsEnabled="True"
|
||||||
|
Background="#666" Padding="10,8" Height="32" FontSize="11" Margin="0,8,0,0" HorizontalAlignment="Stretch" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- Bidders section -->
|
<GridSplitter Grid.Row="3" Height="8" HorizontalAlignment="Stretch" Background="#333333" />
|
||||||
<Grid Grid.Row="2" Margin="12,8,12,4">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Grid.Column="0" Text="Elenco utenti (per numero puntate)" VerticalAlignment="Center" FontSize="12" />
|
|
||||||
<Button x:Name="ClearBiddersButton" Grid.Column="1" Content="Pulisci" Click="ClearBiddersButton_Click"
|
|
||||||
Background="#0EA5E9" Foreground="White" Padding="24,6" BorderThickness="0"
|
|
||||||
FontSize="12" MinWidth="80" Height="30" VerticalAlignment="Center" FontWeight="SemiBold">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="5" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<DataGrid x:Name="BiddersGrid" Grid.Row="3" Margin="12,0,12,0" AutoGenerateColumns="False" HeadersVisibility="Column" CanUserAddRows="False" IsReadOnly="True" Height="90" Background="#091018" RowBackground="#0B1220" AlternatingRowBackground="#081016" Foreground="#E6EDF3" GridLinesVisibility="None">
|
<!-- Dettagli Asta Selezionata - 3 Pannelli Affiancati -->
|
||||||
<DataGrid.Resources>
|
<Border Grid.Row="4" Background="#1a1a1a" Padding="8" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
|
||||||
<Style TargetType="DataGridColumnHeader">
|
<Grid>
|
||||||
<Setter Property="Background" Value="#0F1720" />
|
<Grid.ColumnDefinitions>
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
<ColumnDefinition Width="*" MinWidth="250" />
|
||||||
<Setter Property="FontWeight" Value="SemiBold" />
|
<ColumnDefinition Width="4" />
|
||||||
</Style>
|
<ColumnDefinition Width="*" MinWidth="200" />
|
||||||
<Style TargetType="DataGridCell">
|
<ColumnDefinition Width="4" />
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
<ColumnDefinition Width="*" MinWidth="200" />
|
||||||
<Setter Property="Background" Value="Transparent" />
|
</Grid.ColumnDefinitions>
|
||||||
</Style>
|
|
||||||
</DataGrid.Resources>
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn Header="Utente" Binding="{Binding Name}" Width="*" />
|
|
||||||
<DataGridTextColumn Header="Puntate" Binding="{Binding Count}" Width="120" />
|
|
||||||
<DataGridTextColumn Header="Ultima puntata" Binding="{Binding LastBid}" Width="160" />
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
|
|
||||||
<Grid Grid.Row="4" Margin="12,6,12,4">
|
<!-- PANNELLO 1: Impostazioni Asta -->
|
||||||
<Grid.ColumnDefinitions>
|
<Border Grid.Column="0" Background="#0f0f0f" Padding="12" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Grid.Column="0" Text="Log operazioni" VerticalAlignment="Center" FontSize="12" />
|
|
||||||
<Button x:Name="ClearLogButton" Grid.Column="1" Content="Pulisci" Click="ClearLogButton_Click"
|
|
||||||
Background="#0EA5E9" Foreground="White" Padding="24,6" BorderThickness="0"
|
|
||||||
FontSize="12" MinWidth="80" Height="30" VerticalAlignment="Center" FontWeight="SemiBold">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="5" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<TextBox x:Name="LogBox" Grid.Row="5" Margin="12,0,12,12" IsReadOnly="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True" Style="{StaticResource LogBoxStyle}" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- Pannello Multi-Asta (Griglia + Dettagli Asta Selezionata) -->
|
|
||||||
<Grid x:Name="MultiAuctionPanel" Grid.Row="5" Margin="0,8,0,0" Visibility="Visible">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="2*" MinHeight="150" /> <!-- Griglia aste (resizable) -->
|
|
||||||
<RowDefinition Height="12" /> <!-- Splitter (aumentato da 6 a 12) -->
|
|
||||||
<RowDefinition Height="*" MinHeight="120" /> <!-- Dettagli asta selezionata -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Griglia Aste -->
|
|
||||||
<Border Grid.Row="0" Background="#0F1720" CornerRadius="6" Margin="12,0,12,8">
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<Border Grid.Row="0" Background="#1E293B" Padding="8,6" CornerRadius="6,6,0,0">
|
<Grid Grid.Row="0" Margin="0,0,0,12">
|
||||||
<Grid>
|
<TextBlock Text="Impostazioni" FontSize="13" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" />
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Grid.Column="0" Text="📊 Aste Monitorate" FontWeight="Bold" FontSize="12" Foreground="#E6EDF3" VerticalAlignment="Center" />
|
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
|
|
||||||
<TextBlock Text="Totale:" Margin="0,0,6,0" FontSize="11" Foreground="#94A3B8" VerticalAlignment="Center" />
|
|
||||||
<TextBlock x:Name="TotalAuctionsText" Text="0" FontWeight="Bold" FontSize="11" Foreground="#10B981" VerticalAlignment="Center" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- DataGrid Aste -->
|
|
||||||
<DataGrid x:Name="MultiAuctionsGrid" Grid.Row="1" Margin="8,8,8,8" AutoGenerateColumns="False"
|
|
||||||
HeadersVisibility="Column" CanUserAddRows="False" IsReadOnly="True"
|
|
||||||
Background="#091018" RowBackground="#0B1220"
|
|
||||||
AlternatingRowBackground="#081016" Foreground="#E6EDF3" GridLinesVisibility="Horizontal"
|
|
||||||
BorderThickness="0" SelectionMode="Single" SelectionChanged="MultiAuctionsGrid_SelectionChanged">
|
|
||||||
<DataGrid.Resources>
|
|
||||||
<Style TargetType="DataGridColumnHeader">
|
|
||||||
<Setter Property="Background" Value="#0F1720" />
|
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
|
||||||
<Setter Property="FontWeight" Value="SemiBold" />
|
|
||||||
<Setter Property="Padding" Value="8,6" />
|
|
||||||
<Setter Property="BorderThickness" Value="0,0,0,1" />
|
|
||||||
<Setter Property="BorderBrush" Value="#263143" />
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="DataGridCell">
|
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
|
||||||
<Setter Property="Background" Value="Transparent" />
|
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
|
||||||
<Setter Property="Padding" Value="8,4" />
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="DataGridRow">
|
|
||||||
<Setter Property="Height" Value="32" />
|
|
||||||
<Style.Triggers>
|
|
||||||
<Trigger Property="IsSelected" Value="True">
|
|
||||||
<Setter Property="Background" Value="#1E40AF" />
|
|
||||||
</Trigger>
|
|
||||||
<!-- Evidenzia riga quando è la mia puntata -->
|
|
||||||
<DataTrigger Binding="{Binding IsMyBid}" Value="True">
|
|
||||||
<Setter Property="Background" Value="#15803D" />
|
|
||||||
<Setter Property="FontWeight" Value="Bold" />
|
|
||||||
</DataTrigger>
|
|
||||||
<!-- ⭐ NUOVO: Colora asta in pausa -->
|
|
||||||
<DataTrigger Binding="{Binding IsPaused}" Value="True">
|
|
||||||
<Setter Property="Background" Value="#78350F" />
|
|
||||||
<Setter Property="Opacity" Value="0.7" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</DataGrid.Resources>
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn Header="Asta" Binding="{Binding Name}" Width="2*" />
|
|
||||||
<DataGridTextColumn Header="Timer" Binding="{Binding TimerDisplay}" Width="60" />
|
|
||||||
<DataGridTextColumn Header="Prezzo" Binding="{Binding PriceDisplay}" Width="70" />
|
|
||||||
<DataGridTextColumn Header="Clicks" Binding="{Binding MyClicks}" Width="60" />
|
|
||||||
<DataGridTextColumn Header="Resets" Binding="{Binding ResetCount}" Width="60" />
|
|
||||||
<DataGridTextColumn Header="Ultimo" Binding="{Binding LastBidder}" Width="*" />
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- GridSplitter verticale (aumentato) -->
|
|
||||||
<GridSplitter Grid.Row="1" Height="12" HorizontalAlignment="Stretch" Background="#1f2937" ShowsPreview="True" ResizeDirection="Rows" Cursor="SizeNS" Margin="0,2,0,2" />
|
|
||||||
|
|
||||||
<!-- Dettagli Asta Selezionata -->
|
|
||||||
<Border Grid.Row="2" Background="#0F1720" CornerRadius="6" Margin="12,8,12,12">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Header con pulsanti -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Impostazioni -->
|
|
||||||
<RowDefinition Height="*" /> <!-- Utenti + Log (espandibile) -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Header Dettagli con Pulsanti Pausa/Riprendi -->
|
|
||||||
<Border Grid.Row="0" Background="#1E293B" Padding="8,6" CornerRadius="6,6,0,0">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Grid.Column="0" x:Name="SelectedAuctionName" Text="Seleziona un'asta per vedere i dettagli" FontWeight="Bold" FontSize="12" Foreground="#E6EDF3" VerticalAlignment="Center" />
|
|
||||||
|
|
||||||
<!-- ⭐ NUOVO: Due pulsanti separati -->
|
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
|
||||||
<Button x:Name="PauseAuctionButton" Content="Pausa" Click="PauseAuctionButton_Click"
|
|
||||||
Background="#F59E0B" Foreground="White" Padding="12,4" BorderThickness="0"
|
|
||||||
FontSize="11" FontWeight="SemiBold" MinWidth="65" Height="28" IsEnabled="False">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="4" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button x:Name="ResumeAuctionButton" Content="Riprendi" Click="ResumeAuctionButton_Click"
|
|
||||||
Background="#16A34A" Foreground="White" Padding="12,4" BorderThickness="0"
|
|
||||||
FontSize="11" FontWeight="SemiBold" MinWidth="65" Height="28" IsEnabled="False" Margin="4,0,0,0">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="4" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Impostazioni Asta Selezionata -->
|
|
||||||
<Grid Grid.Row="1" Margin="8,8,8,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="4" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="4" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="0">
|
|
||||||
<TextBlock Text="Timer Click" FontSize="10" Foreground="#94A3B8" />
|
|
||||||
<TextBox x:Name="SelectedTimerClick" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" TextChanged="SelectedTimerClick_TextChanged" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="2">
|
|
||||||
<TextBlock Text="Min €" FontSize="10" Foreground="#94A3B8" />
|
|
||||||
<TextBox x:Name="SelectedMinPrice" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" TextChanged="SelectedMinPrice_TextChanged" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="4">
|
|
||||||
<TextBlock Text="Max €" FontSize="10" Foreground="#94A3B8" />
|
|
||||||
<TextBox x:Name="SelectedMaxPrice" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" TextChanged="SelectedMaxPrice_TextChanged" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Bidders e Log Asta Selezionata (Separati Verticalmente con GridSplitter) -->
|
<!-- Nome Asta -->
|
||||||
<Grid Grid.Row="2" Margin="8,8,12,8">
|
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||||
<Grid.RowDefinitions>
|
<StackPanel>
|
||||||
<RowDefinition Height="*" MinHeight="80" /> <!-- Utenti (espandibile) -->
|
<TextBlock x:Name="SelectedAuctionName" Text="Seleziona un'asta dalla griglia"
|
||||||
<RowDefinition Height="6" /> <!-- Splitter verticale -->
|
FontSize="12" FontWeight="SemiBold" Foreground="#FFFFFF" TextWrapping="Wrap" Margin="0,0,0,16" />
|
||||||
<RowDefinition Height="*" MinHeight="80" /> <!-- Log (espandibile) -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Sezione Utenti (sopra) -->
|
<!-- Link asta e pulsanti -->
|
||||||
<Grid Grid.Row="0">
|
<Grid Margin="0,0,0,12">
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Header Utenti -->
|
|
||||||
<Grid Grid.Row="0" Margin="0,0,0,4">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock Grid.Column="0" Text="Utenti su questa asta" FontSize="11" Foreground="#94A3B8" VerticalAlignment="Center" />
|
<TextBox x:Name="SelectedAuctionUrl" Text="" IsReadOnly="True" MinWidth="220" Margin="0,0,8,0" VerticalAlignment="Center" Background="#181818" Foreground="#00CCFF" BorderBrush="#333" BorderThickness="1" FontSize="11" Grid.Column="0" HorizontalAlignment="Stretch" />
|
||||||
<TextBlock x:Name="SelectedAuctionBiddersCount" Grid.Column="1" Text="0" FontSize="11" FontWeight="Bold" Foreground="#10B981" VerticalAlignment="Center" />
|
<Button Content="Apri" x:Name="OpenAuctionButton" Click="OpenAuctionButton_Click" Style="{StaticResource SmallButtonStyle}" Background="#0099FF" Padding="10,6" Margin="0,0,4,0" Height="28" MinWidth="60" FontSize="11" Grid.Column="1" />
|
||||||
|
<Button Content="Copia" x:Name="CopyAuctionUrlButton" Click="CopyAuctionUrlButton_Click" Style="{StaticResource SmallButtonStyle}" Background="#666" Padding="10,6" Height="28" MinWidth="60" FontSize="11" Grid.Column="2" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- DataGrid Utenti Asta -->
|
<UniformGrid Columns="2" Margin="0,0,0,8">
|
||||||
<DataGrid x:Name="SelectedAuctionBiddersGrid" Grid.Row="1" AutoGenerateColumns="False"
|
<StackPanel Margin="0,0,4,0">
|
||||||
HeadersVisibility="Column" CanUserAddRows="False" IsReadOnly="True"
|
<TextBlock Text="Timer (s)" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
Background="#091018" RowBackground="#0B1220"
|
<TextBox x:Name="SelectedTimerClick" Text="0" TextChanged="SelectedTimerClick_TextChanged"
|
||||||
AlternatingRowBackground="#081016" Foreground="#E6EDF3" GridLinesVisibility="None"
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
BorderThickness="0">
|
</StackPanel>
|
||||||
<DataGrid.Resources>
|
<StackPanel Margin="4,0,0,0">
|
||||||
<Style TargetType="DataGridColumnHeader">
|
<TextBlock Text="Delay (ms)" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
<Setter Property="Background" Value="#0F1720" />
|
<TextBox x:Name="SelectedDelayMs" Text="50" TextChanged="SelectedDelayMs_TextChanged"
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
<Setter Property="FontWeight" Value="SemiBold" />
|
</StackPanel>
|
||||||
<Setter Property="Padding" Value="6,4" />
|
</UniformGrid>
|
||||||
<Setter Property="FontSize" Value="10" />
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="DataGridCell">
|
|
||||||
<Setter Property="Foreground" Value="#E6EDF3" />
|
|
||||||
<Setter Property="Background" Value="Transparent" />
|
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
|
||||||
<Setter Property="Padding" Value="6,3" />
|
|
||||||
<Setter Property="FontSize" Value="10" />
|
|
||||||
</Style>
|
|
||||||
<Style TargetType="DataGridRow">
|
|
||||||
<Setter Property="Height" Value="24" />
|
|
||||||
</Style>
|
|
||||||
</DataGrid.Resources>
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn Header="Utente" Binding="{Binding Key}" Width="*" />
|
|
||||||
<DataGridTextColumn Header="Puntate" Binding="{Binding Value}" Width="60" />
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- GridSplitter Verticale (separatore orizzontale) -->
|
<UniformGrid Columns="2" Margin="0,0,0,8">
|
||||||
<GridSplitter Grid.Row="1" Height="6" HorizontalAlignment="Stretch" VerticalAlignment="Center"
|
<StackPanel Margin="0,0,4,0">
|
||||||
Background="#1f2937" ShowsPreview="True" ResizeDirection="Rows" Cursor="SizeNS" />
|
<TextBlock Text="Min EUR" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
|
<TextBox x:Name="SelectedMinPrice" Text="0" TextChanged="SelectedMinPrice_TextChanged"
|
||||||
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="4,0,0,0">
|
||||||
|
<TextBlock Text="Max EUR" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
|
<TextBox x:Name="SelectedMaxPrice" Text="0" TextChanged="SelectedMaxPrice_TextChanged"
|
||||||
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
|
</StackPanel>
|
||||||
|
</UniformGrid>
|
||||||
|
|
||||||
<!-- Sezione Log (sotto) -->
|
<UniformGrid Columns="2" Margin="0,0,0,12">
|
||||||
<Grid Grid.Row="2">
|
<StackPanel Margin="0,0,4,0">
|
||||||
<Grid.RowDefinitions>
|
<TextBlock Text="Min Resets" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
<RowDefinition Height="Auto" />
|
<TextBox x:Name="SelectedMinResets" Text="0" TextChanged="SelectedMinResets_TextChanged"
|
||||||
<RowDefinition Height="*" />
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
</Grid.RowDefinitions>
|
</StackPanel>
|
||||||
|
<StackPanel Margin="4,0,0,0">
|
||||||
|
<TextBlock Text="Max Resets (0=inf)" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
|
<TextBox x:Name="SelectedMaxResets" Text="0" TextChanged="SelectedMaxResets_TextChanged"
|
||||||
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
|
</StackPanel>
|
||||||
|
</UniformGrid>
|
||||||
|
|
||||||
<!-- Header Log -->
|
<UniformGrid Columns="2" Margin="0,0,0,12">
|
||||||
<TextBlock Grid.Row="0" Text="Log asta" FontSize="11" Foreground="#94A3B8" Margin="0,0,0,4" />
|
<StackPanel Margin="0,0,4,0">
|
||||||
|
<TextBlock Text="Max Clicks (0=inf)" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
|
<TextBox x:Name="SelectedMaxClicks" Text="0" TextChanged="SelectedMaxClicks_TextChanged"
|
||||||
|
Background="#1a1a1a" Foreground="#FFF" Padding="8" FontSize="12" BorderBrush="#444" BorderThickness="1" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Margin="4,0,0,0">
|
||||||
|
<TextBlock Text="(Opzionale)" FontSize="10" Margin="0,0,0,4" Foreground="#999" />
|
||||||
|
<TextBlock Text="Limita il numero di puntate del bot per questa asta" FontSize="10" Foreground="#AAA" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</UniformGrid>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
<!-- TextBox Log -->
|
<!-- Reset Button -->
|
||||||
<TextBox x:Name="SelectedAuctionLog" Grid.Row="1" IsReadOnly="True"
|
<Button Grid.Row="2" x:Name="ResetSettingsButton" Content="Reset Impostazioni" Click="ResetSettingsButton_Click"
|
||||||
VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True"
|
Style="{StaticResource SmallButtonStyle}" IsEnabled="False"
|
||||||
Style="{StaticResource LogBoxStyle}" FontSize="10" />
|
Background="#666" Padding="10,8" Height="32" FontSize="11" Margin="0,8,0,0" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Border>
|
||||||
|
|
||||||
|
<GridSplitter Grid.Column="1" Width="4" HorizontalAlignment="Stretch" Background="#333333" />
|
||||||
|
|
||||||
|
<!-- PANNELLO 2: Utenti -->
|
||||||
|
<Border Grid.Column="2" Background="#0f0f0f" Padding="12" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
|
||||||
|
<TextBlock Text="Utenti: " FontSize="13" FontWeight="Bold" Foreground="#00CC66" />
|
||||||
|
<TextBlock x:Name="SelectedAuctionBiddersCount" Text="0" FontWeight="Bold" Foreground="#FFF" FontSize="13" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<DataGrid x:Name="SelectedAuctionBiddersGrid" Grid.Row="1" AutoGenerateColumns="False"
|
||||||
|
Background="#1a1a1a" Foreground="#FFFFFF" BorderBrush="#333333" BorderThickness="1"
|
||||||
|
GridLinesVisibility="Horizontal" HorizontalGridLinesBrush="#333333"
|
||||||
|
RowBackground="#1a1a1a" AlternatingRowBackground="#222222"
|
||||||
|
IsReadOnly="True" SelectionMode="Single">
|
||||||
|
<DataGrid.Resources>
|
||||||
|
<Style TargetType="DataGridColumnHeader">
|
||||||
|
<Setter Property="Background" Value="#2a2a2a" />
|
||||||
|
<Setter Property="Foreground" Value="#FFFFFF" />
|
||||||
|
<Setter Property="FontWeight" Value="Bold" />
|
||||||
|
<Setter Property="Padding" Value="8,6" />
|
||||||
|
<Setter Property="BorderThickness" Value="0,0,0,2" />
|
||||||
|
<Setter Property="BorderBrush" Value="#00CC66" />
|
||||||
|
<Setter Property="FontSize" Value="11" />
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<Setter Property="Height" Value="28" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsSelected" Value="True">
|
||||||
|
<Setter Property="Background" Value="#0099FF" />
|
||||||
|
<Setter Property="Foreground" Value="White" />
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
<Style TargetType="DataGridCell">
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Padding" Value="8,4" />
|
||||||
|
<Setter Property="FontSize" Value="11" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.Resources>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Utente" Binding="{Binding Username}" Width="*" />
|
||||||
|
<DataGridTextColumn Header="Punt." Binding="{Binding BidCount}" Width="50" />
|
||||||
|
<DataGridTextColumn Header="Ultima" Binding="{Binding LastBidTimeDisplay}" Width="60" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
<Button Grid.Row="2" x:Name="ClearBiddersButton" Content="Pulisci" Click="ClearBiddersButton_Click"
|
||||||
|
Style="{StaticResource SmallButtonStyle}" IsEnabled="False"
|
||||||
|
Background="#666" Padding="10,8" Height="32" FontSize="11" Margin="0,8,0,0" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<GridSplitter Grid.Column="3" Width="4" HorizontalAlignment="Stretch" Background="#333333" />
|
||||||
|
|
||||||
|
<!-- PANNELLO 3: Log Asta -->
|
||||||
|
<Border Grid.Column="4" Background="#0f0f0f" Padding="12" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Text="Log Asta" FontSize="13" FontWeight="Bold" Foreground="#00CC66" Margin="0,0,0,10" />
|
||||||
|
|
||||||
|
<RichTextBox x:Name="SelectedAuctionLog" Grid.Row="1" IsReadOnly="True"
|
||||||
|
VerticalScrollBarVisibility="Auto" Background="#1a1a1a" Foreground="#CCC"
|
||||||
|
Padding="8" FontSize="10" FontFamily="Consolas" BorderBrush="#333333" BorderThickness="1" />
|
||||||
|
|
||||||
|
<Button Grid.Row="2" x:Name="ClearLogButton" Content="Pulisci Log" Click="ClearLogButton_Click"
|
||||||
|
Style="{StaticResource SmallButtonStyle}" IsEnabled="False"
|
||||||
|
Background="#666" Padding="10,8" Height="32" FontSize="11" Margin="0,8,0,0" HorizontalAlignment="Stretch" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- GridSplitter to allow resizing the left panel (only width) -->
|
|
||||||
<GridSplitter Grid.Column="1" Width="6" HorizontalAlignment="Center" VerticalAlignment="Stretch" Background="#1f2937" ShowsPreview="True" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext" Cursor="SizeWE" />
|
|
||||||
|
|
||||||
<!-- Right: webview with address bar -->
|
|
||||||
<Grid Grid.Column="2">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- Address bar con pulsanti navigazione -->
|
|
||||||
<Grid Grid.Row="0" Margin="12,12,12,6">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<!-- Pulsante Indietro -->
|
|
||||||
<Button x:Name="BackButton" Grid.Column="0" Content="Indietro" Click="BackButton_Click"
|
|
||||||
Background="#374151" Foreground="White" Padding="12,8" Margin="0,0,6,0"
|
|
||||||
BorderThickness="0" FontWeight="SemiBold" FontSize="13" MinWidth="70" Height="38" IsEnabled="False">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="6" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- Pulsante Aggiorna -->
|
|
||||||
<Button x:Name="RefreshButton" Grid.Column="1" Content="Aggiorna" Click="RefreshButton_Click"
|
|
||||||
Background="#0EA5E9" Foreground="White" Padding="12,8" Margin="0,0,8,0"
|
|
||||||
BorderThickness="0" FontWeight="SemiBold" FontSize="13" MinWidth="80" Height="38">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="6" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- Barra indirizzo -->
|
|
||||||
<TextBox x:Name="AddressBar" Grid.Column="2" Style="{StaticResource AddressBarStyle}"
|
|
||||||
Text="https://it.bidoo.com" KeyDown="AddressBar_KeyDown"
|
|
||||||
ToolTip="Inserisci URL di Bidoo (es: https://it.bidoo.com/asta/...)" />
|
|
||||||
|
|
||||||
<!-- Pulsante Vai -->
|
|
||||||
<Button x:Name="NavigateButton" Grid.Column="3" Content="Vai" Click="NavigateButton_Click"
|
|
||||||
Background="#16A34A" Foreground="White" Padding="28,10" Margin="8,0,0,0"
|
|
||||||
BorderThickness="0" FontWeight="Bold" FontSize="14" MinWidth="80" Height="38">
|
|
||||||
<Button.Template>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="{TemplateBinding Background}" CornerRadius="6" SnapsToDevicePixels="True">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Button.Template>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- WebView -->
|
|
||||||
<Border Grid.Row="1" Margin="12,0,12,12" CornerRadius="8" Background="#0B1015">
|
|
||||||
<wv2:WebView2 x:Name="webView" Source="https://it.bidoo.com" Margin="2" />
|
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Window>
|
||||||
</Window>
|
|
||||||
|
|||||||
+1006
-1952
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Informazioni base di un'asta monitorata
|
||||||
|
/// </summary>
|
||||||
|
public class AuctionInfo
|
||||||
|
{
|
||||||
|
public string AuctionId { get; set; } = "";
|
||||||
|
public string Name { get; set; } = ""; // Opzionale, può essere lasciato vuoto
|
||||||
|
public string OriginalUrl { get; set; } = ""; // URL completo dell'asta (per referer)
|
||||||
|
|
||||||
|
// Configurazione asta
|
||||||
|
public int TimerClick { get; set; } = 0; // Secondo del timer per click (default 0)
|
||||||
|
public int DelayMs { get; set; } = 50; // Ritardo aggiuntivo in ms (per compensare latenza)
|
||||||
|
public double MinPrice { get; set; } = 0;
|
||||||
|
public double MaxPrice { get; set; } = 0;
|
||||||
|
public int MinResets { get; set; } = 0; // Numero minimo reset prima di puntare
|
||||||
|
public int MaxResets { get; set; } = 0; // Numero massimo reset (0 = illimitati)
|
||||||
|
// Numero massimo di click/puntate che il bot può eseguire per questa asta (0 = illimitato)
|
||||||
|
public int MaxClicks { get; set; } = 0;
|
||||||
|
|
||||||
|
// Stato asta
|
||||||
|
public bool IsActive { get; set; } = true;
|
||||||
|
public bool IsPaused { get; set; } = false;
|
||||||
|
|
||||||
|
// Contatori
|
||||||
|
public int MyClicks { get; set; } = 0;
|
||||||
|
public int ResetCount { get; set; } = 0;
|
||||||
|
|
||||||
|
// Timestamp
|
||||||
|
public DateTime AddedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime? LastClickAt { get; set; }
|
||||||
|
|
||||||
|
// Storico
|
||||||
|
public List<BidHistory> BidHistory { get; set; } = new();
|
||||||
|
public Dictionary<string, BidderInfo> BidderStats { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// Legacy (deprecato, usa BidderStats)
|
||||||
|
[System.Text.Json.Serialization.JsonIgnore]
|
||||||
|
public Dictionary<string, int> Bidders { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// Log per-asta (non serializzato)
|
||||||
|
[System.Text.Json.Serialization.JsonIgnore]
|
||||||
|
public List<string> AuctionLog { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiunge una voce al log dell'asta
|
||||||
|
/// </summary>
|
||||||
|
public void AddLog(string message)
|
||||||
|
{
|
||||||
|
var entry = $"{DateTime.Now:HH:mm:ss} - {message}";
|
||||||
|
AuctionLog.Add(entry);
|
||||||
|
|
||||||
|
// Mantieni solo ultimi 100 log
|
||||||
|
if (AuctionLog.Count > 100)
|
||||||
|
{
|
||||||
|
AuctionLog.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stato real-time di un'asta (snapshot dal polling HTTP)
|
||||||
|
/// </summary>
|
||||||
|
public class AuctionState
|
||||||
|
{
|
||||||
|
public string AuctionId { get; set; } = "";
|
||||||
|
|
||||||
|
// Dati correnti
|
||||||
|
public double Timer { get; set; } = 999;
|
||||||
|
public double Price { get; set; } = 0;
|
||||||
|
public string LastBidder { get; set; } = "";
|
||||||
|
public bool IsMyBid { get; set; } = false;
|
||||||
|
|
||||||
|
// Stato asta
|
||||||
|
public AuctionStatus Status { get; set; } = AuctionStatus.Unknown;
|
||||||
|
public string StartTime { get; set; } = ""; // Es: "Oggi alle 17:00" o "23 Ottobre 10:10"
|
||||||
|
|
||||||
|
// Timestamp snapshot
|
||||||
|
public DateTime SnapshotTime { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// Latenza polling
|
||||||
|
public int PollingLatencyMs { get; set; } = 0;
|
||||||
|
|
||||||
|
// Dati estratti HTML
|
||||||
|
public string RawHtml { get; set; } = "";
|
||||||
|
public bool ParsingSuccess { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stato corrente dell'asta
|
||||||
|
/// </summary>
|
||||||
|
public enum AuctionStatus
|
||||||
|
{
|
||||||
|
Unknown, // Non determinato
|
||||||
|
Running, // Asta in corso (ON + timer attivo + utenti presenti)
|
||||||
|
Paused, // Asta in pausa (STOP nelle API - tipicamente 00:00-10:00)
|
||||||
|
EndedWon, // Asta terminata - HAI VINTO! (OFF + io sono last bidder)
|
||||||
|
EndedLost, // Asta terminata - Persa (OFF + altro è last bidder)
|
||||||
|
Pending, // In attesa di inizio (ON + no bidder + expiry < 30min)
|
||||||
|
Scheduled, // Programmata per più tardi (ON + no bidder + expiry > 30min)
|
||||||
|
Closed, // Asta chiusa/terminata (generico)
|
||||||
|
NotStarted // Non ancora iniziata (legacy)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Statistiche aggregate di un'asta per dashboard e export
|
||||||
|
/// </summary>
|
||||||
|
public class AuctionStatistics
|
||||||
|
{
|
||||||
|
public string AuctionId { get; set; } = "";
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
|
||||||
|
// Tempo monitoraggio
|
||||||
|
public DateTime MonitoringStarted { get; set; }
|
||||||
|
public TimeSpan MonitoringDuration { get; set; }
|
||||||
|
|
||||||
|
// Contatori
|
||||||
|
public int TotalBids { get; set; }
|
||||||
|
public int MyBids { get; set; }
|
||||||
|
public int OpponentBids { get; set; }
|
||||||
|
public int Resets { get; set; }
|
||||||
|
public int UniqueBidders { get; set; }
|
||||||
|
|
||||||
|
// Prezzi
|
||||||
|
public double StartPrice { get; set; }
|
||||||
|
public double CurrentPrice { get; set; }
|
||||||
|
public double MinPrice { get; set; }
|
||||||
|
public double MaxPrice { get; set; }
|
||||||
|
public double AvgPrice { get; set; }
|
||||||
|
|
||||||
|
// Timer
|
||||||
|
public double AvgTimerAtBid { get; set; }
|
||||||
|
public double MinTimerReached { get; set; }
|
||||||
|
|
||||||
|
// Latenza
|
||||||
|
public int AvgPollingLatencyMs { get; set; }
|
||||||
|
public int AvgClickLatencyMs { get; set; }
|
||||||
|
public int MinClickLatencyMs { get; set; }
|
||||||
|
public int MaxClickLatencyMs { get; set; }
|
||||||
|
|
||||||
|
// Rate
|
||||||
|
public double BidsPerMinute { get; set; }
|
||||||
|
public double ResetsPerHour { get; set; }
|
||||||
|
|
||||||
|
// Competitor analysis
|
||||||
|
public string MostActiveBidder { get; set; } = "";
|
||||||
|
public int MostActiveBidderCount { get; set; }
|
||||||
|
public Dictionary<string, int> BidderRanking { get; set; } = new();
|
||||||
|
|
||||||
|
// Success rate
|
||||||
|
public double MyBidSuccessRate { get; set; } // % mie puntate sul totale
|
||||||
|
|
||||||
|
// Calcola statistiche da BidHistory
|
||||||
|
public static AuctionStatistics Calculate(AuctionInfo auction)
|
||||||
|
{
|
||||||
|
var stats = new AuctionStatistics
|
||||||
|
{
|
||||||
|
AuctionId = auction.AuctionId,
|
||||||
|
Name = auction.Name,
|
||||||
|
MonitoringStarted = auction.AddedAt,
|
||||||
|
MonitoringDuration = DateTime.UtcNow - auction.AddedAt,
|
||||||
|
MyBids = auction.MyClicks,
|
||||||
|
Resets = auction.ResetCount,
|
||||||
|
UniqueBidders = auction.Bidders.Count,
|
||||||
|
BidderRanking = auction.Bidders
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auction.BidHistory.Any())
|
||||||
|
{
|
||||||
|
var prices = auction.BidHistory.Select(h => h.Price).Where(p => p > 0).ToList();
|
||||||
|
if (prices.Any())
|
||||||
|
{
|
||||||
|
stats.StartPrice = prices.First();
|
||||||
|
stats.CurrentPrice = prices.Last();
|
||||||
|
stats.MinPrice = prices.Min();
|
||||||
|
stats.MaxPrice = prices.Max();
|
||||||
|
stats.AvgPrice = prices.Average();
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.TotalBids = auction.BidHistory.Count(h => h.EventType == BidEventType.MyBid || h.EventType == BidEventType.OpponentBid);
|
||||||
|
stats.OpponentBids = stats.TotalBids - stats.MyBids;
|
||||||
|
|
||||||
|
var timers = auction.BidHistory.Select(h => h.Timer).ToList();
|
||||||
|
if (timers.Any())
|
||||||
|
{
|
||||||
|
stats.AvgTimerAtBid = timers.Average();
|
||||||
|
stats.MinTimerReached = timers.Min();
|
||||||
|
}
|
||||||
|
|
||||||
|
var latencies = auction.BidHistory.Where(h => h.EventType == BidEventType.MyBid).Select(h => h.LatencyMs).ToList();
|
||||||
|
if (latencies.Any())
|
||||||
|
{
|
||||||
|
stats.AvgClickLatencyMs = (int)latencies.Average();
|
||||||
|
stats.MinClickLatencyMs = latencies.Min();
|
||||||
|
stats.MaxClickLatencyMs = latencies.Max();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.MonitoringDuration.TotalMinutes > 0)
|
||||||
|
{
|
||||||
|
stats.BidsPerMinute = stats.TotalBids / stats.MonitoringDuration.TotalMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.MonitoringDuration.TotalHours > 0)
|
||||||
|
{
|
||||||
|
stats.ResetsPerHour = stats.Resets / stats.MonitoringDuration.TotalHours;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.TotalBids > 0)
|
||||||
|
{
|
||||||
|
stats.MyBidSuccessRate = (double)stats.MyBids / stats.TotalBids * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auction.Bidders.Any())
|
||||||
|
{
|
||||||
|
var topBidder = auction.Bidders.OrderByDescending(b => b.Value).First();
|
||||||
|
stats.MostActiveBidder = topBidder.Key;
|
||||||
|
stats.MostActiveBidderCount = topBidder.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entry storico per ogni puntata/evento dell'asta
|
||||||
|
/// </summary>
|
||||||
|
public class BidHistory
|
||||||
|
{
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public BidEventType EventType { get; set; }
|
||||||
|
public string Bidder { get; set; } = "";
|
||||||
|
public double Price { get; set; }
|
||||||
|
public double Timer { get; set; }
|
||||||
|
public int LatencyMs { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string Notes { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BidEventType
|
||||||
|
{
|
||||||
|
MyBid, // Mia puntata
|
||||||
|
OpponentBid, // Puntata avversario
|
||||||
|
Reset, // Reset timer
|
||||||
|
PriceChange, // Cambio prezzo
|
||||||
|
AuctionStarted, // Asta iniziata
|
||||||
|
AuctionEnded // Asta terminata
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Risultato di un tentativo di puntata API
|
||||||
|
/// </summary>
|
||||||
|
public class BidResult
|
||||||
|
{
|
||||||
|
public string AuctionId { get; set; } = "";
|
||||||
|
public DateTime Timestamp { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public int LatencyMs { get; set; }
|
||||||
|
public string Response { get; set; } = "";
|
||||||
|
public string Error { get; set; } = "";
|
||||||
|
public double NewPrice { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Informazioni su un utente che ha piazzato puntate
|
||||||
|
/// </summary>
|
||||||
|
public class BidderInfo
|
||||||
|
{
|
||||||
|
public string Username { get; set; } = "";
|
||||||
|
public int BidCount { get; set; } = 0;
|
||||||
|
public DateTime LastBidTime { get; set; } = DateTime.MinValue;
|
||||||
|
|
||||||
|
public string LastBidTimeDisplay => LastBidTime == DateTime.MinValue
|
||||||
|
? "-"
|
||||||
|
: LastBidTime.ToString("HH:mm:ss");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AutoBidder.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sessione Bidoo con token di autenticazione
|
||||||
|
/// </summary>
|
||||||
|
public class BidooSession
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Token di autenticazione (estratto da cookie o header)
|
||||||
|
/// Usato per autenticare tutte le chiamate API
|
||||||
|
/// </summary>
|
||||||
|
public string AuthToken { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cookie string completa (opzionale, backup)
|
||||||
|
/// Formato: "cookie1=value1; cookie2=value2; ..."
|
||||||
|
/// </summary>
|
||||||
|
public string CookieString { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Username estratto dalla sessione
|
||||||
|
/// </summary>
|
||||||
|
public string Username { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Puntate rimanenti sull'account
|
||||||
|
/// </summary>
|
||||||
|
public int RemainingBids { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timestamp ultimo aggiornamento info account
|
||||||
|
/// </summary>
|
||||||
|
public DateTime LastAccountUpdate { get; set; } = DateTime.MinValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag sessione valida
|
||||||
|
/// </summary>
|
||||||
|
public bool IsValid => !string.IsNullOrWhiteSpace(AuthToken) || !string.IsNullOrWhiteSpace(CookieString);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSRF Token per puntate (estratto da pagina, opzionale)
|
||||||
|
/// </summary>
|
||||||
|
public string? CsrfToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,417 +0,0 @@
|
|||||||
# ? Implementazione Multi-Asta - Riepilogo Finale
|
|
||||||
|
|
||||||
## ?? Implementazione Completata con Successo!
|
|
||||||
|
|
||||||
Tutte le modifiche richieste sono state implementate e testate. Il sistema è pronto per l'uso.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Cosa è Stato Fatto
|
|
||||||
|
|
||||||
### 1. ? Nuova Modalità Multi-Asta
|
|
||||||
- **Modalità operativa aggiuntiva** che monitora tutte le aste nei preferiti
|
|
||||||
- **Selezione intelligente** dell'asta più vicina al momento del click
|
|
||||||
- **Ottimizzazione risorse** usando una sola WebView invece di finestre multiple
|
|
||||||
- **Gestione automatica** di tutte le funzionalità (reset, bidder, limiti)
|
|
||||||
|
|
||||||
### 2. ?? Interfaccia Utente Aggiornata
|
|
||||||
- Pulsanti di selezione modalità: `[Asta Singola]` / `[Multi-Asta]`
|
|
||||||
- Pannello "Asta Attiva" (visibile solo in Multi-Asta)
|
|
||||||
- Contatore "Aste monitorate"
|
|
||||||
- Indicatori visuali per modalità selezionata
|
|
||||||
|
|
||||||
### 3. ?? Funzionalità Principali Multi-Asta
|
|
||||||
|
|
||||||
#### Scansione Automatica
|
|
||||||
- Rileva tutte le aste nella pagina preferiti (`https://it.bidoo.com/?tab=FAV`)
|
|
||||||
- Estrae metadati: ID, nome, elementi DOM (prezzo, timer, bidder, pulsante)
|
|
||||||
- Aggiorna lista ogni 5 secondi
|
|
||||||
|
|
||||||
#### Selezione Prioritaria
|
|
||||||
```
|
|
||||||
Algoritmo:
|
|
||||||
1. Leggi timer di TUTTE le aste
|
|
||||||
2. Filtra per limiti prezzo (se impostati)
|
|
||||||
3. Seleziona asta con timer più basso
|
|
||||||
4. Clicca quando timer nel range configurato
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Gestione Intelligente
|
|
||||||
- **Reset detection** per ogni asta singolarmente
|
|
||||||
- **Bidder tracking** per asta specifica
|
|
||||||
- **Limiti globali** (Max Clicks, Max Resets, Min/Max Price)
|
|
||||||
- **Log dettagliato** con nome asta per ogni evento
|
|
||||||
|
|
||||||
### 4. ?? Modifiche Tecniche
|
|
||||||
|
|
||||||
#### File Modificati
|
|
||||||
- **`MainWindow.xaml`**: Layout aggiornato con nuovi controlli
|
|
||||||
- **`MainWindow.xaml.cs`**: Logica multi-asta implementata
|
|
||||||
|
|
||||||
#### Nuovi Metodi
|
|
||||||
- `MultiAuctionLoop()` - Loop principale multi-asta
|
|
||||||
- `ScanFavoriteAuctions()` - Scansiona preferiti
|
|
||||||
- `ReadAllAuctionStates()` - Legge stati aste
|
|
||||||
- `PerformMultiAuctionClick()` - Click su asta specifica
|
|
||||||
- `SingleAuctionButton_Click()` / `MultiAuctionButton_Click()`
|
|
||||||
- `UpdateModeButtons()` / `UpdateActiveAuctionDisplay()`
|
|
||||||
|
|
||||||
#### Nuove Classi
|
|
||||||
```csharp
|
|
||||||
class AuctionInfo {
|
|
||||||
// Metadati permanenti asta
|
|
||||||
string AuctionId, Name
|
|
||||||
string PriceElementId, TimerElementId,
|
|
||||||
BidderElementId, ButtonId
|
|
||||||
double LastKnownTimer
|
|
||||||
string LastKnownBidder
|
|
||||||
}
|
|
||||||
|
|
||||||
class AuctionState {
|
|
||||||
// Snapshot temporaneo stato asta
|
|
||||||
string AuctionId, Name
|
|
||||||
string? Price, Bidder
|
|
||||||
double Timer
|
|
||||||
string LastKnownBidder
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. ?? Documentazione Completa
|
|
||||||
|
|
||||||
#### File Creati
|
|
||||||
1. **`README.md`** (11.5 KB)
|
|
||||||
- Documentazione completa progetto
|
|
||||||
- Guide per entrambe le modalità
|
|
||||||
- FAQ e troubleshooting
|
|
||||||
- Strategie vincenti
|
|
||||||
|
|
||||||
2. **`MULTI_AUCTION_GUIDE.md`** (6.5 KB)
|
|
||||||
- Guida dettagliata Multi-Asta
|
|
||||||
- Tutorial passo-passo
|
|
||||||
- Spiegazione algoritmo
|
|
||||||
- Best practices
|
|
||||||
|
|
||||||
3. **`QUICK_REFERENCE.md`** (6.8 KB)
|
|
||||||
- Carta di riferimento rapido
|
|
||||||
- Tabelle impostazioni
|
|
||||||
- Scorciatoie e tips
|
|
||||||
- Troubleshooting rapido
|
|
||||||
|
|
||||||
4. **`IMPLEMENTATION_SUMMARY.md`** (16 KB)
|
|
||||||
- Riepilogo tecnico completo
|
|
||||||
- Diagrammi flusso
|
|
||||||
- Dettagli architettura
|
|
||||||
- Script JavaScript usati
|
|
||||||
|
|
||||||
5. **`CHANGELOG.md`** (7.4 KB)
|
|
||||||
- Cronologia modifiche
|
|
||||||
- Note versione 2.0
|
|
||||||
- Roadmap futura
|
|
||||||
|
|
||||||
6. **`PROJECT_SUMMARY.md`** (questo file)
|
|
||||||
- Riepilogo finale
|
|
||||||
- Istruzioni utilizzo
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Usare la Nuova Funzionalità
|
|
||||||
|
|
||||||
### Modalità Asta Singola (Come Prima)
|
|
||||||
1. Naviga all'asta su Bidoo
|
|
||||||
2. Configura parametri
|
|
||||||
3. Clicca **[Avvia]**
|
|
||||||
4. ? Funziona esattamente come prima
|
|
||||||
|
|
||||||
### Modalità Multi-Asta (NUOVO!)
|
|
||||||
|
|
||||||
#### Setup Iniziale
|
|
||||||
1. **Accedi a Bidoo** tramite AutoBidder
|
|
||||||
2. **Aggiungi aste ai Preferiti**:
|
|
||||||
- Naviga alle aste desiderate
|
|
||||||
- Clicca sulla stella ? per aggiungere ai preferiti
|
|
||||||
3. **Torna su AutoBidder**
|
|
||||||
|
|
||||||
#### Attivazione
|
|
||||||
1. Clicca **[Multi-Asta]** nel pannello sinistro
|
|
||||||
- Il pulsante diventerà verde
|
|
||||||
- AutoBidder naviga automaticamente a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
- Il pannello "Asta Attiva" apparirà
|
|
||||||
|
|
||||||
2. **Configura parametri** (come al solito):
|
|
||||||
- Timer Click (es: 0 o 1)
|
|
||||||
- Ritardo (es: 0-50ms)
|
|
||||||
- Max Clicks (es: 100)
|
|
||||||
- Min/Max Price (opzionale)
|
|
||||||
|
|
||||||
3. Clicca **[Avvia]**
|
|
||||||
|
|
||||||
#### Cosa Succede
|
|
||||||
- ? AutoBidder scansiona tutti i preferiti ogni 5s
|
|
||||||
- ? Legge timer di ogni asta in tempo reale
|
|
||||||
- ? Seleziona automaticamente l'asta più vicina al click
|
|
||||||
- ? Punta sull'asta prioritaria al momento giusto
|
|
||||||
- ? Dopo il click, ri-valuta e passa alla prossima asta urgente
|
|
||||||
|
|
||||||
#### Esempio Pratico
|
|
||||||
```
|
|
||||||
Preferiti:
|
|
||||||
?? Galaxy S25 512GB (Timer: 8.3s) ? Aspetta
|
|
||||||
?? RTX 5080 (Timer: 1.2s) ? PUNTA! ?
|
|
||||||
?? MacBook Pro (Timer: 5.7s) ? Aspetta
|
|
||||||
|
|
||||||
AutoBidder:
|
|
||||||
? Focus su "RTX 5080"
|
|
||||||
? Click quando timer = 0-1s (basato su config)
|
|
||||||
? Dopo click, ri-scansiona
|
|
||||||
? Focus passa a "MacBook Pro" (ora timer più basso)
|
|
||||||
? E così via...
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Configurazioni Consigliate
|
|
||||||
|
|
||||||
### Multi-Asta Aggressiva (Max Vincite)
|
|
||||||
```
|
|
||||||
Modalità: Multi-Asta
|
|
||||||
Timer Click: 0
|
|
||||||
Ritardo: 0ms
|
|
||||||
Multi-Click: ? Attivo
|
|
||||||
Max Clicks: 150-200
|
|
||||||
Min Price: 5€
|
|
||||||
Max Price: 100€
|
|
||||||
Preferiti: 5-10 aste
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multi-Asta Conservativa (Risparmio Click)
|
|
||||||
```
|
|
||||||
Modalità: Multi-Asta
|
|
||||||
Timer Click: 1
|
|
||||||
Ritardo: 100ms
|
|
||||||
Multi-Click: ? Disattivo
|
|
||||||
Max Clicks: 50
|
|
||||||
Min Price: 10€
|
|
||||||
Max Price: 50€
|
|
||||||
Preferiti: 3-5 aste
|
|
||||||
```
|
|
||||||
|
|
||||||
### Asta Singola Velocissima
|
|
||||||
```
|
|
||||||
Modalità: Asta Singola
|
|
||||||
Timer Click: 0
|
|
||||||
Ritardo: 0ms
|
|
||||||
Multi-Click: ? Attivo
|
|
||||||
Max Clicks: 100
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Vantaggi Multi-Asta
|
|
||||||
|
|
||||||
### Rispetto a Finestre Multiple
|
|
||||||
- **?? Memoria**: Risparmio ~70% (150MB vs 500MB+)
|
|
||||||
- **? CPU**: Risparmio ~60% (8-12% vs 20-40%)
|
|
||||||
- **?? Gestione**: Automatica invece di manuale
|
|
||||||
- **?? Efficienza**: Una configurazione per tutte le aste
|
|
||||||
|
|
||||||
### Rispetto a Modalità Singola
|
|
||||||
- **?? Opportunità**: Monitora N aste invece di 1
|
|
||||||
- **?? Intelligenza**: Selezione automatica asta urgente
|
|
||||||
- **?? Tempismo**: Click sempre sull'asta più vicina
|
|
||||||
- **?? Filtri**: Min/Max price applicati automaticamente
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Indicatori e Log
|
|
||||||
|
|
||||||
### Pannello "Asta Attiva" (Solo Multi-Asta)
|
|
||||||
```
|
|
||||||
???????????????????????????
|
|
||||||
? Asta Attiva: ?
|
|
||||||
? Galaxy S25 512GB ? ? Nome asta corrente
|
|
||||||
? ?
|
|
||||||
? Aste monitorate: 3 ? ? Totale preferiti
|
|
||||||
???????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
### Log Dettagliato
|
|
||||||
```
|
|
||||||
?? Ricerca aste nei preferiti...
|
|
||||||
? Trovate 3 aste nei preferiti
|
|
||||||
?? Focus su: Galaxy S25 512GB (Timer: 1.8s)
|
|
||||||
?? Puntata di: utente123 su Galaxy S25 512GB
|
|
||||||
? Click #1 (TuoNome) su Galaxy S25 512GB - Timer: 1.50s
|
|
||||||
?? Reset #1 su Galaxy S25 512GB - Winner: utente123
|
|
||||||
?? Focus su: RTX 5080 (Timer: 2.1s)
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Note Importanti
|
|
||||||
|
|
||||||
### Performance Ottimali
|
|
||||||
- **Max 10-15 aste** nei preferiti (raccomandato)
|
|
||||||
- **Ricarica pagina** preferiti ogni 2-3 minuti
|
|
||||||
- **Pulisci log** periodicamente (pulsante [Pulisci])
|
|
||||||
- **Chiudi app pesanti** durante l'uso
|
|
||||||
|
|
||||||
### Limiti e Comportamenti
|
|
||||||
- **Max Clicks**: Globale su tutte le aste
|
|
||||||
- **Max Resets**: Globale, conta reset di qualsiasi asta
|
|
||||||
- **Min/Max Price**: Applicati a ogni asta singolarmente
|
|
||||||
- **Timer Click**: Stesso valore per tutte le aste
|
|
||||||
- **Pausa**: Sospende puntate su TUTTE le aste
|
|
||||||
|
|
||||||
### Modalità Compatibili
|
|
||||||
- ? **Asta Singola**: Funziona esattamente come prima
|
|
||||||
- ? **Multi-Asta**: Nuova, completamente indipendente
|
|
||||||
- ? **Switch**: Puoi passare da una all'altra senza restart
|
|
||||||
- ? **Configurazioni**: Parametri condivisi tra modalità
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Troubleshooting Rapido
|
|
||||||
|
|
||||||
### "Nessuna asta trovata nei preferiti"
|
|
||||||
**Soluzione:**
|
|
||||||
1. Verifica di essere su `https://it.bidoo.com/?tab=FAV`
|
|
||||||
2. Assicurati di aver aggiunto aste ai preferiti (?)
|
|
||||||
3. Ricarica la pagina ([Aggiorna])
|
|
||||||
|
|
||||||
### "AutoBidder non punta in Multi-Asta"
|
|
||||||
**Controlla:**
|
|
||||||
1. **Aste monitorate > 0** (pannello "Asta Attiva")
|
|
||||||
2. **Timer Click** impostato correttamente (0-8)
|
|
||||||
3. **Min/Max Price** non troppo restrittivi
|
|
||||||
4. **Pausa** disattivata (pulsante deve dire "Pausa")
|
|
||||||
5. **Log** per messaggi "Click bloccato"
|
|
||||||
|
|
||||||
### "Performance basse con Multi-Asta"
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Riduci preferiti a 5-10 aste
|
|
||||||
2. Pulisci log (pulsante [Pulisci])
|
|
||||||
3. Chiudi altre applicazioni pesanti
|
|
||||||
4. Riavvia AutoBidder
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Build e Deploy
|
|
||||||
|
|
||||||
### Build Completato ?
|
|
||||||
```
|
|
||||||
? Compilazione senza errori
|
|
||||||
? Nessun warning critico
|
|
||||||
? Tutti i test passati
|
|
||||||
? Documentazione completa
|
|
||||||
```
|
|
||||||
|
|
||||||
### File Deliverables
|
|
||||||
```
|
|
||||||
AutoBidder/
|
|
||||||
??? AutoBidder.exe # Eseguibile principale
|
|
||||||
??? MainWindow.xaml # UI modificata
|
|
||||||
??? MainWindow.xaml.cs # Logica implementata
|
|
||||||
??? README.md # Documentazione principale
|
|
||||||
??? MULTI_AUCTION_GUIDE.md # Guida Multi-Asta
|
|
||||||
??? QUICK_REFERENCE.md # Riferimento rapido
|
|
||||||
??? IMPLEMENTATION_SUMMARY.md # Dettagli tecnici
|
|
||||||
??? CHANGELOG.md # Cronologia modifiche
|
|
||||||
??? PROJECT_SUMMARY.md # Questo file
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Testing Utente
|
|
||||||
1. ? Testa modalità Asta Singola (verifica retrocompatibilità)
|
|
||||||
2. ? Testa modalità Multi-Asta con 2-3 preferiti
|
|
||||||
3. ? Verifica limiti prezzo funzionanti
|
|
||||||
4. ? Controlla tracciamento bidder e reset
|
|
||||||
5. ? Testa performance con 10+ preferiti
|
|
||||||
|
|
||||||
### Raccolta Feedback
|
|
||||||
- Nota eventuali bug o comportamenti inattesi
|
|
||||||
- Suggerisci miglioramenti UI/UX
|
|
||||||
- Proponi nuove funzionalità
|
|
||||||
|
|
||||||
### Versione Futura (v2.1+)
|
|
||||||
- Persistenza configurazioni
|
|
||||||
- Notifiche audio/visive
|
|
||||||
- Statistiche avanzate
|
|
||||||
- Profili salvabili
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Supporto
|
|
||||||
|
|
||||||
### Documentazione
|
|
||||||
- **Panoramica**: `README.md`
|
|
||||||
- **Multi-Asta**: `MULTI_AUCTION_GUIDE.md`
|
|
||||||
- **Riferimento**: `QUICK_REFERENCE.md`
|
|
||||||
- **Tecnico**: `IMPLEMENTATION_SUMMARY.md`
|
|
||||||
|
|
||||||
### In Caso di Problemi
|
|
||||||
1. Consulta `QUICK_REFERENCE.md` per soluzioni rapide
|
|
||||||
2. Controlla `CHANGELOG.md` per bug noti
|
|
||||||
3. Leggi `MULTI_AUCTION_GUIDE.md` per guide dettagliate
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Checklist Finale
|
|
||||||
|
|
||||||
### Implementazione
|
|
||||||
- [x] Modalità Multi-Asta completa
|
|
||||||
- [x] UI aggiornata con selettore
|
|
||||||
- [x] Pannello "Asta Attiva"
|
|
||||||
- [x] Script scansione preferiti
|
|
||||||
- [x] Algoritmo priorità timer
|
|
||||||
- [x] Click specifico per asta
|
|
||||||
- [x] Rilevamento reset per asta
|
|
||||||
- [x] Tracciamento bidder per asta
|
|
||||||
- [x] Limiti globali applicati
|
|
||||||
- [x] Log dettagliato eventi
|
|
||||||
|
|
||||||
### Documentazione
|
|
||||||
- [x] README.md completo
|
|
||||||
- [x] Guida Multi-Asta dettagliata
|
|
||||||
- [x] Quick Reference Card
|
|
||||||
- [x] Implementation Summary
|
|
||||||
- [x] Changelog aggiornato
|
|
||||||
- [x] Project Summary
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- [x] Build senza errori
|
|
||||||
- [x] Compilazione Release OK
|
|
||||||
- [x] Modalità Singola retrocompatibile
|
|
||||||
- [x] Modalità Multi-Asta funzionante
|
|
||||||
- [x] Switch modalità senza restart
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
**L'implementazione della modalità Multi-Asta è completa e funzionante!**
|
|
||||||
|
|
||||||
Il sistema ora supporta:
|
|
||||||
- ? **Asta Singola**: Focus massimo su un prodotto specifico
|
|
||||||
- ? **Multi-Asta**: Monitoraggio intelligente di tutti i preferiti
|
|
||||||
|
|
||||||
Tutte le funzionalità richieste sono state implementate:
|
|
||||||
- ? Scansione automatica preferiti
|
|
||||||
- ? Selezione intelligente asta prioritaria
|
|
||||||
- ? Ottimizzazione risorse (singola WebView)
|
|
||||||
- ? Gestione completa limiti e reset
|
|
||||||
- ? Documentazione esaustiva
|
|
||||||
|
|
||||||
**Il progetto è pronto per l'uso e il testing finale!** ????
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Buone aste e buona fortuna!** ??
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.0 - Multi-Auction Release*
|
|
||||||
*Developed with ?? for better Bidoo automation*
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
# ?? AutoBidder - Quick Reference Card
|
|
||||||
|
|
||||||
## ?? Avvio Rapido
|
|
||||||
|
|
||||||
### Modalità Asta Singola
|
|
||||||
1. Naviga all'asta su Bidoo
|
|
||||||
2. Imposta **Timer Click** (es: 0 o 1)
|
|
||||||
3. Clicca **[Avvia]**
|
|
||||||
4. ? Done!
|
|
||||||
|
|
||||||
### Modalità Multi-Asta
|
|
||||||
1. Aggiungi aste ai **Preferiti** su Bidoo (?)
|
|
||||||
2. Clicca **[Multi-Asta]** in AutoBidder
|
|
||||||
3. Imposta **Timer Click** (es: 0 o 1)
|
|
||||||
4. Clicca **[Avvia]**
|
|
||||||
5. ? AutoBidder gestisce tutto!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Impostazioni Essenziali
|
|
||||||
|
|
||||||
| Parametro | Valore Consigliato | Descrizione |
|
|
||||||
|-----------|-------------------|-------------|
|
|
||||||
| **Timer Click** | 0 o 1 | Secondo del timer per click (0 = max velocità) |
|
|
||||||
| **Ritardo** | 0-50ms | Delay aggiuntivo (0 = più veloce) |
|
|
||||||
| **Max Clicks** | 50-100 | Limite click (0 = illimitato) |
|
|
||||||
| **Max Resets** | 10-20 | Limite reset (0 = illimitato) |
|
|
||||||
| **Min Price** | 5-10€ | Prezzo minimo (0 = no limite) |
|
|
||||||
| **Max Price** | 50-100€ | Prezzo massimo (0 = no limite) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ??? Controlli Principali
|
|
||||||
|
|
||||||
### Pulsanti
|
|
||||||
- **[Avvia]** ? Inizia automazione
|
|
||||||
- **[Pausa]** ? Sospende puntate (monitora senza puntare)
|
|
||||||
- **[Riprendi]** ? Riprende puntate
|
|
||||||
- **[Stop]** ? Ferma tutto
|
|
||||||
|
|
||||||
### Modalità
|
|
||||||
- **[Asta Singola]** ? Focus su una sola asta
|
|
||||||
- **[Multi-Asta]** ? Monitora tutti i preferiti
|
|
||||||
|
|
||||||
### Opzioni
|
|
||||||
- **? Multi-Click** ? Doppio click per affidabilità
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Indicatori UI
|
|
||||||
|
|
||||||
### Statistiche
|
|
||||||
- **Auto-click: N** ? Puntate effettuate
|
|
||||||
- **Resets: N** ? Reset rilevati
|
|
||||||
- **Prezzo corrente: X€** ? Prezzo asta attiva
|
|
||||||
|
|
||||||
### Multi-Asta (solo modalità Multi)
|
|
||||||
- **Asta Attiva** ? Nome asta su cui si punta
|
|
||||||
- **Aste monitorate** ? Numero preferiti trovati
|
|
||||||
|
|
||||||
### Elenco Utenti
|
|
||||||
- Mostra chi punta e quante volte
|
|
||||||
- **[Pulisci]** ? Azzera lista
|
|
||||||
|
|
||||||
### Log
|
|
||||||
- Cronologia eventi dettagliata
|
|
||||||
- **[Pulisci]** ? Svuota log (migliora performance)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Strategie Rapide
|
|
||||||
|
|
||||||
### Velocità Massima (Aggressiva)
|
|
||||||
```
|
|
||||||
Timer Click: 0
|
|
||||||
Ritardo: 0ms
|
|
||||||
Multi-Click: ?
|
|
||||||
Max Clicks: 100
|
|
||||||
```
|
|
||||||
|
|
||||||
### Risparmio Click (Conservativa)
|
|
||||||
```
|
|
||||||
Timer Click: 1
|
|
||||||
Ritardo: 100ms
|
|
||||||
Multi-Click: ?
|
|
||||||
Max Clicks: 30
|
|
||||||
```
|
|
||||||
|
|
||||||
### Selezione Prezzo (Intelligente)
|
|
||||||
```
|
|
||||||
Timer Click: 0
|
|
||||||
Min Price: 10€
|
|
||||||
Max Price: 50€
|
|
||||||
Multi-Click: ?
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multi-Asta Ottimale
|
|
||||||
```
|
|
||||||
Modalità: Multi-Asta
|
|
||||||
Timer Click: 0 o 1
|
|
||||||
Ritardo: 0-50ms
|
|
||||||
Min/Max Price: A piacere
|
|
||||||
Preferiti: 5-10 aste
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Scorciatoie
|
|
||||||
|
|
||||||
- **Enter** nella barra indirizzo ? Naviga
|
|
||||||
- **[Pulisci]** log ? Migliora performance
|
|
||||||
- **Click destro** su link asta ? Nuova finestra
|
|
||||||
- **[Aggiorna]** pagina ? Ricarica se problemi
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Risoluzione Problemi Rapida
|
|
||||||
|
|
||||||
### AutoBidder non clicca
|
|
||||||
? Verifica **Timer Click** (0-8)
|
|
||||||
? Controlla **Min/Max Price**
|
|
||||||
? Disattiva **Pausa**
|
|
||||||
? Ricarica pagina
|
|
||||||
|
|
||||||
### Click troppo lento
|
|
||||||
? Riduci **Ritardo** a 0ms
|
|
||||||
? Timer Click = **0**
|
|
||||||
? Disattiva **Multi-Click**
|
|
||||||
|
|
||||||
### Multi-Asta: nessuna asta trovata
|
|
||||||
? Vai a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
? Aggiungi aste ai **Preferiti** (?)
|
|
||||||
? Clicca **[Aggiorna]**
|
|
||||||
|
|
||||||
### Lag/Performance basse
|
|
||||||
? Clicca **[Pulisci]** sul log
|
|
||||||
? Riduci preferiti (< 10)
|
|
||||||
? Chiudi altre app
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Comandi Browser
|
|
||||||
|
|
||||||
### Barra Navigazione
|
|
||||||
- **[Indietro]** ? Pagina precedente
|
|
||||||
- **[Aggiorna]** ? Ricarica corrente
|
|
||||||
- **Indirizzo** ? Inserisci URL Bidoo
|
|
||||||
- **[Vai]** ? Naviga a URL
|
|
||||||
|
|
||||||
### Domini Consentiti
|
|
||||||
? `bidoo.com` e sottodomini
|
|
||||||
? `it.bidoo.com`
|
|
||||||
? Altri siti bloccati
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Tips Pro
|
|
||||||
|
|
||||||
### Asta Singola
|
|
||||||
- Usa **Timer Click = 0** per aste competitive
|
|
||||||
- Attiva **Multi-Click** se hai lag
|
|
||||||
- Imposta **Max Resets** per evitare loop infiniti
|
|
||||||
|
|
||||||
### Multi-Asta
|
|
||||||
- Seleziona aste con **timer simili** (tutte 8s o 10s)
|
|
||||||
- Imposta **Min/Max Price** per filtrare
|
|
||||||
- Max **10-15 preferiti** per performance ottimali
|
|
||||||
- Ricarica pagina ogni **2-3 minuti**
|
|
||||||
|
|
||||||
### Generale
|
|
||||||
- Monitora il **Log** per capire cosa succede
|
|
||||||
- Usa **Pausa** invece di Stop per analizzare
|
|
||||||
- Pulisci **Elenco Utenti** periodicamente
|
|
||||||
- Testa configurazioni in aste **non competitive** prima
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Limiti Importanti
|
|
||||||
|
|
||||||
### Max Clicks
|
|
||||||
- **0** = Illimitato (attenzione al consumo!)
|
|
||||||
- **30-50** = Conservativo
|
|
||||||
- **100-200** = Aggressivo
|
|
||||||
|
|
||||||
### Max Resets
|
|
||||||
- **0** = Illimitato (può andare avanti ore)
|
|
||||||
- **5-10** = Sicuro
|
|
||||||
- **20-30** = Persistente
|
|
||||||
|
|
||||||
### Timer Click
|
|
||||||
- **0** = 0.0-0.9s (massima velocità)
|
|
||||||
- **1** = 1.0-1.9s (bilanciato)
|
|
||||||
- **2+** = Per timer lunghi (10s, 15s)
|
|
||||||
|
|
||||||
### Ritardo
|
|
||||||
- **0ms** = Nessun delay (max velocità)
|
|
||||||
- **50-100ms** = Raccomandato
|
|
||||||
- **500+ms** = Troppo lento, evitare
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Colori Interfaccia
|
|
||||||
|
|
||||||
### Pulsanti
|
|
||||||
- ?? **Verde** = Attivo/Selezionato
|
|
||||||
- ?? **Rosso** = Stop (disabilitato finché non avviato)
|
|
||||||
- ?? **Giallo** = Pausa/Riprendi
|
|
||||||
- ?? **Blu** = Azioni secondarie (Aggiorna, Pulisci)
|
|
||||||
- ? **Grigio** = Disattivo
|
|
||||||
|
|
||||||
### Indicatori
|
|
||||||
- ?? **Verde** = Prezzo corrente (valore positivo)
|
|
||||||
- ? **Bianco** = Testo normale
|
|
||||||
- ?? **Blu chiaro** = Link/Interattivo
|
|
||||||
- ?? **Rosso** = Errore/Warning (nel log)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Checklist Pre-Avvio
|
|
||||||
|
|
||||||
### Asta Singola
|
|
||||||
- [ ] Navigato all'asta desiderata
|
|
||||||
- [ ] **Timer Click** impostato (0-8)
|
|
||||||
- [ ] **Ritardo** configurato (0-2000ms)
|
|
||||||
- [ ] **Max Clicks** impostato (o 0 per illimitato)
|
|
||||||
- [ ] **Min/Max Price** configurati (opzionale)
|
|
||||||
- [ ] WebView caricato correttamente
|
|
||||||
|
|
||||||
### Multi-Asta
|
|
||||||
- [ ] Aste aggiunte ai **Preferiti** su Bidoo
|
|
||||||
- [ ] Cliccato **[Multi-Asta]** in AutoBidder
|
|
||||||
- [ ] Navigato a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
- [ ] **Aste monitorate > 0** (vedi pannello)
|
|
||||||
- [ ] **Timer Click** impostato (0-8)
|
|
||||||
- [ ] **Limiti prezzo** configurati (opzionale)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Supporto Emergenza
|
|
||||||
|
|
||||||
### Crash/Freeze
|
|
||||||
1. Chiudi AutoBidder
|
|
||||||
2. Riavvia
|
|
||||||
3. Ricarica pagina Bidoo
|
|
||||||
4. Riconfigura impostazioni
|
|
||||||
|
|
||||||
### Click non funzionanti
|
|
||||||
1. **[Stop]** ? **[Aggiorna]** pagina
|
|
||||||
2. Attendi caricamento completo
|
|
||||||
3. **[Avvia]** di nuovo
|
|
||||||
|
|
||||||
### Troppi click consumati
|
|
||||||
1. **[Stop]** immediatamente
|
|
||||||
2. Aumenta **Timer Click** (es. 0 ? 1)
|
|
||||||
3. Aumenta **Ritardo** (es. 0 ? 100ms)
|
|
||||||
4. Riduci **Max Clicks**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Info Rapide
|
|
||||||
|
|
||||||
**Versione**: 2.0 (Multi-Asta)
|
|
||||||
**Framework**: .NET 8 WPF
|
|
||||||
**Browser**: Edge WebView2
|
|
||||||
**Piattaforma**: Windows 10/11
|
|
||||||
|
|
||||||
**Domini supportati**:
|
|
||||||
- bidoo.com
|
|
||||||
- it.bidoo.com
|
|
||||||
- www.bidoo.com
|
|
||||||
|
|
||||||
**Funzionalità principali**:
|
|
||||||
- ? Asta Singola (focus)
|
|
||||||
- ? Multi-Asta (preferiti)
|
|
||||||
- ? Limiti click/reset/prezzo
|
|
||||||
- ? Multi-click opzionale
|
|
||||||
- ? Polling dinamico ultra-veloce
|
|
||||||
- ? Tracciamento utenti
|
|
||||||
- ? Log dettagliato
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Buone aste! ????**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Documentazione Completa
|
|
||||||
|
|
||||||
Per guide dettagliate, consulta:
|
|
||||||
- `README.md` ? Documentazione completa
|
|
||||||
- `MULTI_AUCTION_GUIDE.md` ? Guida Multi-Asta
|
|
||||||
- `IMPLEMENTATION_SUMMARY.md` ? Dettagli tecnici
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Ultima modifica**: 2024 - AutoBidder Team
|
|
||||||
@@ -1,439 +0,0 @@
|
|||||||
# ?? AutoBidder - Bidoo Auto Bid Assistant
|
|
||||||
|
|
||||||
**AutoBidder** è un'applicazione WPF (.NET 8) per Windows che automatizza le puntate su **Bidoo.com** con precisione al millisecondo.
|
|
||||||
|
|
||||||
## ? Caratteristiche Principali
|
|
||||||
|
|
||||||
### ?? Due Modalità Operative
|
|
||||||
|
|
||||||
#### ?? Modalità Asta Singola
|
|
||||||
- Focus su **una singola asta**
|
|
||||||
- Massima precisione e velocità
|
|
||||||
- Ideale per prodotti specifici
|
|
||||||
|
|
||||||
#### ?? Modalità Multi-Asta (NUOVO!)
|
|
||||||
- Monitora **tutte le aste nei preferiti**
|
|
||||||
- Punta automaticamente sull'asta più vicina
|
|
||||||
- Ottimizza risorse con una sola WebView
|
|
||||||
- Massimizza opportunità di vincita
|
|
||||||
|
|
||||||
### ? Performance Ultra-Reattive
|
|
||||||
- **Polling dinamico**: 20-400ms basato sul timer
|
|
||||||
- **Lettura diretta** variabili JavaScript Bidoo
|
|
||||||
- **Multi-click** opzionale per affidabilità
|
|
||||||
- **Cache intelligente** per velocità massima
|
|
||||||
|
|
||||||
### ??? Controlli Avanzati
|
|
||||||
- **Max Clicks**: Limite puntate totali
|
|
||||||
- **Max Resets**: Limite reset asta
|
|
||||||
- **Min/Max Price**: Range prezzo automatico
|
|
||||||
- **Timer Click**: Secondo esatto del click (0-8s)
|
|
||||||
- **Ritardo**: Delay aggiuntivo (0-2000ms)
|
|
||||||
- **Pausa/Riprendi**: Controllo in tempo reale
|
|
||||||
|
|
||||||
### ?? Statistiche Real-Time
|
|
||||||
- Counter click e reset
|
|
||||||
- Prezzo corrente
|
|
||||||
- Elenco puntatori con timestamp
|
|
||||||
- Log dettagliato operazioni
|
|
||||||
- Asta attiva (Multi-Asta)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Quick Start
|
|
||||||
|
|
||||||
### Requisiti
|
|
||||||
- Windows 10/11
|
|
||||||
- .NET 8 Runtime
|
|
||||||
- Microsoft Edge WebView2 (installato automaticamente)
|
|
||||||
|
|
||||||
### Installazione
|
|
||||||
1. Scarica l'eseguibile
|
|
||||||
2. Esegui `AutoBidder.exe`
|
|
||||||
3. Accedi a Bidoo tramite il browser integrato
|
|
||||||
|
|
||||||
### Primo Utilizzo - Asta Singola
|
|
||||||
1. Naviga all'asta desiderata su Bidoo
|
|
||||||
2. Configura i parametri (Timer Click, limiti, etc.)
|
|
||||||
3. Clicca **"Avvia"**
|
|
||||||
4. AutoBidder punterà automaticamente
|
|
||||||
|
|
||||||
### Primo Utilizzo - Multi-Asta
|
|
||||||
1. Aggiungi aste ai **Preferiti** su Bidoo (?)
|
|
||||||
2. Clicca **"Multi-Asta"** in AutoBidder
|
|
||||||
3. Configura i parametri
|
|
||||||
4. Clicca **"Avvia"**
|
|
||||||
5. AutoBidder gestirà tutte le aste automaticamente
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Guida Completa
|
|
||||||
|
|
||||||
### Modalità Asta Singola
|
|
||||||
|
|
||||||
#### Configurazione Base
|
|
||||||
```
|
|
||||||
Timer Click: 0-8 (secondo del timer per il click)
|
|
||||||
Ritardo: 0-2000ms (delay aggiuntivo)
|
|
||||||
Max Clicks: 0 = illimitato
|
|
||||||
Max Resets: 0 = illimitato
|
|
||||||
Min Price: 0 = nessun limite
|
|
||||||
Max Price: 0 = nessun limite
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Esempio Configurazione
|
|
||||||
- **Timer Click = 1**: Clicca quando il timer è tra 1.0-1.9s
|
|
||||||
- **Ritardo = 100ms**: Attende 100ms dopo il trigger
|
|
||||||
- **Max Clicks = 50**: Ferma dopo 50 puntate
|
|
||||||
- **Min Price = 10**: Non punta se prezzo < 10€
|
|
||||||
- **Max Price = 100**: Non punta se prezzo > 100€
|
|
||||||
|
|
||||||
### Modalità Multi-Asta
|
|
||||||
|
|
||||||
#### Come Funziona
|
|
||||||
1. **Scansione**: Rileva tutte le aste nei preferiti ogni 5s
|
|
||||||
2. **Priorità**: Seleziona asta con timer più basso
|
|
||||||
3. **Click**: Punta sull'asta prioritaria al momento giusto
|
|
||||||
4. **Rotazione**: Continua su altre aste quando necessario
|
|
||||||
|
|
||||||
#### Algoritmo di Priorità
|
|
||||||
```
|
|
||||||
Per ogni ciclo:
|
|
||||||
1. Leggi timer di TUTTE le aste
|
|
||||||
2. Filtra per limiti prezzo (se impostati)
|
|
||||||
3. Seleziona asta con timer più basso
|
|
||||||
4. Clicca se timer nel range configurato
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Esempio Scenario
|
|
||||||
```
|
|
||||||
Preferiti:
|
|
||||||
?? iPhone 16 Pro (Timer: 8.3s) ? Aspetta
|
|
||||||
?? Galaxy S25 (Timer: 1.2s) ? PUNTA! ?
|
|
||||||
?? MacBook Pro (Timer: 5.7s) ? Aspetta
|
|
||||||
|
|
||||||
? Click su Galaxy S25
|
|
||||||
? Dopo il click, ri-valuta priorità
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Impostazioni Dettagliate
|
|
||||||
|
|
||||||
### Timer Click (0-8)
|
|
||||||
- **0**: Clicca a 0-0.9 secondi (massima aggressività)
|
|
||||||
- **1**: Clicca a 1-1.9 secondi (bilanciato)
|
|
||||||
- **2**: Clicca a 2-2.9 secondi (conservativo)
|
|
||||||
- **3-8**: Per timer lunghi (10s, 15s, etc.)
|
|
||||||
|
|
||||||
### Ritardo (ms)
|
|
||||||
- **0**: Nessun delay (massima velocità)
|
|
||||||
- **50-100**: Raccomandato per stabilità
|
|
||||||
- **100-500**: Per connessioni lente
|
|
||||||
- **500+**: Non raccomandato (troppo lento)
|
|
||||||
|
|
||||||
### Multi-Click
|
|
||||||
- ? Attivato: Doppio click a 20ms di distanza
|
|
||||||
- ? Disattivato: Singolo click
|
|
||||||
- ?? **Consiglio**: Attiva se hai lag o packet loss
|
|
||||||
|
|
||||||
### Limiti Prezzo
|
|
||||||
- **Min Price**: AutoBidder salta aste sotto questo valore
|
|
||||||
- **Max Price**: AutoBidder salta aste sopra questo valore
|
|
||||||
- **0 = Nessun limite** (punta sempre)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Interfaccia Utente
|
|
||||||
|
|
||||||
### Pannello Sinistro
|
|
||||||
```
|
|
||||||
???????????????????????????????
|
|
||||||
? [Asta Singola] [Multi-Asta] ? ? Modalità
|
|
||||||
???????????????????????????????
|
|
||||||
? [Avvia] ?
|
|
||||||
? [Pausa] ?
|
|
||||||
? [Stop] ?
|
|
||||||
???????????????????????????????
|
|
||||||
? Auto-click: 0 Resets: 0 ?
|
|
||||||
? Prezzo: 15.50 € ?
|
|
||||||
? ? Multi-Click ?
|
|
||||||
???????????????????????????????
|
|
||||||
? ?? Asta Attiva (Multi-Asta) ?
|
|
||||||
? Galaxy S25 512GB ?
|
|
||||||
? Monitorate: 3 ?
|
|
||||||
???????????????????????????????
|
|
||||||
? Max Clicks ? Max Resets ?
|
|
||||||
? Min Price ? Max Price ?
|
|
||||||
? Timer Click ? Ritardo ?
|
|
||||||
???????????????????????????????
|
|
||||||
? Elenco Utenti [Pulisci] ?
|
|
||||||
? ????????????????????????? ?
|
|
||||||
? ? Nome ? Puntate ? ?
|
|
||||||
? ? user123 ? 15 ? ?
|
|
||||||
? ????????????????????????? ?
|
|
||||||
???????????????????????????????
|
|
||||||
? Log Operazioni [Pulisci] ?
|
|
||||||
? ????????????????????????? ?
|
|
||||||
? ? 10:30:15 - Click #1 ? ?
|
|
||||||
? ? 10:30:18 - Reset #1 ? ?
|
|
||||||
? ????????????????????????? ?
|
|
||||||
???????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pannello Destro (WebView)
|
|
||||||
- **Barra indirizzo**: Inserisci URL Bidoo
|
|
||||||
- **[Indietro]**: Navigazione
|
|
||||||
- **[Aggiorna]**: Ricarica pagina
|
|
||||||
- **[Vai]**: Naviga a URL
|
|
||||||
- **Browser integrato**: Visualizza Bidoo in tempo reale
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Risoluzione Problemi
|
|
||||||
|
|
||||||
### AutoBidder non clicca
|
|
||||||
|
|
||||||
**Possibili cause:**
|
|
||||||
1. ? Timer Click impostato male
|
|
||||||
- Soluzione: Verifica che sia 0-8 e coerente col timer dell'asta
|
|
||||||
2. ? Prezzo fuori range
|
|
||||||
- Soluzione: Controlla Min/Max Price, imposta 0 per disabilitare
|
|
||||||
3. ? Pausa attiva
|
|
||||||
- Soluzione: Clicca "Riprendi"
|
|
||||||
4. ? Elementi pagina non trovati
|
|
||||||
- Soluzione: Ricarica la pagina (F5 o pulsante Aggiorna)
|
|
||||||
|
|
||||||
### Click troppo lento
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Riduci "Ritardo" a 0-50ms
|
|
||||||
2. Disattiva Multi-Click
|
|
||||||
3. Chiudi altre applicazioni
|
|
||||||
4. Usa Timer Click = 0 per massima velocità
|
|
||||||
|
|
||||||
### Multi-Asta non trova aste
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Verifica di essere su `https://it.bidoo.com/?tab=FAV`
|
|
||||||
2. Aggiungi aste ai preferiti (stella ?)
|
|
||||||
3. Ricarica la pagina
|
|
||||||
4. Controlla che le aste siano attive (non vendute)
|
|
||||||
|
|
||||||
### Troppi reset rilevati
|
|
||||||
|
|
||||||
**Causa**: Altri utenti puntano molto velocemente
|
|
||||||
|
|
||||||
**Soluzioni:**
|
|
||||||
1. Riduci Timer Click (es. da 1 a 0)
|
|
||||||
2. Attiva Multi-Click
|
|
||||||
3. Riduci Ritardo a 0ms
|
|
||||||
4. Usa Multi-Asta per più opportunità
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Strategie Vincenti
|
|
||||||
|
|
||||||
### Strategia Aggressiva (Massima Velocità)
|
|
||||||
```
|
|
||||||
Timer Click: 0
|
|
||||||
Ritardo: 0ms
|
|
||||||
Multi-Click: ? Attivo
|
|
||||||
Max Clicks: 100
|
|
||||||
Max Resets: 20
|
|
||||||
```
|
|
||||||
**Pro**: Massima reattività
|
|
||||||
**Contro**: Consuma click rapidamente
|
|
||||||
|
|
||||||
### Strategia Conservativa (Risparmio Click)
|
|
||||||
```
|
|
||||||
Timer Click: 1
|
|
||||||
Ritardo: 100ms
|
|
||||||
Multi-Click: ? Disattivo
|
|
||||||
Max Clicks: 30
|
|
||||||
Max Resets: 5
|
|
||||||
```
|
|
||||||
**Pro**: Risparmia click
|
|
||||||
**Contro**: Meno competitivo
|
|
||||||
|
|
||||||
### Strategia Multi-Asta (Opportunista)
|
|
||||||
```
|
|
||||||
Modalità: Multi-Asta
|
|
||||||
Timer Click: 0-1
|
|
||||||
Ritardo: 50ms
|
|
||||||
Min Price: 5€
|
|
||||||
Max Price: 50€
|
|
||||||
```
|
|
||||||
**Pro**: Massimizza vincite su più aste
|
|
||||||
**Contro**: Richiede più preferiti configurati
|
|
||||||
|
|
||||||
### Strategia Range Prezzo (Selettiva)
|
|
||||||
```
|
|
||||||
Min Price: 20€
|
|
||||||
Max Price: 100€
|
|
||||||
Timer Click: 1
|
|
||||||
Max Clicks: 0 (illimitato)
|
|
||||||
```
|
|
||||||
**Pro**: Punta solo su prezzi vantaggiosi
|
|
||||||
**Contro**: Può saltare molte opportunità
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Ottimizzazione Performance
|
|
||||||
|
|
||||||
### Polling Dinamico
|
|
||||||
AutoBidder adatta automaticamente la frequenza di lettura:
|
|
||||||
|
|
||||||
| Timer Asta | Polling | Reattività |
|
|
||||||
|-----------|---------|------------|
|
|
||||||
| < 1.5s | 20ms | ?? ULTRA |
|
|
||||||
| < 2.5s | 40ms | ?? ALTA |
|
|
||||||
| < 3.5s | 80ms | ?? MEDIA |
|
|
||||||
| < 5.0s | 150ms | ?? NORMALE |
|
|
||||||
| > 8.0s | 400ms | ?? ECO |
|
|
||||||
|
|
||||||
### Cache e Ottimizzazioni
|
|
||||||
- **Cache bottone**: 500ms (riusa elemento click)
|
|
||||||
- **Cache timer**: 20ms (lettura ultra-veloce)
|
|
||||||
- **UI update**: Max ogni 2s (riduce lag)
|
|
||||||
- **Log limit**: 500 righe (auto-pulizia)
|
|
||||||
|
|
||||||
### Consigli Performance
|
|
||||||
1. ?? Chiudi app pesanti durante l'uso
|
|
||||||
2. ?? Non navigare manualmente durante l'automazione
|
|
||||||
3. ?? Usa "Pulisci Log" periodicamente
|
|
||||||
4. ?? In Multi-Asta: max 10-15 preferiti
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Sicurezza e Limitazioni
|
|
||||||
|
|
||||||
### Cosa AutoBidder FA
|
|
||||||
? Automatizza click sul pulsante "PUNTA"
|
|
||||||
? Legge timer e prezzo dalla pagina
|
|
||||||
? Traccia puntatori e statistiche
|
|
||||||
? Applica limiti configurati dall'utente
|
|
||||||
|
|
||||||
### Cosa AutoBidder NON FA
|
|
||||||
? Non modifica il sito Bidoo
|
|
||||||
? Non aggira limiti di vincita
|
|
||||||
? Non invia dati esterni
|
|
||||||
? Non hackera o sfrutta vulnerabilità
|
|
||||||
|
|
||||||
### Domini Consentiti
|
|
||||||
AutoBidder permette navigazione solo su:
|
|
||||||
- ? `bidoo.com` e sottodomini
|
|
||||||
- ? `it.bidoo.com`
|
|
||||||
- ? `www.bidoo.com`
|
|
||||||
- ? Altri domini sono bloccati
|
|
||||||
|
|
||||||
### Privacy
|
|
||||||
- ?? **100% Locale**: Nessun dato inviato online
|
|
||||||
- ?? **No Telemetria**: Zero tracciamento
|
|
||||||
- ?? **Open Logic**: Codice verificabile
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ??? Sviluppo e Contributi
|
|
||||||
|
|
||||||
### Tecnologie
|
|
||||||
- **Framework**: WPF (.NET 8)
|
|
||||||
- **WebView**: Microsoft Edge WebView2
|
|
||||||
- **Linguaggio**: C# 12
|
|
||||||
- **UI**: XAML con stili custom
|
|
||||||
|
|
||||||
### Struttura Codice
|
|
||||||
```
|
|
||||||
AutoBidder/
|
|
||||||
??? MainWindow.xaml # UI principale
|
|
||||||
??? MainWindow.xaml.cs # Logica automazione
|
|
||||||
??? App.xaml # Configurazione app
|
|
||||||
??? MULTI_AUCTION_GUIDE.md # Guida Multi-Asta
|
|
||||||
??? README.md # Questo file
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build
|
|
||||||
```bash
|
|
||||||
dotnet build -c Release
|
|
||||||
```
|
|
||||||
|
|
||||||
### Requisiti Dev
|
|
||||||
- Visual Studio 2022+ o VS Code
|
|
||||||
- .NET 8 SDK
|
|
||||||
- Windows 10/11
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Changelog
|
|
||||||
|
|
||||||
### v2.0 (Attuale)
|
|
||||||
- ? **Nuova modalità Multi-Asta**
|
|
||||||
- ? Monitoraggio simultaneo preferiti
|
|
||||||
- ? Selezione intelligente asta prioritaria
|
|
||||||
- ? Pannello "Asta Attiva"
|
|
||||||
- ? Ottimizzazione risorse (singola WebView)
|
|
||||||
- ?? Fix contatore reset
|
|
||||||
- ?? Fix tracciamento bidder
|
|
||||||
- ? Performance polling dinamico
|
|
||||||
|
|
||||||
### v1.x
|
|
||||||
- ? Modalità Asta Singola
|
|
||||||
- ? Lettura diretta variabili JS Bidoo
|
|
||||||
- ? Multi-click opzionale
|
|
||||||
- ? Limiti prezzo e click
|
|
||||||
- ? Tracciamento utenti
|
|
||||||
- ? Log operazioni
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? FAQ
|
|
||||||
|
|
||||||
**Q: AutoBidder è legale?**
|
|
||||||
A: Sì, automatizza solo azioni che potresti fare manualmente. Non viola ToS di Bidoo.
|
|
||||||
|
|
||||||
**Q: Posso vincere sempre?**
|
|
||||||
A: No, AutoBidder aumenta le possibilità ma non garantisce vincite. Dipende da competizione e configurazione.
|
|
||||||
|
|
||||||
**Q: Quante aste posso monitorare?**
|
|
||||||
A: In Multi-Asta: idealmente 10-15 per performance ottimali. Tecnicamente illimitate.
|
|
||||||
|
|
||||||
**Q: Funziona su Mac/Linux?**
|
|
||||||
A: No, richiede Windows per WebView2. Possibile port futuro con Avalonia.
|
|
||||||
|
|
||||||
**Q: AutoBidder consuma molti click?**
|
|
||||||
A: Dipende da configurazione. Usa Max Clicks e Timer Click appropriati per controllare consumo.
|
|
||||||
|
|
||||||
**Q: Posso usare più istanze?**
|
|
||||||
A: Sì, puoi aprire nuove finestre (click destro su link asta). Attenzione al consumo risorse.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Supporto
|
|
||||||
|
|
||||||
### Problemi Comuni
|
|
||||||
1. **Errore WebView2**: Installa Microsoft Edge
|
|
||||||
2. **Click non funziona**: Ricarica pagina
|
|
||||||
3. **Lag**: Riduci preferiti in Multi-Asta
|
|
||||||
4. **Crash**: Verifica .NET 8 installato
|
|
||||||
|
|
||||||
### Contatti
|
|
||||||
- ?? **Bug Report**: Apri issue su repository
|
|
||||||
- ?? **Feature Request**: Suggerisci miglioramenti
|
|
||||||
- ?? **Documentazione**: Leggi guide incluse
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Licenza
|
|
||||||
|
|
||||||
Questo software è fornito "così com'è" senza garanzie.
|
|
||||||
L'uso è a proprio rischio e responsabilità.
|
|
||||||
|
|
||||||
**Disclaimer**: AutoBidder è uno strumento di automazione per uso personale. L'utente è responsabile del rispetto dei termini di servizio di Bidoo.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Ringraziamenti
|
|
||||||
|
|
||||||
Grazie a tutti gli utenti per feedback e testing!
|
|
||||||
|
|
||||||
**Buone aste! ????**
|
|
||||||
@@ -0,0 +1,478 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AutoBidder.Models;
|
||||||
|
|
||||||
|
namespace AutoBidder.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Servizio centrale per monitoraggio multi-asta
|
||||||
|
/// Gestisce polling API Bidoo e trigger dei click
|
||||||
|
/// </summary>
|
||||||
|
public class AuctionMonitor
|
||||||
|
{
|
||||||
|
private readonly BidooApiClient _apiClient;
|
||||||
|
private readonly List<AuctionInfo> _auctions = new();
|
||||||
|
private CancellationTokenSource? _monitoringCts;
|
||||||
|
private Task? _monitoringTask;
|
||||||
|
|
||||||
|
public event Action<AuctionState>? OnAuctionUpdated;
|
||||||
|
public event Action<AuctionInfo, BidResult>? OnBidExecuted;
|
||||||
|
public event Action<string>? OnLog;
|
||||||
|
public event Action<string>? OnResetCountChanged; // Notifica cambio contatore reset
|
||||||
|
|
||||||
|
public AuctionMonitor()
|
||||||
|
{
|
||||||
|
_apiClient = new BidooApiClient();
|
||||||
|
|
||||||
|
// Subscribe to detailed per-auction logs from API client
|
||||||
|
_apiClient.OnAuctionLog += (auctionId, message) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock (_auctions)
|
||||||
|
{
|
||||||
|
var auction = _auctions.FirstOrDefault(a => a.AuctionId == auctionId);
|
||||||
|
if (auction != null)
|
||||||
|
{
|
||||||
|
auction.AddLog(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inizializza sessione con token di autenticazione
|
||||||
|
/// </summary>
|
||||||
|
public void InitializeSession(string authToken, string username)
|
||||||
|
{
|
||||||
|
_apiClient.InitializeSession(authToken, username);
|
||||||
|
OnLog?.Invoke($"[OK] Sessione configurata per: {username}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inizializza sessione con cookie (fallback legacy)
|
||||||
|
/// </summary>
|
||||||
|
public void InitializeSessionWithCookie(string cookieString, string username)
|
||||||
|
{
|
||||||
|
_apiClient.InitializeSessionWithCookie(cookieString, username);
|
||||||
|
OnLog?.Invoke($"[OK] Sessione configurata (cookie) per: {username}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiorna info utente (puntate rimanenti)
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool> UpdateUserInfoAsync()
|
||||||
|
{
|
||||||
|
return await _apiClient.UpdateUserInfoAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ottieni sessione corrente
|
||||||
|
/// </summary>
|
||||||
|
public BidooSession GetSession()
|
||||||
|
{
|
||||||
|
return _apiClient.GetSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddAuction(AuctionInfo auction)
|
||||||
|
{
|
||||||
|
lock (_auctions)
|
||||||
|
{
|
||||||
|
if (!_auctions.Any(a => a.AuctionId == auction.AuctionId))
|
||||||
|
{
|
||||||
|
_auctions.Add(auction);
|
||||||
|
OnLog?.Invoke($"[+] Asta aggiunta: {auction.Name} (ID: {auction.AuctionId})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAuction(string auctionId)
|
||||||
|
{
|
||||||
|
lock (_auctions)
|
||||||
|
{
|
||||||
|
var auction = _auctions.FirstOrDefault(a => a.AuctionId == auctionId);
|
||||||
|
if (auction != null)
|
||||||
|
{
|
||||||
|
_auctions.Remove(auction);
|
||||||
|
OnLog?.Invoke($"[-] Asta rimossa: {auction.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<AuctionInfo> GetAuctions()
|
||||||
|
{
|
||||||
|
lock (_auctions)
|
||||||
|
{
|
||||||
|
return _auctions.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> InitializeCookies(Microsoft.Web.WebView2.Wpf.WebView2 webView)
|
||||||
|
{
|
||||||
|
// Non più utilizzato - usa InitializeSession invece
|
||||||
|
return Task.FromResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
if (_monitoringTask != null && !_monitoringTask.IsCompleted)
|
||||||
|
{
|
||||||
|
OnLog?.Invoke("[WARN] Monitoraggio gia' attivo");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_monitoringCts = new CancellationTokenSource();
|
||||||
|
_monitoringTask = Task.Run(() => MonitoringLoop(_monitoringCts.Token));
|
||||||
|
OnLog?.Invoke("[START] Monitoraggio avviato");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_monitoringCts?.Cancel();
|
||||||
|
_monitoringTask?.Wait(TimeSpan.FromSeconds(2));
|
||||||
|
_monitoringCts = null;
|
||||||
|
_monitoringTask = null;
|
||||||
|
OnLog?.Invoke("[STOP] Monitoraggio fermato");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MonitoringLoop(CancellationToken token)
|
||||||
|
{
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<AuctionInfo> activeAuctions;
|
||||||
|
lock (_auctions)
|
||||||
|
{
|
||||||
|
// Filtra aste che devono ancora essere monitorate
|
||||||
|
// Include aste attive anche se messe in pausa: vogliamo continuare a monitorarle
|
||||||
|
// ma non inviare puntate per quelle in pausa.
|
||||||
|
activeAuctions = _auctions.Where(a =>
|
||||||
|
a.IsActive &&
|
||||||
|
!IsAuctionTerminated(a)
|
||||||
|
).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeAuctions.Count == 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(1000, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll tutte le aste in parallelo
|
||||||
|
var pollTasks = activeAuctions.Select(a => PollAndProcessAuction(a, token));
|
||||||
|
await Task.WhenAll(pollTasks);
|
||||||
|
|
||||||
|
// Ottimizzazione polling per aste in pausa
|
||||||
|
bool anyPaused = false;
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
int pauseDelayMs = 1000; // default
|
||||||
|
foreach (var a in activeAuctions)
|
||||||
|
{
|
||||||
|
if (a.IsPaused)
|
||||||
|
{
|
||||||
|
anyPaused = true;
|
||||||
|
// Se tra le 00:00 e le 09:55 polling ogni 60s
|
||||||
|
if (now.Hour < 9 || (now.Hour == 9 && now.Minute < 55))
|
||||||
|
pauseDelayMs = 60000;
|
||||||
|
// Negli ultimi 5 minuti prima delle 10 polling ogni 5s
|
||||||
|
else if (now.Hour == 9 && now.Minute >= 55)
|
||||||
|
pauseDelayMs = 5000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (anyPaused)
|
||||||
|
{
|
||||||
|
await Task.Delay(pauseDelayMs, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay adattivo OTTIMIZZATO basato su timer più basso
|
||||||
|
var lowestTimer = activeAuctions
|
||||||
|
.Select(a => GetLastTimer(a))
|
||||||
|
.Where(t => t > 0)
|
||||||
|
.DefaultIfEmpty(999)
|
||||||
|
.Min();
|
||||||
|
|
||||||
|
int delayMs = lowestTimer switch
|
||||||
|
{
|
||||||
|
< 1 => 5, // Iper-veloce: polling ogni 5ms (0-1s rimanenti)
|
||||||
|
< 2 => 20, // Ultra-veloce: polling ogni 20ms (1-2s)
|
||||||
|
< 3 => 50, // Molto veloce: polling ogni 50ms (2-3s)
|
||||||
|
< 5 => 100, // Veloce: polling ogni 100ms (3-5s)
|
||||||
|
< 10 => 200, // Medio: polling ogni 200ms (5-10s)
|
||||||
|
< 30 => 500, // Lento: polling ogni 500ms (10-30s)
|
||||||
|
_ => 1000 // Molto lento: polling ogni 1s (>30s)
|
||||||
|
};
|
||||||
|
|
||||||
|
await Task.Delay(delayMs, token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
OnLog?.Invoke($"[ERRORE] Loop monitoraggio: {ex.Message}");
|
||||||
|
await Task.Delay(1000, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica se un'asta è terminata e non deve più essere monitorata
|
||||||
|
/// </summary>
|
||||||
|
private bool IsAuctionTerminated(AuctionInfo auction)
|
||||||
|
{
|
||||||
|
// Se l'ultima entry nello storico indica uno stato finale, ferma polling
|
||||||
|
var lastHistory = auction.BidHistory.LastOrDefault();
|
||||||
|
if (lastHistory != null)
|
||||||
|
{
|
||||||
|
// Controlla se c'è una nota che indica fine asta
|
||||||
|
if (lastHistory.Notes != null &&
|
||||||
|
(lastHistory.Notes.Contains("VINTA") ||
|
||||||
|
lastHistory.Notes.Contains("Persa") ||
|
||||||
|
lastHistory.Notes.Contains("Chiusa")))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PollAndProcessAuction(AuctionInfo auction, CancellationToken token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Poll tramite API Bidoo (passa anche l'URL originale per referer corretto)
|
||||||
|
var state = await _apiClient.PollAuctionStateAsync(auction.AuctionId, auction.OriginalUrl, token);
|
||||||
|
|
||||||
|
if (state == null)
|
||||||
|
{
|
||||||
|
auction.AddLog("ERRORE: Nessun dato ricevuto da API");
|
||||||
|
OnLog?.Invoke($"[ERRORE] [{auction.AuctionId}] API non ha risposto");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se l'asta è terminata, segnala e disattiva polling
|
||||||
|
if (state.Status == AuctionStatus.EndedWon ||
|
||||||
|
state.Status == AuctionStatus.EndedLost ||
|
||||||
|
state.Status == AuctionStatus.Closed)
|
||||||
|
{
|
||||||
|
string statusMsg = state.Status == AuctionStatus.EndedWon ? "VINTA" :
|
||||||
|
state.Status == AuctionStatus.EndedLost ? "Persa" : "Chiusa";
|
||||||
|
|
||||||
|
// Mark auction inactive immediately to stop further polling
|
||||||
|
auction.IsActive = false;
|
||||||
|
|
||||||
|
auction.AddLog($"[ASTA TERMINATA] {statusMsg}");
|
||||||
|
OnLog?.Invoke($"[FINE] [{auction.AuctionId}] Asta {statusMsg} - Polling fermato");
|
||||||
|
|
||||||
|
// Aggiungi entry nello storico per marcare come terminata
|
||||||
|
auction.BidHistory.Add(new BidHistory
|
||||||
|
{
|
||||||
|
Timestamp = DateTime.UtcNow,
|
||||||
|
EventType = BidEventType.Reset,
|
||||||
|
Bidder = state.LastBidder,
|
||||||
|
Price = state.Price,
|
||||||
|
Timer = 0,
|
||||||
|
Notes = $"Asta {statusMsg}"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notifica UI e fermati
|
||||||
|
OnAuctionUpdated?.Invoke(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log stato solo per aste attive (riduci spam)
|
||||||
|
if (state.Status == AuctionStatus.Running)
|
||||||
|
{
|
||||||
|
auction.AddLog($"API OK - Timer: {state.Timer:F2}s, EUR{state.Price:F2}, {state.LastBidder}, {state.PollingLatencyMs}ms");
|
||||||
|
}
|
||||||
|
else if (state.Status == AuctionStatus.Paused)
|
||||||
|
{
|
||||||
|
auction.AddLog($"[PAUSA] Asta in pausa - Timer: {state.Timer:F2}s, EUR{state.Price:F2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifica aggiornamento UI
|
||||||
|
OnAuctionUpdated?.Invoke(state);
|
||||||
|
|
||||||
|
// Aggiorna storico e bidders
|
||||||
|
UpdateAuctionHistory(auction, state);
|
||||||
|
|
||||||
|
// Verifica se puntare (solo se asta Running, NON se in pausa)
|
||||||
|
if (state.Status == AuctionStatus.Running && ShouldBid(auction, state) && !auction.IsPaused)
|
||||||
|
{
|
||||||
|
auction.AddLog($"[TRIGGER] CONDIZIONI OK - Timer {state.Timer:F2}s <= {auction.TimerClick}s");
|
||||||
|
auction.AddLog($"[BID] Invio puntata...");
|
||||||
|
OnLog?.Invoke($"[BID] [{auction.AuctionId}] PUNTATA a {state.Timer:F2}s!");
|
||||||
|
|
||||||
|
// Attendi ritardo configurato
|
||||||
|
if (auction.DelayMs > 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(auction.DelayMs, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Esegui puntata API
|
||||||
|
var result = await _apiClient.PlaceBidAsync(auction.AuctionId);
|
||||||
|
|
||||||
|
// Aggiorna contatori
|
||||||
|
if (result.Success)
|
||||||
|
{
|
||||||
|
auction.MyClicks++;
|
||||||
|
auction.LastClickAt = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifica risultato
|
||||||
|
OnBidExecuted?.Invoke(auction, result);
|
||||||
|
|
||||||
|
// Log
|
||||||
|
if (result.Success)
|
||||||
|
{
|
||||||
|
auction.AddLog($"[OK] PUNTATA OK: {result.LatencyMs}ms -> EUR{result.NewPrice:F2}");
|
||||||
|
OnLog?.Invoke($"[OK] [{auction.AuctionId}] Puntata riuscita {result.LatencyMs}ms");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auction.AddLog($"[FAIL] PUNTATA FALLITA: {result.Error}");
|
||||||
|
OnLog?.Invoke($"[FAIL] [{auction.AuctionId}] ERRORE: {result.Error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storico
|
||||||
|
auction.BidHistory.Add(new BidHistory
|
||||||
|
{
|
||||||
|
Timestamp = result.Timestamp,
|
||||||
|
EventType = result.Success ? BidEventType.MyBid : BidEventType.OpponentBid,
|
||||||
|
Bidder = "Tu",
|
||||||
|
Price = state.Price,
|
||||||
|
Timer = state.Timer,
|
||||||
|
LatencyMs = result.LatencyMs,
|
||||||
|
Success = result.Success,
|
||||||
|
Notes = result.Success ? $"EUR{result.NewPrice:F2}" : result.Error
|
||||||
|
});
|
||||||
|
|
||||||
|
// Se abbiamo raggiunto il numero massimo di click per l'asta, metti in pausa le puntate (ma continua il monitor)
|
||||||
|
if (auction.MaxClicks > 0 && auction.MyClicks >= auction.MaxClicks)
|
||||||
|
{
|
||||||
|
auction.IsPaused = true;
|
||||||
|
auction.AddLog($"[PAUSA] Massimo click ({auction.MaxClicks}) raggiunto - Puntate disabilitate");
|
||||||
|
OnLog?.Invoke($"[PAUSA] [{auction.AuctionId}] MaxClicks raggiunti");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
auction.AddLog($"[EXCEPTION] ERRORE: {ex.Message}");
|
||||||
|
OnLog?.Invoke($"[EXCEPTION] [{auction.AuctionId}] {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldBid(AuctionInfo auction, AuctionState state)
|
||||||
|
{
|
||||||
|
// Timer check
|
||||||
|
if (state.Timer > auction.TimerClick)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Price check
|
||||||
|
if (auction.MinPrice > 0 && state.Price < auction.MinPrice)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (auction.MaxPrice > 0 && state.Price > auction.MaxPrice)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Cooldown check (evita click multipli ravvicinati)
|
||||||
|
if (auction.LastClickAt.HasValue)
|
||||||
|
{
|
||||||
|
var timeSinceLastClick = DateTime.UtcNow - auction.LastClickAt.Value;
|
||||||
|
if (timeSinceLastClick.TotalSeconds < 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Max clicks per auction
|
||||||
|
if (auction.MaxClicks > 0 && auction.MyClicks >= auction.MaxClicks)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAuctionHistory(AuctionInfo auction, AuctionState state)
|
||||||
|
{
|
||||||
|
// Traccia l'ultima puntata per rilevare cambi
|
||||||
|
var lastHistory = auction.BidHistory.LastOrDefault();
|
||||||
|
var lastPrice = lastHistory?.Price ?? 0;
|
||||||
|
var lastBidder = lastHistory?.Bidder;
|
||||||
|
|
||||||
|
bool isNewBid = false;
|
||||||
|
|
||||||
|
// Nuova puntata = CAMBIO PREZZO (più affidabile)
|
||||||
|
// Ogni incremento di prezzo significa che qualcuno ha puntato
|
||||||
|
if (state.Price > lastPrice && state.Price > 0)
|
||||||
|
{
|
||||||
|
isNewBid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: cambio utente (se il prezzo è uguale ma l'utente cambia)
|
||||||
|
if (!isNewBid &&
|
||||||
|
!string.IsNullOrEmpty(lastBidder) &&
|
||||||
|
!string.IsNullOrEmpty(state.LastBidder) &&
|
||||||
|
!lastBidder.Equals(state.LastBidder, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
isNewBid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNewBid)
|
||||||
|
{
|
||||||
|
auction.ResetCount++;
|
||||||
|
auction.BidHistory.Add(new BidHistory
|
||||||
|
{
|
||||||
|
Timestamp = DateTime.UtcNow,
|
||||||
|
EventType = BidEventType.Reset,
|
||||||
|
Bidder = state.LastBidder,
|
||||||
|
Price = state.Price,
|
||||||
|
Timer = state.Timer,
|
||||||
|
Notes = $"Puntata: EUR{state.Price:F2}"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Aggiorna statistiche bidder
|
||||||
|
if (!string.IsNullOrEmpty(state.LastBidder))
|
||||||
|
{
|
||||||
|
if (!auction.BidderStats.ContainsKey(state.LastBidder))
|
||||||
|
{
|
||||||
|
auction.BidderStats[state.LastBidder] = new BidderInfo
|
||||||
|
{
|
||||||
|
Username = state.LastBidder
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auction.BidderStats[state.LastBidder].BidCount++;
|
||||||
|
auction.BidderStats[state.LastBidder].LastBidTime = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notifica cambio reset count per aggiornare UI
|
||||||
|
OnResetCountChanged?.Invoke(auction.AuctionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetLastTimer(AuctionInfo auction)
|
||||||
|
{
|
||||||
|
var lastEntry = auction.BidHistory.LastOrDefault();
|
||||||
|
return lastEntry?.Timer ?? 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
_apiClient?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<BidResult> PlaceManualBidAsync(AuctionInfo auction)
|
||||||
|
{
|
||||||
|
return await _apiClient.PlaceBidAsync(auction.AuctionId, auction.OriginalUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,627 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Text;
|
||||||
|
using AutoBidder.Models;
|
||||||
|
|
||||||
|
namespace AutoBidder.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Servizio completo API Bidoo (polling, puntate, info utente)
|
||||||
|
/// 100% API-based con simulazione completa del comportamento browser
|
||||||
|
///
|
||||||
|
/// FLUSSO DI AUTENTICAZIONE:
|
||||||
|
/// - Cookie principale: __stattr (non PHPSESSID)
|
||||||
|
/// - Il cookie deve essere estratto dal browser dopo login manuale
|
||||||
|
/// - Tutti i request devono includere: Cookie + X-Requested-With: XMLHttpRequest
|
||||||
|
///
|
||||||
|
/// CHIAMATE GET (SOLO LETTURA - No CSRF Token):
|
||||||
|
/// 1. Polling asta: GET data.php?ALL={id}&LISTID=0
|
||||||
|
/// 2. Info utente: GET ajax/get_auction_bids_info_banner.php
|
||||||
|
///
|
||||||
|
/// CHIAMATE POST (AZIONI - Richiedono CSRF Token):
|
||||||
|
/// 1. Piazza puntata: POST bid.php
|
||||||
|
/// - Step 1: GET pagina asta HTML per estrarre bid_token
|
||||||
|
/// - Step 2: POST con payload: a={id}&bid_type=manual&bid_token={token}&time_sent={ts}
|
||||||
|
/// - Step 3: Analizza risposta: "ok|..." o "error|..."
|
||||||
|
///
|
||||||
|
/// SIMULAZIONE BROWSER:
|
||||||
|
/// - User-Agent: Chrome su Windows
|
||||||
|
/// - Headers CORS: Sec-Fetch-*
|
||||||
|
/// - Referer: URL pagina asta
|
||||||
|
/// - Content-Type: application/x-www-form-urlencoded (per POST)
|
||||||
|
/// </summary>
|
||||||
|
public class BidooApiClient
|
||||||
|
{
|
||||||
|
private readonly HttpClient _httpClient;
|
||||||
|
private BidooSession _session;
|
||||||
|
|
||||||
|
// Event used to push detailed logs into per-auction log in the monitor
|
||||||
|
public event Action<string, string>? OnAuctionLog;
|
||||||
|
|
||||||
|
public BidooApiClient()
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
UseCookies = false, // Gestiamo manualmente i cookie
|
||||||
|
AutomaticDecompression = System.Net.DecompressionMethods.All // Decomprimi GZIP/Deflate/Brotli
|
||||||
|
};
|
||||||
|
|
||||||
|
_httpClient = new HttpClient(handler)
|
||||||
|
{
|
||||||
|
Timeout = TimeSpan.FromSeconds(3)
|
||||||
|
};
|
||||||
|
|
||||||
|
_session = new BidooSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper that writes to Console and, when auctionId provided, emits per-auction log event
|
||||||
|
private void Log(string message, string? auctionId = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Console.WriteLine(message);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(auctionId))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OnAuctionLog?.Invoke(auctionId, message);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inizializza sessione con token di autenticazione
|
||||||
|
/// </summary>
|
||||||
|
public void InitializeSession(string authToken, string username)
|
||||||
|
{
|
||||||
|
_session.AuthToken = authToken;
|
||||||
|
_session.Username = username;
|
||||||
|
|
||||||
|
Log($"[SESSION] Token impostato ({authToken.Length} chars)");
|
||||||
|
Log($"[SESSION] Username: {username}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inizializza sessione con cookie string (fallback)
|
||||||
|
/// </summary>
|
||||||
|
public void InitializeSessionWithCookie(string cookieString, string username)
|
||||||
|
{
|
||||||
|
_session.CookieString = cookieString;
|
||||||
|
_session.Username = username;
|
||||||
|
|
||||||
|
Log($"[SESSION] Cookie impostato ({cookieString.Length} chars)");
|
||||||
|
Log($"[SESSION] Username: {username}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiunge header di autenticazione e browser-like alla richiesta
|
||||||
|
/// Headers critici per evitare rilevamento come bot
|
||||||
|
/// </summary>
|
||||||
|
private void AddAuthHeaders(HttpRequestMessage request, string? referer = null, string? auctionId = null)
|
||||||
|
{
|
||||||
|
// 1. AUTENTICAZIONE (priorità: CookieString completa, poi Token singolo)
|
||||||
|
// Il cookie principale per Bidoo è __stattr (non PHPSESSID)
|
||||||
|
if (!string.IsNullOrWhiteSpace(_session.CookieString))
|
||||||
|
{
|
||||||
|
// Usa la stringa cookie completa (es: "__stattr=eyJyZWZ...")
|
||||||
|
request.Headers.Add("Cookie", _session.CookieString);
|
||||||
|
Log("[AUTH] Using full cookie string", auctionId);
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrWhiteSpace(_session.AuthToken))
|
||||||
|
{
|
||||||
|
// Fallback: se abbiamo solo il token, assumiamo sia __stattr
|
||||||
|
request.Headers.Add("Cookie", $"__stattr={_session.AuthToken}");
|
||||||
|
Log("[AUTH] Using __stattr token", auctionId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("[AUTH WARN] No authentication method available!", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. HEADERS BROWSER-LIKE (anti-detection)
|
||||||
|
|
||||||
|
// User-Agent realistico (Chrome su Windows)
|
||||||
|
request.Headers.Add("User-Agent",
|
||||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36");
|
||||||
|
|
||||||
|
// Accept headers
|
||||||
|
request.Headers.Add("Accept", "*/*");
|
||||||
|
request.Headers.Add("Accept-Language", "it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7");
|
||||||
|
request.Headers.Add("Accept-Encoding", "gzip, deflate, br");
|
||||||
|
|
||||||
|
// Security headers (critici per CORS)
|
||||||
|
request.Headers.Add("Sec-Fetch-Dest", "empty");
|
||||||
|
request.Headers.Add("Sec-Fetch-Mode", "cors");
|
||||||
|
request.Headers.Add("Sec-Fetch-Site", "same-origin");
|
||||||
|
|
||||||
|
// Chrome-specific headers
|
||||||
|
request.Headers.Add("sec-ch-ua", "\"Google Chrome\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"");
|
||||||
|
request.Headers.Add("sec-ch-ua-mobile", "?0");
|
||||||
|
request.Headers.Add("sec-ch-ua-platform", "\"Windows\"");
|
||||||
|
|
||||||
|
// XMLHttpRequest identifier (FONDAMENTALE per API AJAX)
|
||||||
|
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
|
||||||
|
|
||||||
|
// Referer (importante per validazione origin)
|
||||||
|
if (!string.IsNullOrEmpty(referer))
|
||||||
|
{
|
||||||
|
request.Headers.Add("Referer", referer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request.Headers.Add("Referer", "https://it.bidoo.com/");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("[HEADERS] Browser-like headers added (anti-bot)", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Estrae CSRF/Bid token dalla pagina asta
|
||||||
|
/// PASSO 1: Ottenere la pagina HTML dell'asta per estrarre il token di sicurezza
|
||||||
|
/// Il token può essere chiamato: bid_token, csrf_token, _token, etc.
|
||||||
|
/// </summary>
|
||||||
|
private async Task<(string? tokenName, string? tokenValue)> ExtractBidTokenAsync(string auctionId, string? auctionUrl = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = !string.IsNullOrEmpty(auctionUrl) ? auctionUrl : $"https://it.bidoo.com/asta/nome-prodotto-{auctionId}";
|
||||||
|
Log($"[TOKEN] GET {url}", auctionId);
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
AddAuthHeaders(request, url, auctionId);
|
||||||
|
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
var html = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
Log($"[TOKEN] Response: {response.StatusCode}, HTML length: {html.Length}", auctionId);
|
||||||
|
|
||||||
|
var patterns = new System.Collections.Generic.List<(string pattern, string name)>
|
||||||
|
{
|
||||||
|
// double-quoted input attributes
|
||||||
|
("(?i)<input[^>]*name=\"bid_token\"[^>]*value=\"([^\"]+)\"", "bid_token"),
|
||||||
|
("(?i)<input[^>]*value=\"([^\"]+)\"[^>]*name=\"bid_token\"", "bid_token"),
|
||||||
|
("(?i)<input[^>]*name=\"csrf_token\"[^>]*value=\"([^\"]+)\"", "csrf_token"),
|
||||||
|
("(?i)<input[^>]*value=\"([^\"]+)\"[^>]*name=\"csrf_token\"", "csrf_token"),
|
||||||
|
("(?i)<input[^>]*name=\"_token\"[^>]*value=\"([^\"]+)\"", "_token"),
|
||||||
|
("(?i)<input[^>]*name=\"token\"[^>]*value=\"([^\"]+)\"", "token"),
|
||||||
|
|
||||||
|
// single-quoted input attributes
|
||||||
|
("(?i)<input[^>]*name='bid_token'[^>]*value='([^']+)'", "bid_token"),
|
||||||
|
("(?i)<input[^>]*value='([^']+)'[^>]*name='bid_token'", "bid_token"),
|
||||||
|
("(?i)<input[^>]*name='csrf_token'[^>]*value='([^']+)'", "csrf_token"),
|
||||||
|
("(?i)<input[^>]*value='([^']+)'[^>]*name='csrf_token'", "csrf_token"),
|
||||||
|
("(?i)<input[^>]*name='_token'[^>]*value='([^']+)'", "_token"),
|
||||||
|
("(?i)<input[^>]*name='token'[^>]*value='([^']+)'", "token"),
|
||||||
|
|
||||||
|
// JavaScript style assignments (double and single quotes)
|
||||||
|
("(?i)bid_token\\s*[:=]\\s*\"([^\\\"]+)\"", "bid_token"),
|
||||||
|
("(?i)bid_token\\s*[:=]\\s*'([^']+)'", "bid_token"),
|
||||||
|
("(?i)csrf_token\\s*[:=]\\s*\"([^\\\"]+)\"", "csrf_token"),
|
||||||
|
("(?i)csrf_token\\s*[:=]\\s*'([^']+)'", "csrf_token"),
|
||||||
|
|
||||||
|
// JSON style
|
||||||
|
("\"token\"\\s*:\\s*\"([^\\\"]+)\"", "token")
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var pattern in patterns)
|
||||||
|
{
|
||||||
|
var match = System.Text.RegularExpressions.Regex.Match(html, pattern.pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
var tokenValue = match.Groups[1].Value;
|
||||||
|
Log($"[TOKEN] ✓ Token found: {pattern.name} = {tokenValue.Substring(0, Math.Min(20, tokenValue.Length))}...", auctionId);
|
||||||
|
return (pattern.name, tokenValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("[TOKEN] ⚠ No bid token found in HTML", auctionId);
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log($"[TOKEN ERROR] {ex.Message}", auctionId);
|
||||||
|
return (null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<(string? tokenName, string? tokenValue)> ExtractBidTokenAsync(string auctionId)
|
||||||
|
{
|
||||||
|
return ExtractBidTokenAsync(auctionId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuctionState?> PollAuctionStateAsync(string auctionId, string? auctionUrl, CancellationToken token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
|
var url = $"https://it.bidoo.com/data.php?ALL={auctionId}&LISTID=0";
|
||||||
|
|
||||||
|
Log($"[API REQUEST] GET {url}", auctionId);
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
|
||||||
|
var referer = !string.IsNullOrEmpty(auctionUrl)
|
||||||
|
? auctionUrl
|
||||||
|
: $"https://it.bidoo.com/auction.php?a=asta_{auctionId}";
|
||||||
|
|
||||||
|
Log($"[API REQUEST] Using referer: {referer}", auctionId);
|
||||||
|
AddAuthHeaders(request, referer, auctionId);
|
||||||
|
|
||||||
|
var response = await _httpClient.SendAsync(request, token);
|
||||||
|
var latency = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||||
|
|
||||||
|
Log($"[API RESPONSE] Status: {(int)response.StatusCode} {response.StatusCode}", auctionId);
|
||||||
|
Log($"[API RESPONSE] Latency: {latency}ms", auctionId);
|
||||||
|
Log($"[API RESPONSE] Content-Type: {response.Content.Headers.ContentType}", auctionId);
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
Log($"[API RESPONSE] Body ({responseText.Length} bytes): {responseText}", auctionId);
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Log($"[API ERROR] Non-success status code: {response.StatusCode}", auctionId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParsePollingResponse(auctionId, responseText, latency);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log($"[API EXCEPTION] Polling {auctionId}: {ex.GetType().Name} - {ex.Message}", auctionId);
|
||||||
|
Log($"[API EXCEPTION] StackTrace: {ex.StackTrace}", auctionId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuctionState? ParsePollingResponse(string auctionId, string response, int latency)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log($"[PARSE] Starting parse for auction {auctionId}", auctionId);
|
||||||
|
Log($"[PARSE] Raw response: {response}", auctionId);
|
||||||
|
|
||||||
|
// Step 1: Estrai Server Timestamp (può avere formato "timestamp*..." o "timestamp|flag*")
|
||||||
|
string serverTimestamp;
|
||||||
|
string mainData;
|
||||||
|
|
||||||
|
// Cerca il separatore '*' che divide timestamp da dati
|
||||||
|
var starIndex = response.IndexOf('*');
|
||||||
|
if (starIndex == -1)
|
||||||
|
{
|
||||||
|
Log("[PARSE ERROR] No '*' separator found in response", auctionId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timestampPart = response.Substring(0, starIndex);
|
||||||
|
mainData = response.Substring(starIndex + 1);
|
||||||
|
|
||||||
|
// Il timestamp può contenere '|' (es: "1761120002|1")
|
||||||
|
// Prendiamo solo la prima parte numerica
|
||||||
|
if (timestampPart.Contains('|'))
|
||||||
|
{
|
||||||
|
serverTimestamp = timestampPart.Split('|')[0];
|
||||||
|
Log($"[PARSE] Extended format detected: {timestampPart}", auctionId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serverTimestamp = timestampPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log($"[PARSE] Server Timestamp: {serverTimestamp}", auctionId);
|
||||||
|
Log($"[PARSE] Main Data: {mainData}", auctionId);
|
||||||
|
|
||||||
|
// Step 2: Estrai dati asta tra parentesi quadre [...]
|
||||||
|
var bracketStart = mainData.IndexOf('[');
|
||||||
|
var bracketEnd = mainData.IndexOf(']');
|
||||||
|
|
||||||
|
if (bracketStart == -1 || bracketEnd == -1)
|
||||||
|
{
|
||||||
|
Log("[PARSE ERROR] Missing brackets in auction data", auctionId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var auctionData = mainData.Substring(bracketStart + 1, bracketEnd - bracketStart - 1);
|
||||||
|
Log($"[PARSE] Auction Data extracted: {auctionData}", auctionId);
|
||||||
|
|
||||||
|
// Step 3: Split per ';' per ottenere i campi principali
|
||||||
|
// Nota: la stringa può contenere '|' per separare bid history, quindi ci fermiamo al primo '|' o ','
|
||||||
|
var firstSeparator = auctionData.IndexOfAny(new[] { '|', ',' });
|
||||||
|
var coreData = firstSeparator > 0 ? auctionData.Substring(0, firstSeparator) : auctionData;
|
||||||
|
|
||||||
|
var fields = coreData.Split(';');
|
||||||
|
Log($"[PARSE] Core fields count: {fields.Length}", auctionId);
|
||||||
|
for (int i = 0; i < Math.Min(fields.Length, 10); i++)
|
||||||
|
{
|
||||||
|
Log($"[PARSE] Field[{i}] = '{fields[i]}'", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.Length < 5)
|
||||||
|
{
|
||||||
|
Log($"[PARSE ERROR] Expected at least 5 core fields, got {fields.Length}", auctionId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var state = new AuctionState
|
||||||
|
{
|
||||||
|
AuctionId = auctionId,
|
||||||
|
SnapshotTime = DateTime.UtcNow,
|
||||||
|
PollingLatencyMs = latency
|
||||||
|
};
|
||||||
|
|
||||||
|
// Step 4: Parse campi principali
|
||||||
|
|
||||||
|
// Field 0: AuctionID (verifica)
|
||||||
|
Log($"[PARSE] Auction ID from response: {fields[0]} (expected: {auctionId})", auctionId);
|
||||||
|
|
||||||
|
// Field 1: Status (ON/OFF)
|
||||||
|
var status = fields[1].Trim().ToUpperInvariant();
|
||||||
|
|
||||||
|
// Determiniamo lo stato in base a: Status API + LastBidder + Timer
|
||||||
|
// Parsing di Field 4 (LastBidder) anticipato per logica stato
|
||||||
|
string lastBidder = fields[4].Trim();
|
||||||
|
bool hasWinner = !string.IsNullOrEmpty(lastBidder);
|
||||||
|
bool iAmWinner = hasWinner && lastBidder.Equals(_session.Username, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
state.Status = DetermineAuctionStatus(status, hasWinner, iAmWinner, ref state);
|
||||||
|
|
||||||
|
Log($"[PARSE] Status: {status} -> {state.Status}", auctionId);
|
||||||
|
|
||||||
|
// Field 2: Expiry Timestamp (CRITICO per timing)
|
||||||
|
// IMPORTANTE: Usa il ServerTimestamp dalla risposta, NON il tempo locale!
|
||||||
|
// Formato: ServerTimestamp*[..;ExpiryTimestamp;..]
|
||||||
|
// Timer = ExpiryTimestamp - ServerTimestamp
|
||||||
|
if (long.TryParse(serverTimestamp, out var serverTs) && long.TryParse(fields[2], out var expiryTs))
|
||||||
|
{
|
||||||
|
// Calcolo corretto usando il tempo del server
|
||||||
|
var timerSeconds = (double)(expiryTs - serverTs);
|
||||||
|
state.Timer = Math.Max(0, timerSeconds);
|
||||||
|
|
||||||
|
Log($"[PARSE] Server Timestamp: {serverTs}", auctionId);
|
||||||
|
Log($"[PARSE] Expiry Timestamp: {expiryTs}", auctionId);
|
||||||
|
Log($"[PARSE] Timer (Expiry - Server): {expiryTs} - {serverTs} = {timerSeconds:F2}s", auctionId);
|
||||||
|
Log($"[PARSE] ⏱️ Final Timer: {state.Timer:F2}s", auctionId);
|
||||||
|
|
||||||
|
// DEBUG: Verifica se il timer sembra sbagliato
|
||||||
|
if (state.Timer > 60)
|
||||||
|
{
|
||||||
|
Log("[PARSE WARN] Timer unusually high! Check data", auctionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"[PARSE WARN] Failed to parse timestamps - Server: {serverTimestamp}, Expiry: {fields[2]}", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field 3: Price Index (0.01 EUR per index)
|
||||||
|
if (int.TryParse(fields[3], out var priceIndex))
|
||||||
|
{
|
||||||
|
state.Price = priceIndex * 0.01;
|
||||||
|
Log($"[PARSE] Price Index: {priceIndex} -> €{state.Price:F2}", auctionId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log($"[PARSE WARN] Failed to parse price index: {fields[3]}", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field 4: Last Bidder
|
||||||
|
state.LastBidder = fields[4].Trim();
|
||||||
|
state.IsMyBid = !string.IsNullOrEmpty(_session.Username) &&
|
||||||
|
state.LastBidder.Equals(_session.Username, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
Log($"[PARSE] 👤 Last Bidder: {state.LastBidder}", auctionId);
|
||||||
|
Log($"[PARSE] Is My Bid: {state.IsMyBid} (my username: {_session.Username})", auctionId);
|
||||||
|
|
||||||
|
// Field 5 (optional): Additional flags or data
|
||||||
|
if (fields.Length > 5)
|
||||||
|
{
|
||||||
|
Log($"[PARSE] Additional data fields present: {fields.Length - 5}", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.ParsingSuccess = true;
|
||||||
|
|
||||||
|
Log($"[PARSE SUCCESS] ✓ Timer: {state.Timer:F2}s, Price: €{state.Price:F2}, Bidder: {state.LastBidder}, Status: {state.Status}", auctionId);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log($"[PARSE EXCEPTION] {ex.GetType().Name}: {ex.Message}", auctionId);
|
||||||
|
Log($"[PARSE EXCEPTION] StackTrace: {ex.StackTrace}", auctionId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> UpdateUserInfoAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = "https://it.bidoo.com/ajax/get_auction_bids_info_banner.php";
|
||||||
|
|
||||||
|
Log($"[USER INFO REQUEST] GET {url}");
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
AddAuthHeaders(request, "https://it.bidoo.com/");
|
||||||
|
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
var latency = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||||
|
|
||||||
|
Log($"[USER INFO RESPONSE] Status: {(int)response.StatusCode} {response.StatusCode}");
|
||||||
|
Log($"[USER INFO RESPONSE] Latency: {latency}ms");
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
Log($"[USER INFO RESPONSE] Body: {responseText}");
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Log($"[USER INFO ERROR] HTTP {response.StatusCode}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_session.LastAccountUpdate = DateTime.UtcNow;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log($"[USER INFO EXCEPTION] {ex.GetType().Name}: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<BidResult> PlaceBidAsync(string auctionId, string? auctionUrl = null)
|
||||||
|
{
|
||||||
|
var result = new BidResult
|
||||||
|
{
|
||||||
|
AuctionId = auctionId,
|
||||||
|
Timestamp = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log($"[BID] Placing bid via direct GET to bid.php (no token)", auctionId);
|
||||||
|
|
||||||
|
var url = "https://it.bidoo.com/bid.php";
|
||||||
|
var payload = $"AID={WebUtility.UrlEncode(auctionId)}&sup=0&shock=0";
|
||||||
|
|
||||||
|
Log($"[BID REQUEST] GET {url}?{payload}", auctionId);
|
||||||
|
|
||||||
|
var getUrl = url + "?" + payload;
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, getUrl);
|
||||||
|
|
||||||
|
var referer = !string.IsNullOrEmpty(auctionUrl) ? auctionUrl : $"https://it.bidoo.com/asta/nome-prodotto-{auctionId}";
|
||||||
|
AddAuthHeaders(request, referer, auctionId);
|
||||||
|
if (!request.Headers.Contains("Origin"))
|
||||||
|
{
|
||||||
|
request.Headers.Add("Origin", "https://it.bidoo.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
|
var response = await _httpClient.SendAsync(request);
|
||||||
|
result.LatencyMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||||
|
|
||||||
|
Log($"[BID RESPONSE] Status: {(int)response.StatusCode} {response.StatusCode}", auctionId);
|
||||||
|
Log($"[BID RESPONSE] Latency: {result.LatencyMs}ms", auctionId);
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
result.Response = responseText;
|
||||||
|
|
||||||
|
Log($"[BID RESPONSE] Body ({responseText.Length} bytes): {responseText}", auctionId);
|
||||||
|
|
||||||
|
if (responseText.StartsWith("ok", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Success = true;
|
||||||
|
var parts = responseText.Split('|');
|
||||||
|
if (parts.Length > 1 && double.TryParse(parts[1], out var priceIndex))
|
||||||
|
{
|
||||||
|
result.NewPrice = priceIndex * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log("[BID SUCCESS] ✓ Bid placed successfully via GET", auctionId);
|
||||||
|
}
|
||||||
|
else if (responseText.StartsWith("error", StringComparison.OrdinalIgnoreCase) || responseText.StartsWith("no|", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
var parts = responseText.Split('|');
|
||||||
|
result.Error = parts.Length > 1 ? parts[1] : responseText;
|
||||||
|
Log($"[BID ERROR] Server returned error: {result.Error}", auctionId);
|
||||||
|
}
|
||||||
|
else if (responseText.Contains("alive"))
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
result.Error = "Keep-alive response (not a bid response)";
|
||||||
|
Log($"[BID WARN] Received keep-alive instead of bid confirmation", auctionId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
result.Error = string.IsNullOrEmpty(responseText) ? $"HTTP {(int)response.StatusCode}" : responseText;
|
||||||
|
Log($"[BID ERROR] Unexpected response format: {result.Error}", auctionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
result.Success = false;
|
||||||
|
result.Error = ex.Message;
|
||||||
|
Log($"[BID EXCEPTION] {ex.GetType().Name}: {ex.Message}", auctionId);
|
||||||
|
Log($"[BID EXCEPTION] StackTrace: {ex.StackTrace}", auctionId);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determina lo stato dell'asta basandosi su Status, LastBidder, Timer
|
||||||
|
///
|
||||||
|
/// STATI API BIDOO:
|
||||||
|
/// - ON: Asta attiva e in corso
|
||||||
|
/// - OFF: Asta terminata definitivamente
|
||||||
|
/// - STOP: Asta in pausa (tipicamente 00:00-10:00) - riprenderà più tardi
|
||||||
|
/// </summary>
|
||||||
|
private AuctionStatus DetermineAuctionStatus(string apiStatus, bool hasWinner, bool iAmWinner, ref AuctionState state)
|
||||||
|
{
|
||||||
|
// Gestione stato STOP (pausa notturna)
|
||||||
|
if (apiStatus == "STOP")
|
||||||
|
{
|
||||||
|
// L'asta è iniziata ma è in pausa
|
||||||
|
// Controlla se c'è già un vincitore temporaneo
|
||||||
|
if (hasWinner)
|
||||||
|
{
|
||||||
|
state.LastBidder = state.LastBidder; // Mantieni il last bidder
|
||||||
|
return AuctionStatus.Paused;
|
||||||
|
}
|
||||||
|
// Pausa senza puntate ancora
|
||||||
|
return AuctionStatus.Paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiStatus == "OFF")
|
||||||
|
{
|
||||||
|
// Asta terminata definitivamente
|
||||||
|
if (hasWinner)
|
||||||
|
{
|
||||||
|
return iAmWinner ? AuctionStatus.EndedWon : AuctionStatus.EndedLost;
|
||||||
|
}
|
||||||
|
return AuctionStatus.Closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiStatus == "ON")
|
||||||
|
{
|
||||||
|
// Asta attiva
|
||||||
|
if (hasWinner)
|
||||||
|
{
|
||||||
|
// Ci sono già puntate → Running
|
||||||
|
return AuctionStatus.Running;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nessuna puntata ancora → Pending o Scheduled
|
||||||
|
// Se timer molto alto (> 30 minuti), è programmata per più tardi
|
||||||
|
if (state.Timer > 1800) // 30 minuti
|
||||||
|
{
|
||||||
|
return AuctionStatus.Scheduled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Altrimenti sta per iniziare
|
||||||
|
return AuctionStatus.Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuctionStatus.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BidooSession GetSession() => _session;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_httpClient?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using AutoBidder.Models;
|
||||||
|
|
||||||
|
namespace AutoBidder.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gestore persistenza sessione Bidoo
|
||||||
|
/// Salva in modo sicuro il cookie di autenticazione per riutilizzo
|
||||||
|
/// </summary>
|
||||||
|
public class SessionManager
|
||||||
|
{
|
||||||
|
private static readonly string SessionFilePath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"AutoBidder",
|
||||||
|
"session.dat"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("AutoBidder_V1_2025");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva la sessione in modo sicuro (crittografata con DPAPI)
|
||||||
|
/// </summary>
|
||||||
|
public static bool SaveSession(BidooSession session)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Crea directory se non esiste
|
||||||
|
var directory = Path.GetDirectoryName(SessionFilePath);
|
||||||
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializza sessione in JSON
|
||||||
|
var json = JsonSerializer.Serialize(session, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cripta usando DPAPI (Windows Data Protection API)
|
||||||
|
var plainBytes = Encoding.UTF8.GetBytes(json);
|
||||||
|
var encryptedBytes = ProtectedData.Protect(plainBytes, Entropy, DataProtectionScope.CurrentUser);
|
||||||
|
|
||||||
|
// Salva su file
|
||||||
|
File.WriteAllBytes(SessionFilePath, encryptedBytes);
|
||||||
|
|
||||||
|
Console.WriteLine($"[SESSION] Saved to: {SessionFilePath}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[SESSION ERROR] Failed to save: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Carica la sessione salvata (decripta con DPAPI)
|
||||||
|
/// </summary>
|
||||||
|
public static BidooSession? LoadSession()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(SessionFilePath))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[SESSION] No saved session found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leggi file crittografato
|
||||||
|
var encryptedBytes = File.ReadAllBytes(SessionFilePath);
|
||||||
|
|
||||||
|
// Decripta usando DPAPI
|
||||||
|
var plainBytes = ProtectedData.Unprotect(encryptedBytes, Entropy, DataProtectionScope.CurrentUser);
|
||||||
|
var json = Encoding.UTF8.GetString(plainBytes);
|
||||||
|
|
||||||
|
// Deserializza JSON
|
||||||
|
var session = JsonSerializer.Deserialize<BidooSession>(json);
|
||||||
|
|
||||||
|
if (session != null && session.IsValid)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[SESSION] Loaded from: {SessionFilePath}");
|
||||||
|
Console.WriteLine($"[SESSION] Username: {session.Username}");
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"[SESSION] Loaded session is invalid");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[SESSION ERROR] Failed to load: {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Elimina la sessione salvata
|
||||||
|
/// </summary>
|
||||||
|
public static bool ClearSession()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(SessionFilePath))
|
||||||
|
{
|
||||||
|
File.Delete(SessionFilePath);
|
||||||
|
Console.WriteLine($"[SESSION] Cleared: {SessionFilePath}");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[SESSION ERROR] Failed to clear: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifica se esiste una sessione salvata
|
||||||
|
/// </summary>
|
||||||
|
public static bool HasSavedSession()
|
||||||
|
{
|
||||||
|
return File.Exists(SessionFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ottiene informazioni sulla sessione salvata senza caricarla
|
||||||
|
/// </summary>
|
||||||
|
public static (bool exists, DateTime? lastModified) GetSessionInfo()
|
||||||
|
{
|
||||||
|
if (File.Exists(SessionFilePath))
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(SessionFilePath);
|
||||||
|
return (true, fileInfo.LastWriteTime);
|
||||||
|
}
|
||||||
|
return (false, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AutoBidder.Tests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Test manuale delle API Bidoo
|
||||||
|
/// Compilare e eseguire per testare le chiamate
|
||||||
|
/// </summary>
|
||||||
|
public class TestBidooApi
|
||||||
|
{
|
||||||
|
public static async Task RunAsync(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== TEST MANUALE API BIDOO ===\n");
|
||||||
|
|
||||||
|
// CONFIGURAZIONE
|
||||||
|
Console.Write("Inserisci il cookie __stattr: ");
|
||||||
|
string? cookie = Console.ReadLine();
|
||||||
|
|
||||||
|
Console.Write("Inserisci l'ID asta (es: 81417915): ");
|
||||||
|
string? auctionId = Console.ReadLine();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(cookie) || string.IsNullOrWhiteSpace(auctionId))
|
||||||
|
{
|
||||||
|
Console.WriteLine("? Cookie o Auction ID mancanti!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("\n--- Test 1: Polling Stato Asta ---");
|
||||||
|
await TestPollingAsync(cookie, auctionId);
|
||||||
|
|
||||||
|
Console.WriteLine("\n--- Test 2: Info Utente ---");
|
||||||
|
await TestUserInfoAsync(cookie);
|
||||||
|
|
||||||
|
Console.WriteLine("? Test completati! Premi un tasto per uscire...");
|
||||||
|
Console.ReadKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test chiamata polling asta
|
||||||
|
/// </summary>
|
||||||
|
private static async Task TestPollingAsync(string cookie, string auctionId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler { UseCookies = false };
|
||||||
|
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(5) };
|
||||||
|
|
||||||
|
var url = $"https://it.bidoo.com/data.php?ALL={auctionId}&LISTID=0";
|
||||||
|
Console.WriteLine($"?? GET {url}");
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
request.Headers.Add("Cookie", $"__stattr={cookie}");
|
||||||
|
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
|
||||||
|
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
request.Headers.Add("Referer", $"https://it.bidoo.com/asta/nome-prodotto-{auctionId}");
|
||||||
|
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
|
var response = await client.SendAsync(request);
|
||||||
|
var latency = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||||
|
|
||||||
|
Console.WriteLine($"?? Status: {(int)response.StatusCode} {response.StatusCode}");
|
||||||
|
Console.WriteLine($"?? Latency: {latency}ms");
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
Console.WriteLine($"?? Response ({responseText.Length} bytes):");
|
||||||
|
Console.WriteLine(responseText);
|
||||||
|
|
||||||
|
// Parse semplice
|
||||||
|
if (response.IsSuccessStatusCode && responseText.Contains("*"))
|
||||||
|
{
|
||||||
|
Console.WriteLine("\n?? Parsing:");
|
||||||
|
var parts = responseText.Split('*');
|
||||||
|
Console.WriteLine($" Server Time: {parts[0]}");
|
||||||
|
|
||||||
|
if (parts.Length > 1)
|
||||||
|
{
|
||||||
|
var data = parts[1].Replace("[", "").Replace("]", "").Split(';');
|
||||||
|
if (data.Length >= 5)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Auction ID: {data[0]}");
|
||||||
|
Console.WriteLine($" Status: {data[1]}");
|
||||||
|
Console.WriteLine($" Expiry: {data[2]}");
|
||||||
|
|
||||||
|
if (int.TryParse(data[3], out var priceIndex))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Price: {priceIndex} ? €{(priceIndex * 0.01):F2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($" Last Bidder: {data[4]}");
|
||||||
|
|
||||||
|
// Calcola timer
|
||||||
|
if (long.TryParse(data[2], out var expiryTs))
|
||||||
|
{
|
||||||
|
var expiryTime = DateTimeOffset.FromUnixTimeSeconds(expiryTs);
|
||||||
|
var timer = (expiryTime - DateTimeOffset.UtcNow).TotalSeconds;
|
||||||
|
Console.WriteLine($" Timer: {Math.Max(0, timer):F2}s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("?? Risposta non valida o errore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"? Errore: {ex.GetType().Name} - {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Test chiamata info utente
|
||||||
|
/// </summary>
|
||||||
|
private static async Task TestUserInfoAsync(string cookie)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var handler = new HttpClientHandler { UseCookies = false };
|
||||||
|
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(5) };
|
||||||
|
|
||||||
|
var url = "https://it.bidoo.com/ajax/get_auction_bids_info_banner.php";
|
||||||
|
Console.WriteLine($"?? GET {url}");
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
request.Headers.Add("Cookie", $"__stattr={cookie}");
|
||||||
|
request.Headers.Add("X-Requested-With", "XMLHttpRequest");
|
||||||
|
request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
request.Headers.Add("Referer", "https://it.bidoo.com/");
|
||||||
|
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
|
var response = await client.SendAsync(request);
|
||||||
|
var latency = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||||
|
|
||||||
|
Console.WriteLine($"?? Status: {(int)response.StatusCode} {response.StatusCode}");
|
||||||
|
Console.WriteLine($"?? Latency: {latency}ms");
|
||||||
|
|
||||||
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
Console.WriteLine($"?? Response ({responseText.Length} bytes):");
|
||||||
|
Console.WriteLine(responseText);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"? Errore: {ex.GetType().Name} - {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using AutoBidder.Models;
|
||||||
|
|
||||||
|
namespace AutoBidder.Utilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Esporta statistiche aste in formato CSV
|
||||||
|
/// </summary>
|
||||||
|
public static class CsvExporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Esporta cronologia completa di un'asta in CSV
|
||||||
|
/// </summary>
|
||||||
|
public static void ExportAuctionHistory(AuctionInfo auction, string filePath)
|
||||||
|
{
|
||||||
|
var csv = new StringBuilder();
|
||||||
|
|
||||||
|
// Header
|
||||||
|
csv.AppendLine("Timestamp,Event Type,Bidder,Price,Timer,Latency (ms),Success,Notes");
|
||||||
|
|
||||||
|
// Data
|
||||||
|
foreach (var entry in auction.BidHistory.OrderBy(h => h.Timestamp))
|
||||||
|
{
|
||||||
|
csv.AppendLine($"{entry.Timestamp:yyyy-MM-dd HH:mm:ss.fff}," +
|
||||||
|
$"{entry.EventType}," +
|
||||||
|
$"\"{entry.Bidder}\"," +
|
||||||
|
$"{entry.Price:F2}," +
|
||||||
|
$"{entry.Timer:F2}," +
|
||||||
|
$"{entry.LatencyMs}," +
|
||||||
|
$"{entry.Success}," +
|
||||||
|
$"\"{entry.Notes}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(filePath, csv.ToString(), Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Esporta statistiche aggregate di un'asta in CSV
|
||||||
|
/// </summary>
|
||||||
|
public static void ExportAuctionStatistics(AuctionInfo auction, string filePath)
|
||||||
|
{
|
||||||
|
var stats = AuctionStatistics.Calculate(auction);
|
||||||
|
var csv = new StringBuilder();
|
||||||
|
|
||||||
|
// Informazioni asta
|
||||||
|
csv.AppendLine("=== AUCTION INFO ===");
|
||||||
|
csv.AppendLine($"Auction ID,{stats.AuctionId}");
|
||||||
|
csv.AppendLine($"Name,\"{stats.Name}\"");
|
||||||
|
csv.AppendLine($"Monitoring Started,{stats.MonitoringStarted:yyyy-MM-dd HH:mm:ss}");
|
||||||
|
csv.AppendLine($"Monitoring Duration,{stats.MonitoringDuration}");
|
||||||
|
csv.AppendLine();
|
||||||
|
|
||||||
|
// Contatori
|
||||||
|
csv.AppendLine("=== COUNTERS ===");
|
||||||
|
csv.AppendLine($"Total Bids,{stats.TotalBids}");
|
||||||
|
csv.AppendLine($"My Bids,{stats.MyBids}");
|
||||||
|
csv.AppendLine($"Opponent Bids,{stats.OpponentBids}");
|
||||||
|
csv.AppendLine($"Resets,{stats.Resets}");
|
||||||
|
csv.AppendLine($"Unique Bidders,{stats.UniqueBidders}");
|
||||||
|
csv.AppendLine();
|
||||||
|
|
||||||
|
// Prezzi
|
||||||
|
csv.AppendLine("=== PRICES ===");
|
||||||
|
csv.AppendLine($"Start Price,{stats.StartPrice:F2}");
|
||||||
|
csv.AppendLine($"Current Price,{stats.CurrentPrice:F2}");
|
||||||
|
csv.AppendLine($"Min Price,{stats.MinPrice:F2}");
|
||||||
|
csv.AppendLine($"Max Price,{stats.MaxPrice:F2}");
|
||||||
|
csv.AppendLine($"Avg Price,{stats.AvgPrice:F2}");
|
||||||
|
csv.AppendLine();
|
||||||
|
|
||||||
|
// Performance
|
||||||
|
csv.AppendLine("=== PERFORMANCE ===");
|
||||||
|
csv.AppendLine($"Avg Click Latency (ms),{stats.AvgClickLatencyMs}");
|
||||||
|
csv.AppendLine($"Min Click Latency (ms),{stats.MinClickLatencyMs}");
|
||||||
|
csv.AppendLine($"Max Click Latency (ms),{stats.MaxClickLatencyMs}");
|
||||||
|
csv.AppendLine($"Bids Per Minute,{stats.BidsPerMinute:F2}");
|
||||||
|
csv.AppendLine($"Resets Per Hour,{stats.ResetsPerHour:F2}");
|
||||||
|
csv.AppendLine($"My Bid Success Rate,{stats.MyBidSuccessRate:F1}%");
|
||||||
|
csv.AppendLine();
|
||||||
|
|
||||||
|
// Competitor ranking
|
||||||
|
csv.AppendLine("=== BIDDER RANKING ===");
|
||||||
|
csv.AppendLine("Bidder,Bids Count");
|
||||||
|
foreach (var bidder in stats.BidderRanking.OrderByDescending(b => b.Value))
|
||||||
|
{
|
||||||
|
csv.AppendLine($"\"{bidder.Key}\",{bidder.Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(filePath, csv.ToString(), Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Esporta tutte le aste in un unico CSV
|
||||||
|
/// </summary>
|
||||||
|
public static void ExportAllAuctions(IEnumerable<AuctionInfo> auctions, string filePath)
|
||||||
|
{
|
||||||
|
var csv = new StringBuilder();
|
||||||
|
|
||||||
|
// Header
|
||||||
|
csv.AppendLine("Auction ID,Name,Timer Click,Delay (ms),Min Price,Max Price," +
|
||||||
|
"My Clicks,Resets,Total Bidders,Active,Paused," +
|
||||||
|
"Added At,Last Click At");
|
||||||
|
|
||||||
|
// Data
|
||||||
|
foreach (var auction in auctions)
|
||||||
|
{
|
||||||
|
csv.AppendLine($"{auction.AuctionId}," +
|
||||||
|
$"\"{auction.Name}\"," +
|
||||||
|
$"{auction.TimerClick}," +
|
||||||
|
$"{auction.DelayMs}," +
|
||||||
|
$"{auction.MinPrice:F2}," +
|
||||||
|
$"{auction.MaxPrice:F2}," +
|
||||||
|
$"{auction.MyClicks}," +
|
||||||
|
$"{auction.ResetCount}," +
|
||||||
|
$"{auction.Bidders.Count}," +
|
||||||
|
$"{auction.IsActive}," +
|
||||||
|
$"{auction.IsPaused}," +
|
||||||
|
$"{auction.AddedAt:yyyy-MM-dd HH:mm:ss}," +
|
||||||
|
$"{(auction.LastClickAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "")}");
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(filePath, csv.ToString(), Encoding.UTF8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using AutoBidder.Models;
|
||||||
|
|
||||||
|
namespace AutoBidder.Utilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gestisce salvataggio/caricamento lista aste
|
||||||
|
/// </summary>
|
||||||
|
public static class PersistenceManager
|
||||||
|
{
|
||||||
|
private static readonly string AppDataFolder = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"AutoBidder"
|
||||||
|
);
|
||||||
|
|
||||||
|
private static readonly string AuctionsFilePath = Path.Combine(AppDataFolder, "auctions.json");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Salva lista aste su disco
|
||||||
|
/// </summary>
|
||||||
|
public static void SaveAuctions(IEnumerable<AuctionInfo> auctions)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Crea cartella se non esiste
|
||||||
|
if (!Directory.Exists(AppDataFolder))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(AppDataFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializza in JSON
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = JsonSerializer.Serialize(auctions, options);
|
||||||
|
File.WriteAllText(AuctionsFilePath, json);
|
||||||
|
|
||||||
|
Console.WriteLine($"? Aste salvate in {AuctionsFilePath}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"? Errore salvataggio aste: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Carica lista aste da disco
|
||||||
|
/// </summary>
|
||||||
|
public static List<AuctionInfo> LoadAuctions()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(AuctionsFilePath))
|
||||||
|
{
|
||||||
|
return new List<AuctionInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var json = File.ReadAllText(AuctionsFilePath);
|
||||||
|
var auctions = JsonSerializer.Deserialize<List<AuctionInfo>>(json);
|
||||||
|
|
||||||
|
Console.WriteLine($"? Caricate {auctions?.Count ?? 0} aste da {AuctionsFilePath}");
|
||||||
|
|
||||||
|
return auctions ?? new List<AuctionInfo>();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"? Errore caricamento aste: {ex.Message}");
|
||||||
|
return new List<AuctionInfo>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using AutoBidder.Models;
|
||||||
|
|
||||||
|
namespace AutoBidder.ViewModels
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ViewModel per una riga della griglia aste (DataBinding)
|
||||||
|
/// </summary>
|
||||||
|
public class AuctionViewModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private readonly AuctionInfo _auctionInfo;
|
||||||
|
private AuctionState? _lastState;
|
||||||
|
|
||||||
|
public AuctionViewModel(AuctionInfo auctionInfo)
|
||||||
|
{
|
||||||
|
_auctionInfo = auctionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuctionInfo AuctionInfo => _auctionInfo;
|
||||||
|
|
||||||
|
// Proprietà base
|
||||||
|
public string AuctionId => _auctionInfo.AuctionId;
|
||||||
|
public string Name => _auctionInfo.Name;
|
||||||
|
|
||||||
|
// Configurazione
|
||||||
|
public int TimerClick
|
||||||
|
{
|
||||||
|
get => _auctionInfo.TimerClick;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_auctionInfo.TimerClick = value;
|
||||||
|
OnPropertyChanged(nameof(TimerClick));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int DelayMs
|
||||||
|
{
|
||||||
|
get => _auctionInfo.DelayMs;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_auctionInfo.DelayMs = value;
|
||||||
|
OnPropertyChanged(nameof(DelayMs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double MinPrice
|
||||||
|
{
|
||||||
|
get => _auctionInfo.MinPrice;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_auctionInfo.MinPrice = value;
|
||||||
|
OnPropertyChanged(nameof(MinPrice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double MaxPrice
|
||||||
|
{
|
||||||
|
get => _auctionInfo.MaxPrice;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_auctionInfo.MaxPrice = value;
|
||||||
|
OnPropertyChanged(nameof(MaxPrice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stato
|
||||||
|
public bool IsActive
|
||||||
|
{
|
||||||
|
get => _auctionInfo.IsActive;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_auctionInfo.IsActive = value;
|
||||||
|
OnPropertyChanged(nameof(IsActive));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPaused
|
||||||
|
{
|
||||||
|
get => _auctionInfo.IsPaused;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_auctionInfo.IsPaused = value;
|
||||||
|
OnPropertyChanged(nameof(IsPaused));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contatori
|
||||||
|
public int MyClicks => _auctionInfo.MyClicks;
|
||||||
|
public int ResetCount => _auctionInfo.ResetCount;
|
||||||
|
|
||||||
|
// Dati live (da ultimo polling)
|
||||||
|
public string TimerDisplay
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_lastState == null) return "-";
|
||||||
|
|
||||||
|
return _lastState.Status switch
|
||||||
|
{
|
||||||
|
AuctionStatus.EndedWon or AuctionStatus.EndedLost or AuctionStatus.Closed => "TERMINATA",
|
||||||
|
AuctionStatus.Paused => "IN PAUSA",
|
||||||
|
AuctionStatus.Pending => FormatPendingTime(_lastState.Timer),
|
||||||
|
AuctionStatus.Scheduled => FormatScheduledTime(_lastState.Timer),
|
||||||
|
AuctionStatus.Running when _lastState.Timer < 999 => $"{_lastState.Timer:F2}s",
|
||||||
|
AuctionStatus.Running when _lastState.Timer >= 999 => FormatLongTime(_lastState.Timer),
|
||||||
|
_ => "-"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatPendingTime(double seconds)
|
||||||
|
{
|
||||||
|
if (seconds < 60) return $"{seconds:F0}s";
|
||||||
|
int minutes = (int)(seconds / 60);
|
||||||
|
return $"{minutes}min";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatScheduledTime(double seconds)
|
||||||
|
{
|
||||||
|
if (seconds < 3600) // < 1 ora
|
||||||
|
{
|
||||||
|
int minutes = (int)(seconds / 60);
|
||||||
|
return $"{minutes}min";
|
||||||
|
}
|
||||||
|
int hours = (int)(seconds / 3600);
|
||||||
|
return $"{hours}h";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatLongTime(double seconds)
|
||||||
|
{
|
||||||
|
if (seconds < 3600) // < 1 ora
|
||||||
|
{
|
||||||
|
int minutes = (int)(seconds / 60);
|
||||||
|
return $"{minutes}min";
|
||||||
|
}
|
||||||
|
int hours = (int)(seconds / 3600);
|
||||||
|
return $"{hours}h";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PriceDisplay => _lastState != null && _lastState.Price > 0
|
||||||
|
? $"{_lastState.Price:F2}"
|
||||||
|
: "-";
|
||||||
|
|
||||||
|
public string LastBidder => _lastState?.LastBidder ?? "-";
|
||||||
|
|
||||||
|
public bool IsMyBid => _lastState?.IsMyBid ?? false;
|
||||||
|
|
||||||
|
public string StatusDisplay
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_lastState == null) return "Sconosciuto";
|
||||||
|
|
||||||
|
return _lastState.Status switch
|
||||||
|
{
|
||||||
|
AuctionStatus.Running => "In Corso",
|
||||||
|
AuctionStatus.EndedWon => "VINTA",
|
||||||
|
AuctionStatus.EndedLost => "Persa",
|
||||||
|
AuctionStatus.Pending => "Inizia presto",
|
||||||
|
AuctionStatus.Scheduled => "Programmata",
|
||||||
|
AuctionStatus.Paused => "In Pausa",
|
||||||
|
AuctionStatus.Closed => "Chiusa",
|
||||||
|
_ => "Sconosciuto"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Strategy
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_lastState == null) return "Idle";
|
||||||
|
|
||||||
|
// Gestione stati speciali
|
||||||
|
if (_lastState.Status == AuctionStatus.Pending)
|
||||||
|
return $"Inizia presto: {_lastState.StartTime}";
|
||||||
|
if (_lastState.Status == AuctionStatus.Scheduled)
|
||||||
|
return $"Programmata: {_lastState.StartTime}";
|
||||||
|
|
||||||
|
// Stati normali running
|
||||||
|
if (_lastState.Timer < 2) return "Active";
|
||||||
|
if (_lastState.Timer < 10) return "Fast";
|
||||||
|
if (_lastState.Timer < 30) return "HTTP";
|
||||||
|
return "Slow";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aggiorna stato da polling
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateState(AuctionState state)
|
||||||
|
{
|
||||||
|
_lastState = state;
|
||||||
|
|
||||||
|
// Notifica tutte le proprietà dipendenti dallo stato
|
||||||
|
OnPropertyChanged(nameof(TimerDisplay));
|
||||||
|
OnPropertyChanged(nameof(PriceDisplay));
|
||||||
|
OnPropertyChanged(nameof(LastBidder));
|
||||||
|
OnPropertyChanged(nameof(IsMyBid));
|
||||||
|
OnPropertyChanged(nameof(StatusDisplay));
|
||||||
|
OnPropertyChanged(nameof(Strategy));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notifica cambio contatori
|
||||||
|
/// </summary>
|
||||||
|
public void RefreshCounters()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(MyClicks));
|
||||||
|
OnPropertyChanged(nameof(ResetCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
|
protected void OnPropertyChanged(string propertyName)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
# ?? AutoBidder v2.1 - Riepilogo Modifiche
|
|
||||||
|
|
||||||
## ? Implementazione Completata
|
|
||||||
|
|
||||||
### ?? Nuova Funzionalità: Griglia Multi-Asta in Tempo Reale
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Interfaccia (MainWindow.xaml)
|
|
||||||
|
|
||||||
### Pannello Stats Riorganizzato
|
|
||||||
|
|
||||||
**Prima (v2.0):**
|
|
||||||
```
|
|
||||||
- Stats (Click, Reset, Prezzo)
|
|
||||||
- Multi-Click checkbox
|
|
||||||
- Pannello "Asta Attiva" (nome + contatore)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ora (v2.1):**
|
|
||||||
```
|
|
||||||
- Stats (Click, Reset)
|
|
||||||
- Prezzo (solo Asta Singola)
|
|
||||||
- Multi-Click checkbox
|
|
||||||
- GRIGLIA ASTE (solo Multi-Asta)
|
|
||||||
?? Header (Totale aste)
|
|
||||||
?? DataGrid con colonne:
|
|
||||||
?? Asta
|
|
||||||
?? Timer
|
|
||||||
?? Prezzo
|
|
||||||
?? Vincitore
|
|
||||||
?? Stato
|
|
||||||
```
|
|
||||||
|
|
||||||
### Elementi Aggiunti
|
|
||||||
|
|
||||||
1. **SingleAuctionPricePanel** (StackPanel)
|
|
||||||
- Visibile solo in modalità Asta Singola
|
|
||||||
- Contiene "Prezzo corrente: X€"
|
|
||||||
|
|
||||||
2. **MultiAuctionGridPanel** (Border)
|
|
||||||
- Visibile solo in modalità Multi-Asta
|
|
||||||
- Contiene griglia completa aste
|
|
||||||
|
|
||||||
3. **MultiAuctionsGrid** (DataGrid)
|
|
||||||
- AutoGenerateColumns = False
|
|
||||||
- MaxHeight = 200 (scrollabile)
|
|
||||||
- Colonne personalizzate con binding
|
|
||||||
|
|
||||||
4. **TotalAuctionsText** (TextBlock)
|
|
||||||
- Mostra numero totale aste monitorate
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Code-Behind (MainWindow.xaml.cs)
|
|
||||||
|
|
||||||
### Nuove Classi
|
|
||||||
|
|
||||||
#### 1. AuctionDisplayModel
|
|
||||||
```csharp
|
|
||||||
class AuctionDisplayModel : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
// Proprietà con notifica cambio
|
|
||||||
string AuctionId
|
|
||||||
string Name
|
|
||||||
double Timer ? TimerDisplay (es: "2.3s")
|
|
||||||
string Price ? PriceDisplay (es: "15.50€")
|
|
||||||
string Bidder
|
|
||||||
string Status ? StatusDisplay (??/?/??)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Scopo:** Modello dati per binding DataGrid con aggiornamento automatico UI
|
|
||||||
|
|
||||||
#### 2. AuctionInfo (Aggiornata)
|
|
||||||
```csharp
|
|
||||||
class AuctionInfo
|
|
||||||
{
|
|
||||||
// Esistenti
|
|
||||||
string AuctionId, Name, PriceElementId,
|
|
||||||
TimerElementId, BidderElementId, ButtonId
|
|
||||||
double LastKnownTimer
|
|
||||||
string LastKnownBidder
|
|
||||||
|
|
||||||
// NUOVI
|
|
||||||
bool IsActive // Per gestione on/off (futura)
|
|
||||||
bool IsPaused // Per pausa individuale (futura)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nuove Variabili
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// Collection ObservableCollection per binding griglia
|
|
||||||
private readonly ObservableCollection<AuctionDisplayModel> _auctionDisplayList = new();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nuovi Metodi
|
|
||||||
|
|
||||||
#### 1. UpdateMultiAuctionGrid(List<AuctionState>)
|
|
||||||
```csharp
|
|
||||||
// Aggiorna griglia in tempo reale
|
|
||||||
// - Aggiunge nuove aste
|
|
||||||
// - Aggiorna timer/prezzo/bidder/stato
|
|
||||||
// - Rimuove aste non più nei preferiti
|
|
||||||
```
|
|
||||||
|
|
||||||
**Chiamato:** Ogni ciclo di polling (20-400ms)
|
|
||||||
|
|
||||||
**Comportamento:**
|
|
||||||
- Se asta nuova ? Aggiungi a _auctionDisplayList
|
|
||||||
- Se asta esistente ? Aggiorna proprietà (trigger INotifyPropertyChanged)
|
|
||||||
- Se asta rimossa dai preferiti ? Rimuovi da lista
|
|
||||||
|
|
||||||
#### 2. UpdateModeButtons() (Modificato)
|
|
||||||
```csharp
|
|
||||||
// Ora gestisce visibilità pannelli
|
|
||||||
if (Multi-Asta):
|
|
||||||
MultiAuctionGridPanel.Visibility = Visible
|
|
||||||
SingleAuctionPricePanel.Visibility = Collapsed
|
|
||||||
else:
|
|
||||||
MultiAuctionGridPanel.Visibility = Collapsed
|
|
||||||
SingleAuctionPricePanel.Visibility = Visible
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. UpdateActiveAuctionDisplay() (Semplificato)
|
|
||||||
```csharp
|
|
||||||
// Ora aggiorna solo TotalAuctionsText
|
|
||||||
// (non più nome asta attiva, visibile nella griglia)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Metodi Modificati
|
|
||||||
|
|
||||||
#### MultiAuctionLoop()
|
|
||||||
```csharp
|
|
||||||
// Aggiunto dopo ReadAllAuctionStates():
|
|
||||||
UpdateMultiAuctionGrid(auctionStates);
|
|
||||||
|
|
||||||
// Rimosso:
|
|
||||||
// SetCurrentPriceText() - ora nella griglia
|
|
||||||
// Logica prezzo/bidder individuale - ora in UpdateMultiAuctionGrid
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Flusso Operativo Aggiornato
|
|
||||||
|
|
||||||
### v2.0 (Vecchio)
|
|
||||||
```
|
|
||||||
1. Scansiona preferiti
|
|
||||||
2. Leggi stati aste
|
|
||||||
3. Seleziona asta prioritaria
|
|
||||||
4. Aggiorna "Asta Attiva" (nome)
|
|
||||||
5. Aggiorna prezzo singolo
|
|
||||||
6. Aggiorna bidder singolo
|
|
||||||
7. Click se necessario
|
|
||||||
```
|
|
||||||
|
|
||||||
### v2.1 (Nuovo)
|
|
||||||
```
|
|
||||||
1. Scansiona preferiti
|
|
||||||
2. Leggi stati aste
|
|
||||||
3. ? AGGIORNA GRIGLIA (tutte le aste)
|
|
||||||
4. Seleziona asta prioritaria
|
|
||||||
5. Log focus asta
|
|
||||||
6. Click se necessario
|
|
||||||
```
|
|
||||||
|
|
||||||
**Differenza chiave:** Aggiornamento **simultaneo** di tutte le aste invece che focus su una sola.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Struttura Dati Griglia
|
|
||||||
|
|
||||||
### DataGrid Columns
|
|
||||||
|
|
||||||
| Header | Binding | Converter | Width |
|
|
||||||
|--------|---------|-----------|-------|
|
|
||||||
| Asta | `{Binding Name}` | - | 2* |
|
|
||||||
| Timer | `{Binding TimerDisplay}` | `F1 + "s"` | 70 |
|
|
||||||
| Prezzo | `{Binding PriceDisplay}` | `+ "€"` | 80 |
|
|
||||||
| Vincitore | `{Binding Bidder}` | - | * |
|
|
||||||
| Stato | `{Binding StatusDisplay}` | Emoji | 90 |
|
|
||||||
|
|
||||||
### Logica Stato
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
Status = Timer < 3 ? "active" : "waiting"
|
|
||||||
|
|
||||||
StatusDisplay:
|
|
||||||
- "active" ? "?? Attiva"
|
|
||||||
- "paused" ? "?? Pausa"
|
|
||||||
- "waiting" ? "? Attesa"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Vantaggi Implementazione
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
| Aspetto | v2.0 | v2.1 | Miglioramento |
|
|
||||||
|---------|------|------|---------------|
|
|
||||||
| **Update UI** | Ogni asta | Batch griglia | +70% velocità |
|
|
||||||
| **Visibilità** | 1 asta | N aste | ? |
|
|
||||||
| **Comprensione** | Nome text | Griglia completa | ????? |
|
|
||||||
| **Polling** | Uguale | Uguale | = |
|
|
||||||
|
|
||||||
### User Experience
|
|
||||||
|
|
||||||
- ? **Vede tutte le aste** contemporaneamente
|
|
||||||
- ? **Timer in tempo reale** per ogni asta
|
|
||||||
- ? **Prezzo aggiornato** per ogni asta
|
|
||||||
- ? **Vincitore corrente** per ogni asta
|
|
||||||
- ? **Stato visuale** (emoji ??/?)
|
|
||||||
- ? **Log invariato** per eventi dettagliati
|
|
||||||
- ? **Elenco utenti invariato** per statistiche
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Compatibilità
|
|
||||||
|
|
||||||
### Modalità Asta Singola
|
|
||||||
- ? **Invariata al 100%**
|
|
||||||
- ? Mostra "Prezzo corrente" come prima
|
|
||||||
- ? Log e stats uguali
|
|
||||||
|
|
||||||
### Modalità Multi-Asta
|
|
||||||
- ? **Griglia aggiunta** senza rimuovere funzionalità
|
|
||||||
- ? Log ancora disponibile
|
|
||||||
- ? Elenco utenti ancora disponibile
|
|
||||||
- ? Stats globali ancora visibili
|
|
||||||
|
|
||||||
### Retrocompatibilità
|
|
||||||
- ? Configurazioni esistenti funzionano
|
|
||||||
- ? Nessuna breaking change
|
|
||||||
- ? Switch modalità senza restart
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
**Modifiche:**
|
|
||||||
1. Sostituito "ActiveAuctionPanel" con "MultiAuctionGridPanel"
|
|
||||||
2. Aggiunto "SingleAuctionPricePanel" (visibile solo Asta Singola)
|
|
||||||
3. Aggiunto DataGrid "MultiAuctionsGrid" con 5 colonne
|
|
||||||
4. Aggiunto "TotalAuctionsText" per contatore aste
|
|
||||||
|
|
||||||
**Righe totali:** +60 righe XAML
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
**Modifiche:**
|
|
||||||
1. Aggiunta classe `AuctionDisplayModel` (INotifyPropertyChanged)
|
|
||||||
2. Aggiornata classe `AuctionInfo` (IsActive, IsPaused)
|
|
||||||
3. Aggiunta variabile `_auctionDisplayList` (ObservableCollection)
|
|
||||||
4. Aggiunto metodo `UpdateMultiAuctionGrid()`
|
|
||||||
5. Modificato `UpdateModeButtons()` per gestire pannelli
|
|
||||||
6. Modificato `MultiAuctionLoop()` per chiamare UpdateMultiAuctionGrid
|
|
||||||
7. Uso `FindName()` per elementi dinamici (fix compilazione)
|
|
||||||
|
|
||||||
**Righe totali:** +80 righe C#
|
|
||||||
|
|
||||||
### Nuovi File Creati
|
|
||||||
1. **MULTI_AUCTION_GRID_GUIDE.md** (Guida completa griglia)
|
|
||||||
2. **v2.1_CHANGES.md** (Questo file)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Testing Completato
|
|
||||||
|
|
||||||
### Build
|
|
||||||
- ? Compilazione senza errori
|
|
||||||
- ? Nessun warning critico
|
|
||||||
- ? XAML validato
|
|
||||||
- ? Binding DataGrid corretto
|
|
||||||
|
|
||||||
### Funzionalità
|
|
||||||
- ? Switch modalità funziona
|
|
||||||
- ? Griglia appare in Multi-Asta
|
|
||||||
- ? Griglia nascosta in Asta Singola
|
|
||||||
- ? ObservableCollection binding corretto
|
|
||||||
- ? INotifyPropertyChanged trigger UI
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi (Testing Utente)
|
|
||||||
|
|
||||||
### Da Verificare
|
|
||||||
1. **Griglia popolata correttamente** con aste reali
|
|
||||||
2. **Timer si aggiornano** in tempo reale
|
|
||||||
3. **Prezzo cambia** quando qualcuno punta
|
|
||||||
4. **Vincitore aggiornato** correttamente
|
|
||||||
5. **Stato emoji** (??/?) funziona
|
|
||||||
6. **Performance** con 5-10 aste
|
|
||||||
|
|
||||||
### Se Problemi
|
|
||||||
1. Controlla log per errori JavaScript
|
|
||||||
2. Verifica URL preferiti: `https://it.bidoo.com/?tab=FAV`
|
|
||||||
3. Ricarica pagina se griglia vuota
|
|
||||||
4. Controlla che aste siano nei preferiti (?)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Roadmap v2.2 (Futura)
|
|
||||||
|
|
||||||
### Feature Pianificate
|
|
||||||
- [ ] **Impostazioni per asta** (Timer, limiti individuali)
|
|
||||||
- [ ] **Pause per asta** (Pulsante ?? nella griglia)
|
|
||||||
- [ ] **Click manuale** (Forza click su asta specifica)
|
|
||||||
- [ ] **Colori personalizzati** (Soglie timer/prezzo)
|
|
||||||
- [ ] **Ordinamento griglia** (Per timer, prezzo, nome)
|
|
||||||
- [ ] **Context menu** (Click destro su riga per azioni)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Checklist Implementazione
|
|
||||||
|
|
||||||
### Completato
|
|
||||||
- [x] Classe `AuctionDisplayModel` con INotifyPropertyChanged
|
|
||||||
- [x] ObservableCollection `_auctionDisplayList`
|
|
||||||
- [x] DataGrid con 5 colonne
|
|
||||||
- [x] Binding proprietà (Name, Timer, Price, Bidder, Status)
|
|
||||||
- [x] Converter display (TimerDisplay, PriceDisplay, StatusDisplay)
|
|
||||||
- [x] Metodo `UpdateMultiAuctionGrid()`
|
|
||||||
- [x] Visibilità pannelli (Single/Multi)
|
|
||||||
- [x] Integrazione in `MultiAuctionLoop()`
|
|
||||||
- [x] Documentazione completa (MULTI_AUCTION_GRID_GUIDE.md)
|
|
||||||
- [x] Build senza errori
|
|
||||||
|
|
||||||
### Non Implementato (Out of Scope v2.1)
|
|
||||||
- [ ] Impostazioni individuali per asta
|
|
||||||
- [ ] Pulsanti azioni in griglia (? ? ??)
|
|
||||||
- [ ] Context menu click destro
|
|
||||||
- [ ] Ordinamento colonne
|
|
||||||
- [ ] Filtri griglia
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
### Obiettivo Raggiunto
|
|
||||||
? **Griglia Multi-Asta in tempo reale completamente funzionale**
|
|
||||||
|
|
||||||
### Risultato
|
|
||||||
Gli utenti ora possono:
|
|
||||||
- ??? **Vedere** tutte le aste simultaneamente
|
|
||||||
- ?? **Monitorare** timer in tempo reale per ogni asta
|
|
||||||
- ?? **Tracciare** prezzi e vincitori aggiornati
|
|
||||||
- ?? **Capire** quale asta è prioritaria (?? Attiva)
|
|
||||||
- ?? **Analizzare** dati completi senza perdere informazioni
|
|
||||||
|
|
||||||
### Prossimo Step
|
|
||||||
**Testing utente finale** con aste reali su Bidoo!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.1 - Grid-Based Multi-Auction Monitoring*
|
|
||||||
*Implementato con successo! ??*
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# ?? AutoBidder v2.1 - Grid Multi-Asta
|
|
||||||
|
|
||||||
## ?? Novità: Griglia Aste in Tempo Reale
|
|
||||||
|
|
||||||
Ora puoi vedere **tutte le aste simultaneamente** in una griglia aggiornata in tempo reale!
|
|
||||||
|
|
||||||
### Prima (v2.0)
|
|
||||||
```
|
|
||||||
Asta Attiva: Galaxy S25 512GB
|
|
||||||
Aste monitorate: 3
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ora (v2.1)
|
|
||||||
```
|
|
||||||
??????????????????????????????????????????????????
|
|
||||||
? Asta Timer Prezzo Stato ?
|
|
||||||
? Galaxy S25 512GB 2.3s 15.50€ ?? Attiva ?
|
|
||||||
? RTX 5080 5.1s 45.20€ ? Attesa ?
|
|
||||||
? MacBook Pro 8.0s 120.00€ ? Attesa ?
|
|
||||||
??????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
## ? Caratteristiche
|
|
||||||
|
|
||||||
- ? **Tutte le aste visibili** contemporaneamente
|
|
||||||
- ? **Timer in tempo reale** per ogni asta (20-400ms)
|
|
||||||
- ? **Prezzo aggiornato** automaticamente
|
|
||||||
- ? **Vincitore corrente** per ogni asta
|
|
||||||
- ? **Stato visuale** (?? Attiva / ? Attesa)
|
|
||||||
- ? **Log ed elenco utenti** invariati
|
|
||||||
|
|
||||||
## ?? Come Usare
|
|
||||||
|
|
||||||
1. Aggiungi aste ai **Preferiti** su Bidoo (?)
|
|
||||||
2. Clicca **[Multi-Asta]** in AutoBidder
|
|
||||||
3. Attendi 5s per scansione
|
|
||||||
4. Osserva la **griglia popolarsi**
|
|
||||||
5. Clicca **[Avvia]**
|
|
||||||
6. Monitora tutto in tempo reale!
|
|
||||||
|
|
||||||
## ?? Documentazione
|
|
||||||
|
|
||||||
- **Guida Griglia**: [MULTI_AUCTION_GRID_GUIDE.md](MULTI_AUCTION_GRID_GUIDE.md)
|
|
||||||
- **Modifiche v2.1**: [v2.1_CHANGES.md](v2.1_CHANGES.md)
|
|
||||||
- **Riepilogo**: [v2.1_SUMMARY.md](v2.1_SUMMARY.md)
|
|
||||||
|
|
||||||
## ?? Vantaggi
|
|
||||||
|
|
||||||
| Aspetto | v2.0 | v2.1 |
|
|
||||||
|---------|------|------|
|
|
||||||
| Visibilità | 1 asta | Tutte |
|
|
||||||
| Info real-time | Limitata | Completa |
|
|
||||||
| Comprensione | "Su cosa punta?" | "Vedo tutto!" |
|
|
||||||
|
|
||||||
**Vedi tutto. Capisci tutto. Vinci di più.** ??
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.1 - Grid-Based Multi-Auction Monitoring*
|
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
# ? AutoBidder v2.1 - Implementazione Completata!
|
|
||||||
|
|
||||||
## ?? Modifiche Implementate con Successo
|
|
||||||
|
|
||||||
Hai richiesto di vedere **tutte le aste simultaneamente in una griglia** invece di una per volta. Ho implementato questa funzionalità mantenendo log ed elenco utenti invariati.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Cosa È Stato Fatto
|
|
||||||
|
|
||||||
### 1. Nuova Griglia Multi-Asta
|
|
||||||
|
|
||||||
**Interfaccia:**
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????????
|
|
||||||
? ?? Aste Monitorate Totale: 3 ?
|
|
||||||
???????????????????????????????????????????????????????????
|
|
||||||
? Asta Timer Prezzo Vincitore Stato ?
|
|
||||||
? Galaxy S25 512GB 2.3s 15.50€ user123 ?? Attiva ?
|
|
||||||
? RTX 5080 5.1s 45.20€ user456 ? Attesa ?
|
|
||||||
? MacBook Pro 8.0s 120.00€ user789 ? Attesa ?
|
|
||||||
???????????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Caratteristiche:**
|
|
||||||
- ? Tutte le aste visibili contemporaneamente
|
|
||||||
- ? Timer in tempo reale per ogni asta
|
|
||||||
- ? Prezzo aggiornato automaticamente
|
|
||||||
- ? Vincitore corrente per ogni asta
|
|
||||||
- ? Stato visuale (?? Attiva / ? Attesa)
|
|
||||||
- ? Scrollabile se più di 6-7 aste
|
|
||||||
|
|
||||||
### 2. Log ed Elenco Utenti Invariati
|
|
||||||
|
|
||||||
**Mantenuto come prima:**
|
|
||||||
- ? Log operazioni completo e dettagliato
|
|
||||||
- ? Elenco utenti con contatore puntate
|
|
||||||
- ? Statistiche globali (Click, Reset)
|
|
||||||
- ? Pulsanti Pulisci per entrambi
|
|
||||||
|
|
||||||
### 3. Modalità Asta Singola Intatta
|
|
||||||
|
|
||||||
**Nessuna modifica:**
|
|
||||||
- ? Funziona esattamente come prima
|
|
||||||
- ? Mostra "Prezzo corrente" come sempre
|
|
||||||
- ? Stessa interfaccia e comportamento
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Funziona Ora
|
|
||||||
|
|
||||||
### Modalità Multi-Asta (NUOVO!)
|
|
||||||
|
|
||||||
1. **Scansione Preferiti**: Ogni 5s cerca aste nei preferiti
|
|
||||||
2. **Lettura Stati**: Legge timer, prezzo, vincitore di TUTTE le aste
|
|
||||||
3. **Aggiorna Griglia**: Popola/aggiorna DataGrid in tempo reale
|
|
||||||
4. **Selezione Priorità**: Identifica asta con timer più basso
|
|
||||||
5. **Evidenzia Asta Attiva**: Mostra ?? sull'asta prioritaria
|
|
||||||
6. **Click Automatico**: Punta sull'asta attiva al momento giusto
|
|
||||||
7. **Rotazione**: Passa alla prossima asta dopo il click
|
|
||||||
|
|
||||||
### Esempio Pratico
|
|
||||||
|
|
||||||
```
|
|
||||||
Situazione:
|
|
||||||
?? Galaxy S25 Timer: 8.0s Prezzo: 15€ ? ? Attesa
|
|
||||||
?? RTX 5080 Timer: 1.8s Prezzo: 45€ ? ?? Attiva (punta qui!)
|
|
||||||
?? MacBook Pro Timer: 5.3s Prezzo: 120€ ? ? Attesa
|
|
||||||
|
|
||||||
AutoBidder clicca su RTX 5080
|
|
||||||
|
|
||||||
Dopo click (RTX resettato):
|
|
||||||
?? Galaxy S25 Timer: 7.5s ? ? Attesa
|
|
||||||
?? RTX 5080 Timer: 8.0s ? ? Attesa (appena resettato)
|
|
||||||
?? MacBook Pro Timer: 4.8s ? ?? Attiva (nuovo target!)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Vantaggi Nuova Interfaccia
|
|
||||||
|
|
||||||
### Rispetto a v2.0 (Precedente)
|
|
||||||
|
|
||||||
| Cosa | Prima (v2.0) | Ora (v2.1) |
|
|
||||||
|------|-------------|-----------|
|
|
||||||
| **Visibilità aste** | Solo asta attiva | Tutte simultanee |
|
|
||||||
| **Informazioni** | Nome + timer + prezzo dell'asta attiva | Timer + prezzo + vincitore per TUTTE |
|
|
||||||
| **Comprensione** | Limitata ("su cosa sta puntando?") | Completa (vedi tutto) |
|
|
||||||
| **Controllo** | Cieco ("confido nell'algoritmo") | Visivo ("vedo cosa succede") |
|
|
||||||
| **Log/Utenti** | Invariati | Invariati ? |
|
|
||||||
|
|
||||||
### Cosa Puoi Fare Ora
|
|
||||||
|
|
||||||
? **Vedere** lo stato di tutte le aste in tempo reale
|
|
||||||
? **Capire** quale asta è prioritaria (?? Attiva)
|
|
||||||
? **Monitorare** timer, prezzi e vincitori simultaneamente
|
|
||||||
? **Tracciare** chi punta su quale asta (log + griglia)
|
|
||||||
? **Decidere** meglio quali aste aggiungere ai preferiti
|
|
||||||
? **Analizzare** performance e competizione
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Usare la Nuova Griglia
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
1. **Accedi a Bidoo** tramite AutoBidder
|
|
||||||
2. **Aggiungi ai Preferiti** (?) le aste interessanti
|
|
||||||
- Consiglio: 5-10 aste per performance ottimali
|
|
||||||
3. **Clicca [Multi-Asta]** in AutoBidder
|
|
||||||
- AutoBidder naviga a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
4. **Attendi 5 secondi** per scansione iniziale
|
|
||||||
|
|
||||||
### Configurazione
|
|
||||||
|
|
||||||
1. **Timer Click**: Imposta secondo del click (es: 0 o 1)
|
|
||||||
2. **Ritardo**: Delay aggiuntivo (es: 0-50ms)
|
|
||||||
3. **Min/Max Price**: Filtra aste per prezzo (opzionale)
|
|
||||||
4. **Max Clicks/Resets**: Limiti globali su tutte le aste
|
|
||||||
|
|
||||||
### Osservazione
|
|
||||||
|
|
||||||
1. **Guarda la griglia**:
|
|
||||||
- Timer si aggiornano ogni 20-400ms
|
|
||||||
- Prezzo cambia quando qualcuno punta
|
|
||||||
- Vincitore aggiornato in tempo reale
|
|
||||||
- Stato (??/?) indica priorità
|
|
||||||
|
|
||||||
2. **Monitora il Log**:
|
|
||||||
- Eventi dettagliati per ogni asta
|
|
||||||
- "?? Focus su: [Nome Asta]"
|
|
||||||
- "? Click #N su [Nome Asta]"
|
|
||||||
|
|
||||||
3. **Controlla Elenco Utenti**:
|
|
||||||
- Vedi chi punta di più
|
|
||||||
- Traccia competitor
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Dettagli Tecnici
|
|
||||||
|
|
||||||
### Nuove Classi
|
|
||||||
|
|
||||||
**AuctionDisplayModel** (INotifyPropertyChanged)
|
|
||||||
```csharp
|
|
||||||
- AuctionId, Name
|
|
||||||
- Timer ? TimerDisplay ("2.3s")
|
|
||||||
- Price ? PriceDisplay ("15.50€")
|
|
||||||
- Bidder
|
|
||||||
- Status ? StatusDisplay (??/?/??)
|
|
||||||
```
|
|
||||||
|
|
||||||
**AuctionInfo** (Aggiornata)
|
|
||||||
```csharp
|
|
||||||
+ bool IsActive // Per future impostazioni individuali
|
|
||||||
+ bool IsPaused // Per pausa per asta
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nuovi Metodi
|
|
||||||
|
|
||||||
**UpdateMultiAuctionGrid(states)**
|
|
||||||
- Aggiorna griglia in tempo reale
|
|
||||||
- Aggiunge nuove aste
|
|
||||||
- Rimuove aste eliminate dai preferiti
|
|
||||||
- Trigger INotifyPropertyChanged per UI
|
|
||||||
|
|
||||||
**UpdateModeButtons()** (Modificato)
|
|
||||||
- Gestisce visibilità pannelli
|
|
||||||
- Multi-Asta ? Mostra griglia
|
|
||||||
- Asta Singola ? Mostra prezzo
|
|
||||||
|
|
||||||
### DataGrid Columns
|
|
||||||
|
|
||||||
| Colonna | Binding | Descrizione |
|
|
||||||
|---------|---------|-------------|
|
|
||||||
| Asta | Name | Nome prodotto |
|
|
||||||
| Timer | TimerDisplay | Timer con "s" |
|
|
||||||
| Prezzo | PriceDisplay | Prezzo con "€" |
|
|
||||||
| Vincitore | Bidder | Utente corrente |
|
|
||||||
| Stato | StatusDisplay | ??/? emoji |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Creati/Modificati
|
|
||||||
|
|
||||||
### Modificati
|
|
||||||
1. **MainWindow.xaml**: Griglia + pannelli visibilità
|
|
||||||
2. **MainWindow.xaml.cs**: Classi, metodi, logica griglia
|
|
||||||
|
|
||||||
### Creati
|
|
||||||
1. **MULTI_AUCTION_GRID_GUIDE.md**: Guida completa utente
|
|
||||||
2. **v2.1_CHANGES.md**: Riepilogo tecnico modifiche
|
|
||||||
3. **v2.1_SUMMARY.md**: Questo file
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build e Testing
|
|
||||||
|
|
||||||
### Compilazione
|
|
||||||
- ? Build completato senza errori
|
|
||||||
- ? Nessun warning critico
|
|
||||||
- ? XAML validato correttamente
|
|
||||||
- ? Binding DataGrid funzionante
|
|
||||||
|
|
||||||
### Funzionalità Base Verificate
|
|
||||||
- ? Switch modalità funziona
|
|
||||||
- ? Griglia appare in Multi-Asta
|
|
||||||
- ? Griglia nascosta in Asta Singola
|
|
||||||
- ? ObservableCollection binding corretto
|
|
||||||
- ? Visibilità pannelli corretta
|
|
||||||
|
|
||||||
### Da Testare (Utente Finale)
|
|
||||||
- [ ] Griglia popolata con aste reali
|
|
||||||
- [ ] Timer si aggiornano in tempo reale
|
|
||||||
- [ ] Prezzo cambia correttamente
|
|
||||||
- [ ] Vincitore aggiornato
|
|
||||||
- [ ] Stato ??/? funziona
|
|
||||||
- [ ] Performance con 5-10 aste
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Immediate (Testing)
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Accedi a Bidoo
|
|
||||||
3. Aggiungi 3-5 aste ai preferiti (?)
|
|
||||||
4. Clicca [Multi-Asta]
|
|
||||||
5. Clicca [Avvia]
|
|
||||||
6. **Osserva la griglia** mentre si popola
|
|
||||||
7. Verifica aggiornamenti in tempo reale
|
|
||||||
|
|
||||||
### Se Problemi
|
|
||||||
- **Griglia vuota**: Verifica preferiti, attendi 5s, ricarica pagina
|
|
||||||
- **Timer non si aggiorna**: Ricarica pagina, controlla log errori
|
|
||||||
- **Asta non trovata**: Verifica URL `https://it.bidoo.com/?tab=FAV`
|
|
||||||
|
|
||||||
### Future (v2.2+)
|
|
||||||
- Impostazioni per asta (Timer, limiti individuali)
|
|
||||||
- Pulsanti azioni in griglia (? ? ??)
|
|
||||||
- Context menu click destro
|
|
||||||
- Ordinamento colonne
|
|
||||||
- Filtri avanzati
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Documentazione
|
|
||||||
|
|
||||||
### Guide Disponibili
|
|
||||||
|
|
||||||
1. **README.md**: Documentazione generale progetto
|
|
||||||
2. **MULTI_AUCTION_GUIDE.md**: Guida Multi-Asta originale (v2.0)
|
|
||||||
3. **MULTI_AUCTION_GRID_GUIDE.md**: Guida griglia (v2.1) ? NUOVO
|
|
||||||
4. **QUICK_REFERENCE.md**: Riferimento rapido
|
|
||||||
5. **v2.1_CHANGES.md**: Riepilogo tecnico modifiche
|
|
||||||
6. **v2.1_SUMMARY.md**: Questo file
|
|
||||||
|
|
||||||
### Quale Leggere?
|
|
||||||
|
|
||||||
- **Utente base**: QUICK_REFERENCE.md
|
|
||||||
- **Utente Multi-Asta**: MULTI_AUCTION_GRID_GUIDE.md ?
|
|
||||||
- **Sviluppatore**: v2.1_CHANGES.md
|
|
||||||
- **Panoramica generale**: README.md
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
### Obiettivo Completato
|
|
||||||
? **Griglia Multi-Asta in tempo reale implementata con successo!**
|
|
||||||
|
|
||||||
### Cosa Hai Ottenuto
|
|
||||||
|
|
||||||
**Prima (v2.0):**
|
|
||||||
- ? Multi-Asta funzionante
|
|
||||||
- ? Selezione automatica asta prioritaria
|
|
||||||
- ? Visione limitata (solo asta attiva)
|
|
||||||
|
|
||||||
**Ora (v2.1):**
|
|
||||||
- ? Multi-Asta funzionante
|
|
||||||
- ? Selezione automatica asta prioritaria
|
|
||||||
- ? **Griglia completa con TUTTE le aste** ?
|
|
||||||
- ? **Timer/Prezzo/Vincitore in tempo reale** ?
|
|
||||||
- ? **Stato visuale priorità** (??/?) ?
|
|
||||||
- ? Log ed Elenco Utenti invariati
|
|
||||||
|
|
||||||
### Il Risultato
|
|
||||||
|
|
||||||
Ora hai **visibilità completa** su tutte le aste monitorate senza perdere funzionalità di log e statistiche. Puoi:
|
|
||||||
|
|
||||||
- ??? Vedere tutto quello che succede
|
|
||||||
- ?? Capire dove AutoBidder sta puntando
|
|
||||||
- ?? Analizzare performance in tempo reale
|
|
||||||
- ?? Decidere meglio la strategia
|
|
||||||
- ?? Massimizzare le vincite
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Ready to Go!
|
|
||||||
|
|
||||||
**Il sistema è pronto per essere testato!**
|
|
||||||
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Vai su Bidoo
|
|
||||||
3. Aggiungi preferiti
|
|
||||||
4. Attiva Multi-Asta
|
|
||||||
5. Osserva la magia della griglia! ?
|
|
||||||
|
|
||||||
**Buone aste e buona fortuna!** ????
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.1 - Grid-Based Multi-Auction Monitoring*
|
|
||||||
*Developed with ?? for better auction visibility*
|
|
||||||
@@ -1,591 +0,0 @@
|
|||||||
# ?? AutoBidder v2.2 - Gestione Per-Asta Completa
|
|
||||||
|
|
||||||
## ? Implementazione Completata
|
|
||||||
|
|
||||||
### ?? Nuova Funzionalità: Gestione Completa Per-Asta con Dettagli Selezionabili
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Interfaccia (MainWindow.xaml)
|
|
||||||
|
|
||||||
### Nuova Architettura Pannelli
|
|
||||||
|
|
||||||
**v2.1 (Precedente):**
|
|
||||||
```
|
|
||||||
Left Panel:
|
|
||||||
?? Mode Buttons
|
|
||||||
?? Start/Pause/Stop
|
|
||||||
?? Stats Globali
|
|
||||||
?? Settings Globali (Asta Singola)
|
|
||||||
?? Griglia Aste (Multi-Asta) - altezza fissa
|
|
||||||
?? Bidders Globali
|
|
||||||
?? Log Globale
|
|
||||||
```
|
|
||||||
|
|
||||||
**v2.2 (Attuale):**
|
|
||||||
```
|
|
||||||
Left Panel:
|
|
||||||
?? Mode Buttons
|
|
||||||
?? Start/Pause/Stop
|
|
||||||
?? Stats Globali
|
|
||||||
?? CONTENUTO DINAMICO:
|
|
||||||
|
|
||||||
[ASTA SINGOLA]
|
|
||||||
?? Settings
|
|
||||||
?? Bidders
|
|
||||||
?? Log
|
|
||||||
|
|
||||||
[MULTI-ASTA]
|
|
||||||
?? Griglia Aste (RESIZABLE - Row 2*)
|
|
||||||
?? GridSplitter (6px)
|
|
||||||
?? Dettagli Asta Selezionata (Row 1*)
|
|
||||||
?? Nome Asta
|
|
||||||
?? Impostazioni (Timer, Min, Max)
|
|
||||||
?? Bidders Count
|
|
||||||
?? Log Specifico
|
|
||||||
```
|
|
||||||
|
|
||||||
### Elementi Aggiunti/Modificati
|
|
||||||
|
|
||||||
#### 1. Pannelli Dinamici
|
|
||||||
|
|
||||||
**SingleAuctionPanel** (Grid):
|
|
||||||
- Visibile solo in modalità Asta Singola
|
|
||||||
- Contiene: Settings, Bidders Grid, Log
|
|
||||||
- Invariato rispetto a v2.1
|
|
||||||
|
|
||||||
**MultiAuctionPanel** (Grid):
|
|
||||||
- Visibile solo in modalità Multi-Asta
|
|
||||||
- Struttura 3 righe:
|
|
||||||
- Row 0 (Height="2*" MinHeight="150"): Griglia Aste
|
|
||||||
- Row 1 (Height="6"): GridSplitter resizable
|
|
||||||
- Row 2 (Height="*" MinHeight="100"): Dettagli Asta Selezionata
|
|
||||||
|
|
||||||
#### 2. Griglia Aste Multi - Modificata
|
|
||||||
|
|
||||||
**Colonne aggiornate:**
|
|
||||||
| Colonna | Binding | Width | Descrizione |
|
|
||||||
|---------|---------|-------|-------------|
|
|
||||||
| Asta | Name | 2* | Nome prodotto |
|
|
||||||
| Timer | TimerDisplay | 60 | Timer real-time |
|
|
||||||
| Prezzo | PriceDisplay | 70 | Prezzo corrente |
|
|
||||||
| **Clicks** | **MyClicks** | **60** | **Click fatti da me su questa asta** ? |
|
|
||||||
| **Ultimo** | **LastBidder** | * | **Ultimo utente che ha puntato** ? |
|
|
||||||
| Stato | StatusDisplay | 80 | ??/? |
|
|
||||||
|
|
||||||
**Aggiunte:**
|
|
||||||
- `SelectionMode="Single"` ? Permette selezione singola asta
|
|
||||||
- `SelectionChanged="MultiAuctionsGrid_SelectionChanged"` ? Handler click
|
|
||||||
- `IsSelected` Trigger ? Evidenzia riga selezionata in blu (#1E40AF)
|
|
||||||
|
|
||||||
#### 3. Pannello Dettagli Asta Selezionata - NUOVO!
|
|
||||||
|
|
||||||
**Struttura:**
|
|
||||||
```xml
|
|
||||||
<Border Background="#0F1720" CornerRadius="6">
|
|
||||||
<Grid>
|
|
||||||
<!-- Header con nome asta -->
|
|
||||||
<Border Background="#1E293B">
|
|
||||||
<TextBlock x:Name="SelectedAuctionName" />
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Impostazioni PER-ASTA -->
|
|
||||||
<Grid> <!-- 3 colonne -->
|
|
||||||
<TextBox x:Name="SelectedTimerClick" />
|
|
||||||
<TextBox x:Name="SelectedMinPrice" />
|
|
||||||
<TextBox x:Name="SelectedMaxPrice" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- Bidders asta selezionata -->
|
|
||||||
<TextBlock x:Name="SelectedAuctionBiddersCount" />
|
|
||||||
|
|
||||||
<!-- Log asta selezionata -->
|
|
||||||
<TextBox x:Name="SelectedAuctionLog" IsReadOnly="True" />
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. GridSplitter Verticale
|
|
||||||
|
|
||||||
- **Height**: 6px
|
|
||||||
- **Cursor**: SizeNS
|
|
||||||
- **Funzione**: Ridimensiona griglia aste vs dettagli
|
|
||||||
- **Beneficio**: Più spazio per griglia se necessario, oppure per log se si vuole leggere meglio
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Code-Behind (MainWindow.xaml.cs)
|
|
||||||
|
|
||||||
### 1. AuctionDisplayModel - Classe Potenziata
|
|
||||||
|
|
||||||
**Proprietà aggiunte:**
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// Dati per griglia
|
|
||||||
public string LastBidder { get; set; } // Ultimo utente puntata (non più "Bidder" generico)
|
|
||||||
public int MyClicks { get; set; } // Contatore click fatti da ME su questa asta
|
|
||||||
|
|
||||||
// Impostazioni PER-ASTA
|
|
||||||
public int TimerClick { get; set; } = 0;
|
|
||||||
public double MinPrice { get; set; } = 0;
|
|
||||||
public double MaxPrice { get; set; } = 0;
|
|
||||||
|
|
||||||
// Dati PER-ASTA
|
|
||||||
public List<string> AuctionLog { get; set; } = new();
|
|
||||||
public Dictionary<string, int> AuctionBidders { get; set; } = new();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Binding aggiornati:**
|
|
||||||
- `Bidder` ? `LastBidder` (più chiaro)
|
|
||||||
- `TimerDisplay`, `PriceDisplay` ? Invariati
|
|
||||||
- `MyClicks` ? Nuovo binding
|
|
||||||
|
|
||||||
### 2. Nuove Variabili
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private AuctionDisplayModel? _selectedAuction = null;
|
|
||||||
```
|
|
||||||
|
|
||||||
Traccia l'asta attualmente selezionata dall'utente.
|
|
||||||
|
|
||||||
### 3. Nuovi Metodi
|
|
||||||
|
|
||||||
#### MultiAuctionsGrid_SelectionChanged
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private void MultiAuctionsGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
// Cattura selezione asta
|
|
||||||
// Aggiorna _selectedAuction
|
|
||||||
// Chiama UpdateSelectedAuctionDetails
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Quando:** Click su riga nella griglia
|
|
||||||
|
|
||||||
#### UpdateSelectedAuctionDetails
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private void UpdateSelectedAuctionDetails(AuctionDisplayModel auction)
|
|
||||||
{
|
|
||||||
// Aggiorna SelectedAuctionName
|
|
||||||
// Carica impostazioni (SelectedTimerClick, SelectedMinPrice, SelectedMaxPrice)
|
|
||||||
// Aggiorna SelectedAuctionBiddersCount
|
|
||||||
// Aggiorna SelectedAuctionLog
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Effetto:** Popola pannello dettagli con dati dell'asta selezionata
|
|
||||||
|
|
||||||
#### LogAuction
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private void LogAuction(AuctionDisplayModel auction, string message)
|
|
||||||
{
|
|
||||||
// Aggiunge entry a auction.AuctionLog
|
|
||||||
// Mantiene max 100 righe
|
|
||||||
// Se è asta selezionata ? Aggiorna UI log
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Beneficio:** Ogni asta ha il SUO log separato
|
|
||||||
|
|
||||||
#### Gestori Impostazioni Per-Asta
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private void SelectedTimerClick_TextChanged(object sender, TextChangedEventArgs e)
|
|
||||||
private void SelectedMinPrice_TextChanged(object sender, TextChangedEventArgs e)
|
|
||||||
private void SelectedMaxPrice_TextChanged(object sender, TextChangedEventArgs e)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Quando:** Utente cambia impostazioni nel pannello dettagli
|
|
||||||
**Effetto:** Aggiorna `_selectedAuction.TimerClick/MinPrice/MaxPrice`
|
|
||||||
**Log:** Aggiunge entry al log dell'asta
|
|
||||||
|
|
||||||
### 4. UpdateMultiAuctionGrid - Potenziata
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// Quando aggiunge nuova asta:
|
|
||||||
displayModel.MyClicks = 0;
|
|
||||||
displayModel.TimerClick = 0; // Default
|
|
||||||
displayModel.MinPrice = 0;
|
|
||||||
displayModel.MaxPrice = 0;
|
|
||||||
LogAuction(displayModel, "Asta aggiunta al monitoraggio");
|
|
||||||
|
|
||||||
// Quando rileva cambio bidder:
|
|
||||||
if (state.Bidder != displayModel.LastBidder)
|
|
||||||
{
|
|
||||||
displayModel.LastBidder = state.Bidder;
|
|
||||||
|
|
||||||
// Aggiorna dizionario bidders per asta
|
|
||||||
if (displayModel.AuctionBidders.ContainsKey(state.Bidder))
|
|
||||||
displayModel.AuctionBidders[state.Bidder]++;
|
|
||||||
else
|
|
||||||
displayModel.AuctionBidders[state.Bidder] = 1;
|
|
||||||
|
|
||||||
LogAuction(displayModel, $"?? Puntata di: {state.Bidder}");
|
|
||||||
|
|
||||||
// Se è asta selezionata ? aggiorna bidders count
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. MultiAuctionLoop - Usa Impostazioni Per-Asta
|
|
||||||
|
|
||||||
**Prima (v2.1):**
|
|
||||||
```csharp
|
|
||||||
// Usava impostazioni globali da ClickTimerBox, MinPriceBox, MaxPriceBox
|
|
||||||
int clickTimerValue = ClickTimerBox.Text;
|
|
||||||
double minPrice = MinPriceBox.Text;
|
|
||||||
double maxPrice = MaxPriceBox.Text;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ora (v2.2):**
|
|
||||||
```csharp
|
|
||||||
// Trova displayModel dell'asta target
|
|
||||||
var targetDisplayModel = _auctionDisplayList.FirstOrDefault(a => a.AuctionId == targetAuction.AuctionId);
|
|
||||||
|
|
||||||
// USA IMPOSTAZIONI PER-ASTA!
|
|
||||||
int clickTimerValue = targetDisplayModel?.TimerClick ?? 0;
|
|
||||||
double minPrice = targetDisplayModel?.MinPrice ?? 0.0;
|
|
||||||
double maxPrice = targetDisplayModel?.MaxPrice ?? 0.0;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Effetto:**
|
|
||||||
Ogni asta può avere Timer Click, Min Price, Max Price **diversi**!
|
|
||||||
|
|
||||||
**Quando click riuscito:**
|
|
||||||
```csharp
|
|
||||||
if (targetDisplayModel != null)
|
|
||||||
{
|
|
||||||
targetDisplayModel.MyClicks++; // ? Incrementa contatore
|
|
||||||
LogAuction(targetDisplayModel, $"? Click #{targetDisplayModel.MyClicks}");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Workflow Utente
|
|
||||||
|
|
||||||
### Modalità Multi-Asta v2.2
|
|
||||||
|
|
||||||
#### 1. Setup Iniziale
|
|
||||||
|
|
||||||
1. Aggiungi 5-10 aste ai Preferiti su Bidoo (?)
|
|
||||||
2. Clicca **[Multi-Asta]** in AutoBidder
|
|
||||||
3. Attendi 5s per scansione
|
|
||||||
4. La griglia si popola con le aste
|
|
||||||
|
|
||||||
#### 2. Configurazione Per-Asta
|
|
||||||
|
|
||||||
1. **Clicca su un'asta nella griglia**
|
|
||||||
2. Il pannello dettagli si popola:
|
|
||||||
```
|
|
||||||
?? Galaxy S25 512GB
|
|
||||||
|
|
||||||
Timer Click: [0] Min €: [10] Max €: [50]
|
|
||||||
|
|
||||||
Utenti su questa asta: 3
|
|
||||||
|
|
||||||
Log:
|
|
||||||
12:30:15 - Asta aggiunta al monitoraggio
|
|
||||||
12:30:20 - Timer Click cambiato: 1
|
|
||||||
12:30:25 - Min Price cambiato: 10€
|
|
||||||
12:30:30 - Max Price cambiato: 50€
|
|
||||||
12:31:05 - ?? Puntata di: user123
|
|
||||||
12:31:18 - ? Click #1 - Timer: 0.8s
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Modifica impostazioni**:
|
|
||||||
- Timer Click: `1` ? Punta quando timer = 1s
|
|
||||||
- Min Price: `10` ? Non puntare se prezzo < 10€
|
|
||||||
- Max Price: `50` ? Non puntare se prezzo > 50€
|
|
||||||
|
|
||||||
4. **Clicca su un'altra asta** per configurarla diversamente
|
|
||||||
|
|
||||||
#### 3. Esempio Configurazione Multi-Asta
|
|
||||||
|
|
||||||
```
|
|
||||||
?????????????????????????????????????????????????????????????
|
|
||||||
? Galaxy S25 2.3s 15€ 2 user123 ?? [SELEZIONATA] ?
|
|
||||||
? RTX 5080 5.1s 45€ 0 user456 ? ?
|
|
||||||
? MacBook Pro 8.0s 120€ 5 user789 ? ?
|
|
||||||
?????????????????????????????????????????????????????????????
|
|
||||||
|
|
||||||
?? Galaxy S25 512GB
|
|
||||||
Timer Click: [1] Min €: [10] Max €: [50]
|
|
||||||
Utenti: 3
|
|
||||||
|
|
||||||
Config:
|
|
||||||
- Timer = 1s ? Punta solo quando timer scende a 1s
|
|
||||||
- Min = 10€ ? Skippa se prezzo < 10€
|
|
||||||
- Max = 50€ ? Skippa se prezzo > 50€
|
|
||||||
```
|
|
||||||
|
|
||||||
**Altre aste:**
|
|
||||||
- RTX 5080: Timer=0, Min=20, Max=100 ? Configurazione diversa!
|
|
||||||
- MacBook Pro: Timer=0, Min=0, Max=200 ? Altra configurazione!
|
|
||||||
|
|
||||||
#### 4. Monitoraggio Real-Time
|
|
||||||
|
|
||||||
**Griglia aggiornata ogni 20-400ms:**
|
|
||||||
- Timer countdown per ogni asta
|
|
||||||
- Prezzo cambia quando qualcuno punta
|
|
||||||
- **Clicks** si incrementa quando TU punti
|
|
||||||
- **Ultimo** mostra chi ha puntato per ultimo
|
|
||||||
|
|
||||||
**Log per-asta:**
|
|
||||||
- Clicca su asta per vedere LOG SPECIFICO
|
|
||||||
- Eventi solo per quella asta
|
|
||||||
- Max 100 righe per asta
|
|
||||||
|
|
||||||
#### 5. Ridimensionamento
|
|
||||||
|
|
||||||
**Drag GridSplitter** (6px tra griglia e dettagli):
|
|
||||||
- **Su:** Più spazio griglia ? Vedi più aste
|
|
||||||
- **Giù:** Più spazio dettagli ? Leggi meglio log
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Vantaggi v2.2
|
|
||||||
|
|
||||||
### Rispetto a v2.1
|
|
||||||
|
|
||||||
| Aspetto | v2.1 | v2.2 | Miglioramento |
|
|
||||||
|---------|------|------|---------------|
|
|
||||||
| **Impostazioni** | Globali | Per-asta ? | ????? |
|
|
||||||
| **Visibilità click** | Solo totale | Per-asta ? | ????? |
|
|
||||||
| **Log** | Globale | Per-asta ? | ????? |
|
|
||||||
| **Bidders** | Globale | Per-asta ? | ???? |
|
|
||||||
| **Controllo** | Limitato | Completo ? | ????? |
|
|
||||||
| **Griglia** | Fissa | Resizable ? | ???? |
|
|
||||||
|
|
||||||
### Cosa Puoi Fare Ora (NUOVO!)
|
|
||||||
|
|
||||||
? **Configurare** ogni asta con impostazioni diverse
|
|
||||||
? **Vedere** quanti click hai fatto su ogni asta
|
|
||||||
? **Monitorare** log specifico per ogni asta
|
|
||||||
? **Tracciare** bidders per ogni asta separatamente
|
|
||||||
? **Ridimensionare** griglia vs dettagli dinamicamente
|
|
||||||
? **Switchare** tra aste per vedere dettagli diversi
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Dettagli Tecnici
|
|
||||||
|
|
||||||
### Flusso Dati Per-Asta
|
|
||||||
|
|
||||||
```
|
|
||||||
User Click su Griglia
|
|
||||||
?
|
|
||||||
MultiAuctionsGrid_SelectionChanged
|
|
||||||
?
|
|
||||||
_selectedAuction = auction
|
|
||||||
?
|
|
||||||
UpdateSelectedAuctionDetails
|
|
||||||
?
|
|
||||||
Carica: Nome, Impostazioni, Bidders Count, Log
|
|
||||||
?
|
|
||||||
User modifica impostazioni
|
|
||||||
?
|
|
||||||
SelectedTimerClick_TextChanged
|
|
||||||
?
|
|
||||||
_selectedAuction.TimerClick = value
|
|
||||||
?
|
|
||||||
LogAuction(_selectedAuction, "Timer cambiato")
|
|
||||||
?
|
|
||||||
Se asta ancora selezionata ? Aggiorna log UI
|
|
||||||
```
|
|
||||||
|
|
||||||
### Algoritmo Click Multi-Asta v2.2
|
|
||||||
|
|
||||||
```
|
|
||||||
Loop:
|
|
||||||
1. Scansiona aste nei preferiti
|
|
||||||
2. Leggi stati tutte le aste
|
|
||||||
3. Aggiorna griglia (timer, prezzo, bidders)
|
|
||||||
|
|
||||||
4. Trova asta con timer più basso
|
|
||||||
5. Recupera displayModel dell'asta
|
|
||||||
|
|
||||||
6. USA IMPOSTAZIONI PER-ASTA:
|
|
||||||
- clickTimerValue = displayModel.TimerClick
|
|
||||||
- minPrice = displayModel.MinPrice
|
|
||||||
- maxPrice = displayModel.MaxPrice
|
|
||||||
|
|
||||||
7. Se timer in range E prezzo OK:
|
|
||||||
- Click
|
|
||||||
- displayModel.MyClicks++
|
|
||||||
- LogAuction(displayModel, "Click #X")
|
|
||||||
- Aggiorna LastBidder
|
|
||||||
- Aggiorna AuctionBidders[user]++
|
|
||||||
|
|
||||||
8. Ripeti
|
|
||||||
```
|
|
||||||
|
|
||||||
### Sincronizzazione UI
|
|
||||||
|
|
||||||
**ObservableCollection + INotifyPropertyChanged:**
|
|
||||||
- Griglia si aggiorna automaticamente quando cambia `MyClicks`, `Timer`, `Price`, etc.
|
|
||||||
- Binding bidirezionale tra TextBox impostazioni e `_selectedAuction`
|
|
||||||
- Log aggiornato in tempo reale se asta è selezionata
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Strategie Avanzate Per-Asta
|
|
||||||
|
|
||||||
### Strategia "Diversificata"
|
|
||||||
|
|
||||||
```
|
|
||||||
Obiettivo: Massimizzare vincite su aste diverse con config ottimali
|
|
||||||
|
|
||||||
Galaxy S25:
|
|
||||||
- Timer: 1s (massima precisione)
|
|
||||||
- Min: 10€, Max: 50€ (range conveniente)
|
|
||||||
|
|
||||||
RTX 5080:
|
|
||||||
- Timer: 0s (ultra-aggressivo)
|
|
||||||
- Min: 20€, Max: 100€ (più permissivo)
|
|
||||||
|
|
||||||
MacBook Pro:
|
|
||||||
- Timer: 2s (meno competitivo)
|
|
||||||
- Min: 0€, Max: 200€ (tutto ok)
|
|
||||||
|
|
||||||
Risultato: Ogni asta ottimizzata individualmente!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategia "Focus Selettivo"
|
|
||||||
|
|
||||||
```
|
|
||||||
Obiettivo: Puntare solo su aste specifiche
|
|
||||||
|
|
||||||
Aste Prioritarie (Timer=0, Min=0, Max=100):
|
|
||||||
- iPhone 16
|
|
||||||
- Galaxy S25
|
|
||||||
|
|
||||||
Aste Opportunistiche (Timer=2, Min=50, Max=150):
|
|
||||||
- MacBook Pro
|
|
||||||
- iPad Pro
|
|
||||||
|
|
||||||
Risultato: Aste prioritarie ultra-aggressive, altre più conservative
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. Sostituito pannello statico con `SingleAuctionPanel` e `MultiAuctionPanel`
|
|
||||||
2. Aggiunto GridSplitter resizable verticale
|
|
||||||
3. Aggiunto pannello "Dettagli Asta Selezionata"
|
|
||||||
4. Modificate colonne griglia: `Bidder` ? `LastBidder`, aggiunto `MyClicks`
|
|
||||||
5. Aggiunto `SelectionChanged` handler alla griglia
|
|
||||||
|
|
||||||
**Righe totali:** +120 righe XAML
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. Aggiornata `AuctionDisplayModel` con nuove proprietà (6 nuove)
|
|
||||||
2. Aggiunta variabile `_selectedAuction`
|
|
||||||
3. Aggiunto metodo `MultiAuctionsGrid_SelectionChanged`
|
|
||||||
4. Aggiunto metodo `UpdateSelectedAuctionDetails`
|
|
||||||
5. Aggiunti 3 gestori cambio impostazioni per-asta
|
|
||||||
6. Aggiunto metodo `LogAuction`
|
|
||||||
7. Aggiornato `UpdateMultiAuctionGrid` per gestire bidders e log per-asta
|
|
||||||
8. Aggiornato `MultiAuctionLoop` per usare impostazioni per-asta e incrementare `MyClicks`
|
|
||||||
9. Aggiornato `UpdateModeButtons` per gestire `SingleAuctionPanel` e `MultiAuctionPanel`
|
|
||||||
|
|
||||||
**Righe totali:** +150 righe C#
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build e Testing
|
|
||||||
|
|
||||||
### Compilazione
|
|
||||||
|
|
||||||
```
|
|
||||||
? Build: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
? Binding: Corretto
|
|
||||||
? GridSplitter: Funzionante
|
|
||||||
```
|
|
||||||
|
|
||||||
### Funzionalità Verificate
|
|
||||||
|
|
||||||
- ? Switch modalità Singola/Multi
|
|
||||||
- ? Pannelli dinamici visibilità corretta
|
|
||||||
- ? Griglia popolata con aste
|
|
||||||
- ? Click su asta seleziona correttamente
|
|
||||||
- ? Dettagli asta caricati
|
|
||||||
- ? Impostazioni per-asta modificabili
|
|
||||||
- ? GridSplitter ridimensionabile
|
|
||||||
- ? Binding `MyClicks`, `LastBidder` corretti
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Testing Utente
|
|
||||||
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Clicca [Multi-Asta]
|
|
||||||
3. Aggiungi 3-5 aste ai preferiti
|
|
||||||
4. Attendi popolamento griglia
|
|
||||||
5. **Clicca su un'asta**
|
|
||||||
6. Verifica caricamento dettagli
|
|
||||||
7. Modifica impostazioni (Timer, Min, Max)
|
|
||||||
8. Clicca [Avvia]
|
|
||||||
9. Osserva:
|
|
||||||
- Clicks si incrementa per asta
|
|
||||||
- Log per-asta funziona
|
|
||||||
- Impostazioni per-asta applicate
|
|
||||||
|
|
||||||
### Se Problemi
|
|
||||||
|
|
||||||
- **Dettagli non caricano**: Riclicca sull'asta
|
|
||||||
- **Impostazioni non salvano**: Verifica formato numeri (0-8 per Timer, decimali con . per prezzi)
|
|
||||||
- **Log non si aggiorna**: Riseleziona asta
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
### Obiettivo v2.2 Raggiunto
|
|
||||||
|
|
||||||
? **Gestione completa per-asta implementata!**
|
|
||||||
|
|
||||||
### Risultato
|
|
||||||
|
|
||||||
**v2.1:**
|
|
||||||
- ? Griglia multi-asta
|
|
||||||
- ? Impostazioni globali
|
|
||||||
- ? Log globale
|
|
||||||
- ? Bidders globali
|
|
||||||
|
|
||||||
**v2.2:**
|
|
||||||
- ? Griglia multi-asta
|
|
||||||
- ? **Impostazioni PER-ASTA** ?
|
|
||||||
- ? **Log PER-ASTA** ?
|
|
||||||
- ? **Bidders PER-ASTA** ?
|
|
||||||
- ? **Clicks contati PER-ASTA** ?
|
|
||||||
- ? **Pannello dettagli selezionabile** ?
|
|
||||||
- ? **Griglia ridimensionabile** ?
|
|
||||||
|
|
||||||
### Prossimo Livello
|
|
||||||
|
|
||||||
Possibili future implementazioni (v2.3+):
|
|
||||||
- [ ] **Pulsanti azioni in griglia** (? Abilita, ? Pausa, ?? Config rapida)
|
|
||||||
- [ ] **Context menu click destro** (Elimina, Duplica config, etc.)
|
|
||||||
- [ ] **Ordinamento griglia** (Per timer, prezzo, clicks)
|
|
||||||
- [ ] **Filtri** (Solo attive, solo > X clicks, etc.)
|
|
||||||
- [ ] **Export config** (Salva impostazioni aste su file)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.2 - Per-Auction Complete Management*
|
|
||||||
*Controllo totale su ogni singola asta! ??*
|
|
||||||
@@ -1,521 +0,0 @@
|
|||||||
# ?? AutoBidder v2.3 - Multi-Auction Improvements
|
|
||||||
|
|
||||||
## ? Modifiche Implementate
|
|
||||||
|
|
||||||
### ?? Lista Richieste
|
|
||||||
|
|
||||||
1. ? **Rimossa colonna "Stato"** dalla griglia Multi-Asta
|
|
||||||
2. ? **Aumentato spazio** tra griglia e dettagli (GridSplitter da 6px a 12px + margin)
|
|
||||||
3. ? **Aggiunto pulsante Pausa** per singola asta
|
|
||||||
4. ? **Evidenziazione riga** quando punti tu (sfondo verde)
|
|
||||||
5. ? **Contatore Reset** per ogni asta
|
|
||||||
6. ? **Rimosso Multi-Click** dal Multi-Asta
|
|
||||||
7. ? **Nascoste statistiche globali** (Auto-click/Resets) in Multi-Asta
|
|
||||||
8. ? **Multi-Asta come default** all'avvio
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Interfaccia (XAML)
|
|
||||||
|
|
||||||
### 1. Griglia Multi-Asta - Nuove Colonne
|
|
||||||
|
|
||||||
**PRIMA (v2.2):**
|
|
||||||
```
|
|
||||||
| Asta | Timer | Prezzo | Clicks | Ultimo | Stato |
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.3):**
|
|
||||||
```
|
|
||||||
| Asta | Timer | Prezzo | Clicks | Resets | Ultimo |
|
|
||||||
```
|
|
||||||
|
|
||||||
**Cambiamenti:**
|
|
||||||
- ? Rimossa colonna "Stato" (non utile)
|
|
||||||
- ? Aggiunta colonna "Resets" (contatore per asta)
|
|
||||||
|
|
||||||
### 2. Evidenziazione Righe
|
|
||||||
|
|
||||||
**Nuovo Style Trigger:**
|
|
||||||
```xaml
|
|
||||||
<DataTrigger Binding="{Binding IsMyBid}" Value="True">
|
|
||||||
<Setter Property="Background" Value="#15803D" /> <!-- Verde scuro -->
|
|
||||||
<Setter Property="FontWeight" Value="Bold" />
|
|
||||||
</DataTrigger>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Effetto:**
|
|
||||||
- Quando punti su un'asta, la riga diventa **verde** e **grassetto**
|
|
||||||
- Si vede chiaramente su quale asta hai l'ultima puntata
|
|
||||||
|
|
||||||
### 3. GridSplitter Migliorato
|
|
||||||
|
|
||||||
**PRIMA:**
|
|
||||||
```xml
|
|
||||||
<RowDefinition Height="6" />
|
|
||||||
<GridSplitter Height="6" />
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA:**
|
|
||||||
```xml
|
|
||||||
<RowDefinition Height="12" />
|
|
||||||
<GridSplitter Height="12" Margin="0,2,0,2" />
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefici:**
|
|
||||||
- Più facile da afferrare con il mouse
|
|
||||||
- Maggiore spazio visivo tra sezioni
|
|
||||||
|
|
||||||
### 4. Pannello Dettagli con Pulsante Pausa
|
|
||||||
|
|
||||||
**Header Aggiornato:**
|
|
||||||
```xaml
|
|
||||||
<Grid>
|
|
||||||
<TextBlock Text="?? {AuctionName}" />
|
|
||||||
<Button x:Name="PauseAuctionButton" Content="? Pausa"
|
|
||||||
Click="PauseAuctionButton_Click" />
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Stati:**
|
|
||||||
- **Pausa** (Giallo): `? Pausa` - Asta attiva
|
|
||||||
- **Riprendi** (Verde): `? Riprendi` - Asta in pausa
|
|
||||||
|
|
||||||
### 5. Stats Panel con Visibilità Condizionale
|
|
||||||
|
|
||||||
**PRIMA:**
|
|
||||||
```xaml
|
|
||||||
<Grid x:Name="SingleAuctionPricePanel" Visibility="{...}">
|
|
||||||
<TextBlock Text="Prezzo corrente:" />
|
|
||||||
...
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA:**
|
|
||||||
```xaml
|
|
||||||
<Grid x:Name="SingleAuctionStatsPanel" Visibility="{...}">
|
|
||||||
<StackPanel> <!-- Auto-click, Resets -->
|
|
||||||
<StackPanel> <!-- Prezzo corrente -->
|
|
||||||
<StackPanel> <!-- Multi-Click -->
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Comportamento:**
|
|
||||||
- **Asta Singola:** Stats visibili
|
|
||||||
- **Multi-Asta:** Stats nascoste (gestite per-asta)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Code-Behind (C#)
|
|
||||||
|
|
||||||
### 1. AuctionDisplayModel - Nuove Proprietà
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private int _resetCount = 0;
|
|
||||||
private bool _isMyBid = false;
|
|
||||||
|
|
||||||
public int ResetCount { get; set; }
|
|
||||||
public bool IsMyBid { get; set; }
|
|
||||||
public bool IsPaused { get; set; } = false;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Funzionalità:**
|
|
||||||
- `ResetCount`: Conta reset per singola asta
|
|
||||||
- `IsMyBid`: Flag per evidenziare riga verde
|
|
||||||
- `IsPaused`: Pausa per singola asta
|
|
||||||
|
|
||||||
### 2. UpdateMultiAuctionGrid - Evidenziazione
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// ? Verifica se sono io
|
|
||||||
displayModel.IsMyBid = !string.IsNullOrEmpty(_currentUserName) &&
|
|
||||||
state.Bidder.Equals(_currentUserName, StringComparison.OrdinalIgnoreCase);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Logica:**
|
|
||||||
1. Confronta `Bidder` con `_currentUserName`
|
|
||||||
2. Se match ? `IsMyBid = true`
|
|
||||||
3. DataTrigger applica sfondo verde
|
|
||||||
|
|
||||||
### 3. Reset Detection Per-Asta
|
|
||||||
|
|
||||||
**PRIMA (v2.2):**
|
|
||||||
```csharp
|
|
||||||
// Reset globale
|
|
||||||
resetCount++;
|
|
||||||
Dispatcher.BeginInvoke(() => ResetCountText.Text = resetCount.ToString());
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.3):**
|
|
||||||
```csharp
|
|
||||||
// Reset per-asta
|
|
||||||
targetDisplayModel.ResetCount++;
|
|
||||||
Log($"?? Reset #{targetDisplayModel.ResetCount} su {targetAuction.Name}");
|
|
||||||
LogAuction(targetDisplayModel, $"?? Reset #{targetDisplayModel.ResetCount}");
|
|
||||||
```
|
|
||||||
|
|
||||||
**Vantaggi:**
|
|
||||||
- Ogni asta ha il suo contatore
|
|
||||||
- Visibile nella griglia
|
|
||||||
- Tracciato nel log per-asta
|
|
||||||
|
|
||||||
### 4. Gestione Pausa Per-Asta
|
|
||||||
|
|
||||||
**Metodo Click:**
|
|
||||||
```csharp
|
|
||||||
private void PauseAuctionButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (_selectedAuction == null) return;
|
|
||||||
|
|
||||||
_selectedAuction.IsPaused = !_selectedAuction.IsPaused;
|
|
||||||
|
|
||||||
// Aggiorna UI pulsante
|
|
||||||
btn.Content = _selectedAuction.IsPaused ? "? Riprendi" : "? Pausa";
|
|
||||||
btn.Background = _selectedAuction.IsPaused ?
|
|
||||||
new SolidColorBrush(Color.FromRgb(22, 163, 74)) : // Verde
|
|
||||||
new SolidColorBrush(Color.FromRgb(245, 158, 11)); // Giallo
|
|
||||||
|
|
||||||
LogAuction(_selectedAuction, _selectedAuction.IsPaused ?
|
|
||||||
"? Asta messa in pausa" : "? Asta riattivata");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Loop Check:**
|
|
||||||
```csharp
|
|
||||||
// ? SKIPPA SE ASTA IN PAUSA
|
|
||||||
if (targetDisplayModel.IsPaused)
|
|
||||||
{
|
|
||||||
await Task.Delay(500, token);
|
|
||||||
continue; // Passa alla prossima asta
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Funzionalità:**
|
|
||||||
- Click su `? Pausa` ? Asta ignorata dal loop
|
|
||||||
- Click su `? Riprendi` ? Asta riattivata
|
|
||||||
- Altre aste continuano normalmente
|
|
||||||
|
|
||||||
### 5. Multi-Click Rimosso
|
|
||||||
|
|
||||||
**PRIMA (v2.2):**
|
|
||||||
```csharp
|
|
||||||
bool multiClickEnabled = false;
|
|
||||||
await Dispatcher.InvokeAsync(() => {
|
|
||||||
multiClickEnabled = MultiClickCheckBox.IsChecked == true;
|
|
||||||
});
|
|
||||||
await PerformMultiAuctionClick(..., multiClickEnabled, ...);
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.3):**
|
|
||||||
```csharp
|
|
||||||
// ? RIMUOVI multi-click nel Multi-Asta
|
|
||||||
await PerformMultiAuctionClick(..., false, ...); // Hardcoded false
|
|
||||||
```
|
|
||||||
|
|
||||||
**Motivo:**
|
|
||||||
- Multi-click non necessario nel Multi-Asta
|
|
||||||
- Riduce complessità
|
|
||||||
- Migliori performance
|
|
||||||
|
|
||||||
### 6. UpdateModeButtons - Gestione Stats
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var singleStatsPanel = FindName("SingleAuctionStatsPanel") as Grid;
|
|
||||||
|
|
||||||
if (_isMultiAuctionMode)
|
|
||||||
{
|
|
||||||
if (singleStatsPanel != null)
|
|
||||||
singleStatsPanel.Visibility = Visibility.Collapsed; // ? Nascondi
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (singleStatsPanel != null)
|
|
||||||
singleStatsPanel.Visibility = Visibility.Visible; // ? Mostra
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 7. Default Mode: Multi-Asta
|
|
||||||
|
|
||||||
**PRIMA (v2.2):**
|
|
||||||
```csharp
|
|
||||||
private bool _isMultiAuctionMode = false; // Asta Singola default
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.3):**
|
|
||||||
```csharp
|
|
||||||
private bool _isMultiAuctionMode = true; // ? Multi-Asta default
|
|
||||||
```
|
|
||||||
|
|
||||||
**Effetto:**
|
|
||||||
- All'avvio, Multi-Asta è già selezionato
|
|
||||||
- Navigazione automatica a `https://it.bidoo.com/?tab=FAV`
|
|
||||||
- Griglia visibile da subito
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Workflow Utente v2.3
|
|
||||||
|
|
||||||
### Avvio Applicazione
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. ? Multi-Asta GIÀ SELEZIONATO
|
|
||||||
3. ? Naviga automaticamente a Preferiti
|
|
||||||
4. Attendi 5s per scansione
|
|
||||||
5. Griglia si popola con aste
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configurazione Asta
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Click su un'asta nella griglia
|
|
||||||
2. Pannello dettagli si apre
|
|
||||||
3. Modifica impostazioni:
|
|
||||||
- Timer Click: 0-8
|
|
||||||
- Min Price: €
|
|
||||||
- Max Price: €
|
|
||||||
4. Click [? Pausa] per disabilitare temporaneamente
|
|
||||||
5. Click [? Riprendi] per riattivare
|
|
||||||
```
|
|
||||||
|
|
||||||
### Monitoraggio Real-Time
|
|
||||||
|
|
||||||
**Griglia:**
|
|
||||||
```
|
|
||||||
??????????????????????????????????????????????????????
|
|
||||||
? Asta Timer Prezzo Clicks Resets Ultimo?
|
|
||||||
? Galaxy S25 2.3s 15€ 2 1 Tu ? ? VERDE (Tua puntata)
|
|
||||||
? RTX 5080 5.1s 45€ 0 0 user2 ?
|
|
||||||
? MacBook Pro 8.0s 120€ 5 3 user3 ?
|
|
||||||
??????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Indicatori:**
|
|
||||||
- **Verde + Grassetto**: Ultima puntata è tua
|
|
||||||
- **Clicks**: Quanti click hai fatto
|
|
||||||
- **Resets**: Quanti reset su quell'asta
|
|
||||||
|
|
||||||
### Gestione Pausa
|
|
||||||
|
|
||||||
**Caso d'uso:**
|
|
||||||
```
|
|
||||||
Scenario: Vuoi fermare una sola asta senza fermare tutto
|
|
||||||
|
|
||||||
1. Click su "Galaxy S25" nella griglia
|
|
||||||
2. Click [? Pausa]
|
|
||||||
3. Galaxy S25 viene saltata
|
|
||||||
4. RTX 5080 e MacBook Pro continuano
|
|
||||||
5. Quando vuoi ? Click [? Riprendi]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Confronto v2.2 vs v2.3
|
|
||||||
|
|
||||||
| Caratteristica | v2.2 | v2.3 | Beneficio |
|
|
||||||
|----------------|------|------|-----------|
|
|
||||||
| **Colonna Stato** | ? Presente | ? Rimossa | Spazio recuperato |
|
|
||||||
| **Reset per asta** | ? Solo globale | ? Per-asta | Più informazioni |
|
|
||||||
| **Pausa per asta** | ? Solo globale | ? Per-asta | Controllo fine |
|
|
||||||
| **Evidenziazione** | ? Nessuna | ? Verde se tua | Visibilità immediata |
|
|
||||||
| **Multi-Click** | ? Attivo | ? Disabilitato | Performance |
|
|
||||||
| **Stats globali** | ? Sempre visibili | ? Solo Singola | UI pulita |
|
|
||||||
| **Default mode** | Asta Singola | Multi-Asta | UX migliore |
|
|
||||||
| **GridSplitter** | 6px | 12px | Usabilità |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Miglioramenti Performance
|
|
||||||
|
|
||||||
### 1. Rimozione Multi-Click
|
|
||||||
- **Prima:** 2-3 click per puntata
|
|
||||||
- **Ora:** 2 click (doppio click built-in)
|
|
||||||
- **Risparmio:** ~30% overhead
|
|
||||||
|
|
||||||
### 2. Stats Nascoste
|
|
||||||
- **UI Updates ridotti** in Multi-Asta
|
|
||||||
- Focus su dati per-asta
|
|
||||||
- Meno re-rendering
|
|
||||||
|
|
||||||
### 3. Reset Per-Asta
|
|
||||||
- Non serve più contatore globale
|
|
||||||
- Informazione distribuita
|
|
||||||
- Log più pulito
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Bug Fix
|
|
||||||
|
|
||||||
### 1. Evidenziazione Puntata
|
|
||||||
|
|
||||||
**Problema v2.2:**
|
|
||||||
```
|
|
||||||
Non si capiva su quale asta avevi puntato per ultimo
|
|
||||||
```
|
|
||||||
|
|
||||||
**Soluzione v2.3:**
|
|
||||||
```csharp
|
|
||||||
displayModel.IsMyBid = state.Bidder.Equals(_currentUserName, ...);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Risultato:**
|
|
||||||
- Riga verde = tua ultima puntata
|
|
||||||
- Immediata comprensione visiva
|
|
||||||
|
|
||||||
### 2. Reset Non Tracciati
|
|
||||||
|
|
||||||
**Problema v2.2:**
|
|
||||||
```
|
|
||||||
Reset globali, impossibile capire quale asta resetta di più
|
|
||||||
```
|
|
||||||
|
|
||||||
**Soluzione v2.3:**
|
|
||||||
```csharp
|
|
||||||
targetDisplayModel.ResetCount++;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Risultato:**
|
|
||||||
- Colonna "Resets" in griglia
|
|
||||||
- Visibile per ogni asta
|
|
||||||
|
|
||||||
### 3. Pausa Globale Troppo Invasiva
|
|
||||||
|
|
||||||
**Problema v2.2:**
|
|
||||||
```
|
|
||||||
Pausa globale ferma TUTTO, anche aste che vanno bene
|
|
||||||
```
|
|
||||||
|
|
||||||
**Soluzione v2.3:**
|
|
||||||
```csharp
|
|
||||||
if (targetDisplayModel.IsPaused) continue;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Risultato:**
|
|
||||||
- Pausa selettiva per asta
|
|
||||||
- Altre aste continuano
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
**Modifiche:**
|
|
||||||
1. Rimossa colonna `<DataGridTextColumn Header="Stato" .../>`
|
|
||||||
2. Aggiunta colonna `<DataGridTextColumn Header="Resets" Binding="{Binding ResetCount}" .../>`
|
|
||||||
3. Aggiunto `<DataTrigger Binding="{Binding IsMyBid}" Value="True">` per sfondo verde
|
|
||||||
4. GridSplitter: `Height="6"` ? `Height="12"`, aggiunto `Margin="0,2,0,2"`
|
|
||||||
5. Aggiunto `<Button x:Name="PauseAuctionButton" .../>` in header dettagli
|
|
||||||
6. Rinominato `SingleAuctionPricePanel` ? `SingleAuctionStatsPanel`
|
|
||||||
7. Spostato `MultiAuctionPanel` Visibility da `Collapsed` a `Visible` (default)
|
|
||||||
|
|
||||||
**Righe modificate:** ~25
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
**Modifiche:**
|
|
||||||
1. `_isMultiAuctionMode = false` ? `_isMultiAuctionMode = true`
|
|
||||||
2. `AuctionDisplayModel`: Aggiunte proprietà `ResetCount`, `IsMyBid`, `IsPaused`
|
|
||||||
3. `UpdateMultiAuctionGrid`: Aggiunto check `IsMyBid`
|
|
||||||
4. `UpdateMultiAuctionGrid`: Inizializzato `ResetCount = 0`
|
|
||||||
5. `MultiAuctionLoop`: Reset detection per-asta invece che globale
|
|
||||||
6. `MultiAuctionLoop`: Check `if (targetDisplayModel.IsPaused) continue;`
|
|
||||||
7. `MultiAuctionLoop`: Rimosso `multiClickEnabled`, hardcoded `false`
|
|
||||||
8. `MultiAuctionLoop`: Aggiunto `targetDisplayModel.IsMyBid = true` dopo click
|
|
||||||
9. `UpdateModeButtons`: Gestione `SingleAuctionStatsPanel` visibility
|
|
||||||
10. `UpdateSelectedAuctionDetails`: Abilita e aggiorna pulsante Pausa
|
|
||||||
11. Aggiunto metodo `PauseAuctionButton_Click`
|
|
||||||
|
|
||||||
**Righe modificate:** ~80
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Testing
|
|
||||||
|
|
||||||
### Build
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0 (critical)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Funzionalità Verificate
|
|
||||||
- ? Multi-Asta è default all'avvio
|
|
||||||
- ? Griglia visibile da subito
|
|
||||||
- ? Stats nascoste in Multi-Asta
|
|
||||||
- ? Colonna Resets presente
|
|
||||||
- ? Pulsante Pausa funzionante
|
|
||||||
- ? Evidenziazione verde (binding corretto)
|
|
||||||
|
|
||||||
### Da Testare (Utente)
|
|
||||||
- [ ] Evidenziazione verde appare dopo tua puntata
|
|
||||||
- [ ] Contatore Resets si incrementa correttamente
|
|
||||||
- [ ] Pausa asta funziona (asta skipata)
|
|
||||||
- [ ] Riprendi asta riattiva correttamente
|
|
||||||
- [ ] Multi-Click effettivamente disabilitato
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Immediate
|
|
||||||
1. Testa evidenziazione verde
|
|
||||||
2. Verifica contatore Reset per-asta
|
|
||||||
3. Prova Pausa/Riprendi su asta
|
|
||||||
4. Controlla che Stats siano nascoste
|
|
||||||
|
|
||||||
### Se Problemi
|
|
||||||
- **Verde non appare**: Verifica `_currentUserName` sia impostato
|
|
||||||
- **Reset non si incrementa**: Check log per debug
|
|
||||||
- **Pausa non funziona**: Verifica `IsPaused` flag
|
|
||||||
|
|
||||||
### Future v2.4
|
|
||||||
- [ ] Salvataggio configurazione per-asta
|
|
||||||
- [ ] Export/Import settings
|
|
||||||
- [ ] Statistiche avanzate per asta
|
|
||||||
- [ ] Grafici reset/click
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
### Obiettivi v2.3 Raggiunti
|
|
||||||
|
|
||||||
? **UI Pulita:**
|
|
||||||
- Rimossa colonna inutile "Stato"
|
|
||||||
- Stats nascoste quando non servono
|
|
||||||
- Evidenziazione visuale immediata
|
|
||||||
|
|
||||||
? **Controllo Granulare:**
|
|
||||||
- Pausa per singola asta
|
|
||||||
- Reset tracciati per asta
|
|
||||||
- Impostazioni per asta
|
|
||||||
|
|
||||||
? **Performance:**
|
|
||||||
- Multi-Click rimosso
|
|
||||||
- Update UI ottimizzati
|
|
||||||
- Loop più efficiente
|
|
||||||
|
|
||||||
? **UX Migliorata:**
|
|
||||||
- Multi-Asta default
|
|
||||||
- GridSplitter più facile
|
|
||||||
- Feedback visivo chiaro
|
|
||||||
|
|
||||||
### Il Risultato
|
|
||||||
|
|
||||||
**v2.2:**
|
|
||||||
- ? Gestione per-asta base
|
|
||||||
- ? Colonna Stato inutile
|
|
||||||
- ? Reset globali
|
|
||||||
- ? Pausa solo globale
|
|
||||||
- ? Nessuna evidenziazione
|
|
||||||
|
|
||||||
**v2.3:**
|
|
||||||
- ? Gestione per-asta completa ?
|
|
||||||
- ? Colonna Resets utile ?
|
|
||||||
- ? Reset tracciati per asta ?
|
|
||||||
- ? Pausa per singola asta ?
|
|
||||||
- ? Evidenziazione verde tua puntata ?
|
|
||||||
- ? Multi-Asta default ?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.3 - Per-Auction Complete Control*
|
|
||||||
*Controllo totale, visibilità immediata! ??*
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
# ? v2.3 - MODIFICHE COMPLETATE
|
|
||||||
|
|
||||||
## ?? Tutte le Richieste Implementate
|
|
||||||
|
|
||||||
### 1. ? Rimossa colonna "Stato"
|
|
||||||
- Eliminata dalla griglia
|
|
||||||
- Più spazio per informazioni utili
|
|
||||||
|
|
||||||
### 2. ? Aumentato spazio griglia/dettagli
|
|
||||||
- GridSplitter: 6px ? 12px + margin
|
|
||||||
- Più facile da ridimensionare
|
|
||||||
- Migliore separazione visiva
|
|
||||||
|
|
||||||
### 3. ? Pulsante Pausa per singola asta
|
|
||||||
- `? Pausa` (Giallo) ? Disabilita asta
|
|
||||||
- `? Riprendi` (Verde) ? Riattiva asta
|
|
||||||
- Altre aste continuano normalmente
|
|
||||||
|
|
||||||
### 4. ? Evidenziazione riga tua puntata
|
|
||||||
- **Sfondo verde** quando sei ultimo bidder
|
|
||||||
- **Grassetto** per maggiore visibilità
|
|
||||||
- Binding automatico con `IsMyBid`
|
|
||||||
|
|
||||||
### 5. ? Contatore Reset per asta
|
|
||||||
- Colonna "Resets" nella griglia
|
|
||||||
- Conta reset per ogni asta singolarmente
|
|
||||||
- Visibile e tracciato nel log
|
|
||||||
|
|
||||||
### 6. ? Rimosso Multi-Click da Multi-Asta
|
|
||||||
- Click singolo (doppio built-in)
|
|
||||||
- Migliori performance
|
|
||||||
- Codice più semplice
|
|
||||||
|
|
||||||
### 7. ? Stats nascoste in Multi-Asta
|
|
||||||
- Auto-click/Resets non visibili
|
|
||||||
- Solo in Asta Singola
|
|
||||||
- UI più pulita
|
|
||||||
|
|
||||||
### 8. ? Multi-Asta come default
|
|
||||||
- Si avvia direttamente in Multi-Asta
|
|
||||||
- Naviga automaticamente ai Preferiti
|
|
||||||
- Pronto all'uso immediato
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Nuova Griglia
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Asta Timer Prezzo Clicks Resets Ultimo ?
|
|
||||||
? Galaxy S25 2.3s 15€ 2 1 Tu ? ? VERDE!
|
|
||||||
? RTX 5080 5.1s 45€ 0 0 user2 ?
|
|
||||||
? MacBook Pro 8.0s 120€ 5 3 user3 ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? (Ridimensionabile - 12px)
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [? Pausa] ?
|
|
||||||
? Timer Click: [1] Min €: [10] Max €: [50] ?
|
|
||||||
? Utenti su questa asta: 3 ?
|
|
||||||
? Log... ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Quick Start
|
|
||||||
|
|
||||||
1. **Apri AutoBidder** ? Multi-Asta già attivo
|
|
||||||
2. **Aggiungi aste** ai Preferiti su Bidoo (?)
|
|
||||||
3. **Attendi 5s** ? Griglia si popola
|
|
||||||
4. **Click su asta** ? Vedi dettagli
|
|
||||||
5. **Configura** Timer/Min/Max per asta
|
|
||||||
6. **Clicca [Avvia]** ? Inizia monitoraggio
|
|
||||||
|
|
||||||
### Pausa Selettiva
|
|
||||||
|
|
||||||
```
|
|
||||||
Vuoi fermare solo "Galaxy S25"?
|
|
||||||
1. Click su "Galaxy S25"
|
|
||||||
2. Click [? Pausa]
|
|
||||||
3. Altre aste continuano!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Evidenziazione
|
|
||||||
|
|
||||||
```
|
|
||||||
Quando punti:
|
|
||||||
- Riga diventa VERDE + GRASSETTO
|
|
||||||
- Vedi subito dove hai puntato
|
|
||||||
- "Ultimo" mostra "Tu"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Build
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0 (critici)
|
|
||||||
? Tutto funzionante!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Cosa Hai Ora
|
|
||||||
|
|
||||||
**v2.3 = Controllo Totale Per-Asta!**
|
|
||||||
|
|
||||||
- ? Vedi TUTTO in tempo reale (timer, prezzo, clicks, resets)
|
|
||||||
- ? Evidenziazione VERDE quando punti
|
|
||||||
- ? Pausa SELETTIVA per singola asta
|
|
||||||
- ? Reset TRACCIATI per ogni asta
|
|
||||||
- ? UI PULITA senza info inutili
|
|
||||||
- ? Multi-Asta PRONTO all'avvio
|
|
||||||
|
|
||||||
**Pronto per testare! ??**
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
# ? v2.4 - UI REFINEMENTS COMPLETATE
|
|
||||||
|
|
||||||
## ?? Tutte le Modifiche Implementate
|
|
||||||
|
|
||||||
### 1. ? Margine Simmetrico Griglia
|
|
||||||
- Bottom margin griglia: 12px ? 8px
|
|
||||||
- Match perfetto con top margin dettagli (8px)
|
|
||||||
- Visual balance migliorato
|
|
||||||
|
|
||||||
### 2. ? Rimosso Pulsante Pausa Globale
|
|
||||||
- Layout semplificato: 3 colonne invece di 5
|
|
||||||
- Solo **[Avvia]** e **[Stop]** ora
|
|
||||||
- Pausa gestita solo per-asta (più preciso)
|
|
||||||
|
|
||||||
### 3. ? Pulsanti Senza Icone
|
|
||||||
- `? Pausa` ? `Pausa`
|
|
||||||
- `? Riprendi` ? `Riprendi`
|
|
||||||
- Più spazio, più leggibile
|
|
||||||
|
|
||||||
### 4. ? Due Pulsanti Separati
|
|
||||||
- **[Pausa]** (Giallo #F59E0B) - Attivo se NON in pausa
|
|
||||||
- **[Riprendi]** (Verde #16A34A) - Attivo se in pausa
|
|
||||||
- Opacity 50% quando disabilitato
|
|
||||||
|
|
||||||
### 5. ? Colore Aste in Pausa
|
|
||||||
- **Marrone scuro** (#78350F) + opacity 70%
|
|
||||||
- Si vede subito quale asta è disabilitata
|
|
||||||
- DataTrigger automatico su `IsPaused`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Nuova Palette Griglia
|
|
||||||
|
|
||||||
```
|
|
||||||
??????????????????????????????????????????????????????
|
|
||||||
? Asta Timer Prezzo Clicks Resets Ultimo?
|
|
||||||
? Galaxy S25 2.3s 15€ 2 1 Tu ? ? VERDE (Tua puntata)
|
|
||||||
? RTX 5080 5.1s 45€ 0 0 user2 ? ? NORMALE
|
|
||||||
? MacBook Pro PAUSA 120€ 5 3 user3 ? ? MARRONE (In pausa)
|
|
||||||
??????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Colori:**
|
|
||||||
- **Grigio scuro** (#0B1220): Normale
|
|
||||||
- **Blu** (#1E40AF): Selezionata
|
|
||||||
- **Verde** (#15803D): Mia puntata
|
|
||||||
- **Marrone** (#78350F): In pausa ?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Code Changes
|
|
||||||
|
|
||||||
### IsPaused con Notify
|
|
||||||
```csharp
|
|
||||||
// Prima
|
|
||||||
public bool IsPaused { get; set; } = false;
|
|
||||||
|
|
||||||
// Ora (Observable)
|
|
||||||
private bool _isPaused = false;
|
|
||||||
public bool IsPaused
|
|
||||||
{
|
|
||||||
get => _isPaused;
|
|
||||||
set { _isPaused = value; OnPropertyChanged(nameof(IsPaused)); }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Due Metodi Separati
|
|
||||||
```csharp
|
|
||||||
private void PauseAuctionButton_Click(...)
|
|
||||||
{
|
|
||||||
_selectedAuction.IsPaused = true;
|
|
||||||
UpdateAuctionButtonStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResumeAuctionButton_Click(...)
|
|
||||||
{
|
|
||||||
_selectedAuction.IsPaused = false;
|
|
||||||
UpdateAuctionButtonStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAuctionButtonStates()
|
|
||||||
{
|
|
||||||
pauseBtn.IsEnabled = !_selectedAuction.IsPaused;
|
|
||||||
pauseBtn.Opacity = _selectedAuction.IsPaused ? 0.5 : 1.0;
|
|
||||||
|
|
||||||
resumeBtn.IsEnabled = _selectedAuction.IsPaused;
|
|
||||||
resumeBtn.Opacity = _selectedAuction.IsPaused ? 1.0 : 0.5;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Funziona
|
|
||||||
|
|
||||||
### Pausa Asta
|
|
||||||
|
|
||||||
1. Click su asta nella griglia
|
|
||||||
2. Click **[Pausa]** (giallo)
|
|
||||||
3. ? **Riga diventa MARRONE** + trasparente
|
|
||||||
4. ? **[Pausa] si disabilita** (50% opacity)
|
|
||||||
5. ? **[Riprendi] si abilita** (100% opacity)
|
|
||||||
6. Loop skippa l'asta
|
|
||||||
7. Log: "? Asta messa in pausa"
|
|
||||||
|
|
||||||
### Riprendi Asta
|
|
||||||
|
|
||||||
1. Click **[Riprendi]** (verde)
|
|
||||||
2. ? **Riga torna NORMALE**
|
|
||||||
3. ? **[Riprendi] si disabilita**
|
|
||||||
4. ? **[Pausa] si abilita**
|
|
||||||
5. Loop riprende processarla
|
|
||||||
6. Log: "? Asta riattivata"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build Status
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
? Pronto per il test!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Documentazione
|
|
||||||
|
|
||||||
- **v2.4_UI_REFINEMENTS.md** - Guida completa tecnica
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Test Rapido
|
|
||||||
|
|
||||||
1. Apri AutoBidder ? Multi-Asta
|
|
||||||
2. Aggiungi 3 aste ai preferiti
|
|
||||||
3. Avvia monitoraggio
|
|
||||||
4. **Click su asta** ? Pannello dettagli
|
|
||||||
5. **Click [Pausa]**
|
|
||||||
- ? Riga diventa marrone?
|
|
||||||
- ? [Pausa] disabilitato?
|
|
||||||
- ? [Riprendi] abilitato?
|
|
||||||
6. **Aspetta** ? Loop skippa quell'asta?
|
|
||||||
7. **Click [Riprendi]**
|
|
||||||
- ? Riga torna normale?
|
|
||||||
- ? Loop riprende?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**v2.4 Completata! UI pulita, feedback immediato! ???**
|
|
||||||
@@ -1,515 +0,0 @@
|
|||||||
# ?? AutoBidder v2.4 - UI Refinements
|
|
||||||
|
|
||||||
## ? Modifiche Completate
|
|
||||||
|
|
||||||
### ?? Lista Richieste
|
|
||||||
|
|
||||||
1. ? **Margine simmetrico** tra griglia e dettagli (8px bottom match top)
|
|
||||||
2. ? **Rimosso pulsante Pausa globale** (solo per-asta)
|
|
||||||
3. ? **Rimossa icona** da pulsante Pausa (solo testo)
|
|
||||||
4. ? **Due pulsanti separati** Pausa e Riprendi
|
|
||||||
5. ? **Colore distintivo** per aste in pausa (#78350F - marrone/arancio scuro)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche UI (XAML)
|
|
||||||
|
|
||||||
### 1. Spaziatura Simmetrica Griglia
|
|
||||||
|
|
||||||
**PRIMA (v2.3):**
|
|
||||||
```xml
|
|
||||||
<!-- Griglia Aste -->
|
|
||||||
<Border Margin="12,0,12,0">
|
|
||||||
<DataGrid Margin="8,8,8,12" ... /> <!-- Bottom: 12px -->
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Dettagli -->
|
|
||||||
<Border Margin="12,8,12,12"> <!-- Top: 8px -->
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.4):**
|
|
||||||
```xml
|
|
||||||
<!-- Griglia Aste -->
|
|
||||||
<Border Margin="12,0,12,8">
|
|
||||||
<DataGrid Margin="8,8,8,8" ... /> <!-- Bottom: 8px ? -->
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- Dettagli -->
|
|
||||||
<Border Margin="12,8,12,12"> <!-- Top: 8px ? -->
|
|
||||||
```
|
|
||||||
|
|
||||||
**Risultato:**
|
|
||||||
- Spazio uniforme sopra e sotto GridSplitter
|
|
||||||
- Visual balance migliorato
|
|
||||||
|
|
||||||
### 2. Rimosso Pulsante Pausa Globale
|
|
||||||
|
|
||||||
**PRIMA (v2.3):**
|
|
||||||
```xml
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="8"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="8"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Button x:Name="StartButton" Grid.Column="0" ... />
|
|
||||||
<Button x:Name="PauseBidButton" Grid.Column="2" ... />
|
|
||||||
<Button x:Name="StopButton" Grid.Column="4" ... />
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.4):**
|
|
||||||
```xml
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="8"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Button x:Name="StartButton" Grid.Column="0" ... />
|
|
||||||
<Button x:Name="StopButton" Grid.Column="2" ... />
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefici:**
|
|
||||||
- UI più pulita e semplice
|
|
||||||
- Pausa gestita solo per-asta (più preciso)
|
|
||||||
- Meno confusione per l'utente
|
|
||||||
|
|
||||||
### 3. Pulsanti Pausa/Riprendi Separati
|
|
||||||
|
|
||||||
**PRIMA (v2.3):**
|
|
||||||
```xml
|
|
||||||
<!-- Un solo pulsante toggle -->
|
|
||||||
<Button x:Name="PauseAuctionButton" Content="? Pausa" ... />
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.4):**
|
|
||||||
```xml
|
|
||||||
<!-- Due pulsanti distinti -->
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Button x:Name="PauseAuctionButton" Content="Pausa" ... />
|
|
||||||
<Button x:Name="ResumeAuctionButton" Content="Riprendi" Margin="4,0,0,0" ... />
|
|
||||||
</StackPanel>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Comportamento:**
|
|
||||||
- **Pausa** (Giallo): Attivo se asta NON in pausa
|
|
||||||
- **Riprendi** (Verde): Attivo se asta in pausa
|
|
||||||
- Opacity 0.5 quando disabilitato
|
|
||||||
|
|
||||||
**Vantaggi:**
|
|
||||||
- Chiaro quale azione si può fare
|
|
||||||
- No icone (più spazio, più leggibile)
|
|
||||||
- Stati visivi immediati
|
|
||||||
|
|
||||||
### 4. Colore Aste in Pausa
|
|
||||||
|
|
||||||
**Nuovo DataTrigger:**
|
|
||||||
```xml
|
|
||||||
<DataTrigger Binding="{Binding IsPaused}" Value="True">
|
|
||||||
<Setter Property="Background" Value="#78350F" /> <!-- Marrone/Arancio scuro -->
|
|
||||||
<Setter Property="Opacity" Value="0.7" />
|
|
||||||
</DataTrigger>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Palette colori griglia:**
|
|
||||||
| Stato | Colore | Codice | Significato |
|
|
||||||
|-------|--------|--------|-------------|
|
|
||||||
| **Normale** | Grigio scuro | #0B1220 | Asta attiva standard |
|
|
||||||
| **Selezionata** | Blu | #1E40AF | Click sulla riga |
|
|
||||||
| **Mia puntata** | Verde | #15803D | Ultima puntata è tua |
|
|
||||||
| **In pausa** | Marrone scuro | #78350F | Asta disabilitata |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Code-Behind (C#)
|
|
||||||
|
|
||||||
### 1. IsPaused con INotifyPropertyChanged
|
|
||||||
|
|
||||||
**PRIMA (v2.3):**
|
|
||||||
```csharp
|
|
||||||
public bool IsPaused { get; set; } = false;
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.4):**
|
|
||||||
```csharp
|
|
||||||
private bool _isPaused = false;
|
|
||||||
public bool IsPaused
|
|
||||||
{
|
|
||||||
get => _isPaused;
|
|
||||||
set { _isPaused = value; OnPropertyChanged(nameof(IsPaused)); }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Motivo:**
|
|
||||||
- Trigger XAML si attiva automaticamente
|
|
||||||
- Riga cambia colore real-time quando metti in pausa
|
|
||||||
- Binding reattivo
|
|
||||||
|
|
||||||
### 2. Due Metodi Click Separati
|
|
||||||
|
|
||||||
**PRIMA (v2.3):**
|
|
||||||
```csharp
|
|
||||||
private void PauseAuctionButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_selectedAuction.IsPaused = !_selectedAuction.IsPaused;
|
|
||||||
// Toggle Content, Background...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.4):**
|
|
||||||
```csharp
|
|
||||||
private void PauseAuctionButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (_selectedAuction == null) return;
|
|
||||||
_selectedAuction.IsPaused = true;
|
|
||||||
UpdateAuctionButtonStates();
|
|
||||||
LogAuction(_selectedAuction, "? Asta messa in pausa");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResumeAuctionButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (_selectedAuction == null) return;
|
|
||||||
_selectedAuction.IsPaused = false;
|
|
||||||
UpdateAuctionButtonStates();
|
|
||||||
LogAuction(_selectedAuction, "? Asta riattivata");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Più chiaro e manutenibile!**
|
|
||||||
|
|
||||||
### 3. Gestione Stati Pulsanti
|
|
||||||
|
|
||||||
**Nuovo metodo:**
|
|
||||||
```csharp
|
|
||||||
private void UpdateAuctionButtonStates()
|
|
||||||
{
|
|
||||||
if (_selectedAuction == null) return;
|
|
||||||
|
|
||||||
Dispatcher.BeginInvoke(() =>
|
|
||||||
{
|
|
||||||
var pauseBtn = FindName("PauseAuctionButton") as Button;
|
|
||||||
var resumeBtn = FindName("ResumeAuctionButton") as Button;
|
|
||||||
|
|
||||||
if (pauseBtn != null)
|
|
||||||
{
|
|
||||||
pauseBtn.IsEnabled = !_selectedAuction.IsPaused;
|
|
||||||
pauseBtn.Opacity = _selectedAuction.IsPaused ? 0.5 : 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resumeBtn != null)
|
|
||||||
{
|
|
||||||
resumeBtn.IsEnabled = _selectedAuction.IsPaused;
|
|
||||||
resumeBtn.Opacity = _selectedAuction.IsPaused ? 1.0 : 0.5;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Chiamato da:**
|
|
||||||
- `PauseAuctionButton_Click()`
|
|
||||||
- `ResumeAuctionButton_Click()`
|
|
||||||
- `UpdateSelectedAuctionDetails()` (al cambio selezione)
|
|
||||||
|
|
||||||
### 4. Rimosso UpdatePauseButtonContent
|
|
||||||
|
|
||||||
**Metodo obsoleto eliminato:**
|
|
||||||
```csharp
|
|
||||||
// ? RIMOSSO
|
|
||||||
private void UpdatePauseButtonContent() { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
Era per il pulsante globale, non più necessario.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Workflow Utente v2.4
|
|
||||||
|
|
||||||
### Pausa Asta
|
|
||||||
|
|
||||||
**Prima (v2.3):**
|
|
||||||
```
|
|
||||||
1. Seleziona asta
|
|
||||||
2. Click [? Pausa]
|
|
||||||
3. Pulsante diventa [? Riprendi]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ora (v2.4):**
|
|
||||||
```
|
|
||||||
1. Seleziona asta
|
|
||||||
2. Click [Pausa] (giallo)
|
|
||||||
3. [Pausa] diventa disabilitato (opacity 50%)
|
|
||||||
4. [Riprendi] diventa abilitato (verde)
|
|
||||||
5. Riga in griglia diventa MARRONE SCURO + opacity 70%
|
|
||||||
```
|
|
||||||
|
|
||||||
**Immediato feedback visivo! ??**
|
|
||||||
|
|
||||||
### Riprendi Asta
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Click [Riprendi] (verde)
|
|
||||||
2. [Riprendi] diventa disabilitato
|
|
||||||
3. [Pausa] diventa abilitato
|
|
||||||
4. Riga torna al colore normale
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Confronto Versioni
|
|
||||||
|
|
||||||
### Stati Visivi Griglia
|
|
||||||
|
|
||||||
| Versione | Normale | Selezionata | Mia puntata | In pausa |
|
|
||||||
|----------|---------|-------------|-------------|----------|
|
|
||||||
| v2.3 | Grigio | Blu | Verde | - |
|
|
||||||
| v2.4 | Grigio | Blu | Verde | **Marrone** ? |
|
|
||||||
|
|
||||||
### Controlli Pausa
|
|
||||||
|
|
||||||
| Versione | Globale | Per-asta | UI |
|
|
||||||
|----------|---------|----------|-----|
|
|
||||||
| v2.3 | Pulsante | Toggle | 1 pulsante con icona |
|
|
||||||
| v2.4 | **Rimosso** ? | 2 pulsanti | Pausa + Riprendi |
|
|
||||||
|
|
||||||
### Spaziatura
|
|
||||||
|
|
||||||
| Versione | Griglia bottom | Dettagli top | Simmetria |
|
|
||||||
|----------|----------------|--------------|-----------|
|
|
||||||
| v2.3 | 12px | 8px | ? |
|
|
||||||
| v2.4 | 8px | 8px | ? |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Benefici v2.4
|
|
||||||
|
|
||||||
### 1. Chiarezza UI
|
|
||||||
|
|
||||||
**v2.3:**
|
|
||||||
- ? Pulsante Pausa globale + per-asta (confuso)
|
|
||||||
- ? Toggle con cambio icona/colore
|
|
||||||
- ? Aste in pausa non distinguibili
|
|
||||||
|
|
||||||
**v2.4:**
|
|
||||||
- ? Solo pausa per-asta (chiaro)
|
|
||||||
- ? Due pulsanti distinti (intuitivo)
|
|
||||||
- ? Colore marrone immediato (visibile)
|
|
||||||
|
|
||||||
### 2. Feedback Visivo
|
|
||||||
|
|
||||||
**Quando metti in pausa:**
|
|
||||||
```
|
|
||||||
1. Riga diventa MARRONE + trasparente
|
|
||||||
2. Pulsante [Pausa] si disabilita
|
|
||||||
3. Pulsante [Riprendi] si abilita
|
|
||||||
4. Log conferma azione
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tutto in un colpo d'occhio! ???**
|
|
||||||
|
|
||||||
### 3. Coerenza Estetica
|
|
||||||
|
|
||||||
- Margini simmetrici ?
|
|
||||||
- Allineamento perfetto ?
|
|
||||||
- Palette colori distintiva ?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Fix Tecnici
|
|
||||||
|
|
||||||
### 1. IsPaused Binding
|
|
||||||
|
|
||||||
**Problema:**
|
|
||||||
```
|
|
||||||
IsPaused era property semplice, il trigger XAML non si attivava
|
|
||||||
```
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
```csharp
|
|
||||||
// Ora è observable
|
|
||||||
private bool _isPaused = false;
|
|
||||||
public bool IsPaused
|
|
||||||
{
|
|
||||||
get => _isPaused;
|
|
||||||
set { _isPaused = value; OnPropertyChanged(nameof(IsPaused)); }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. UpdatePauseButtonContent Rimosso
|
|
||||||
|
|
||||||
**Problema:**
|
|
||||||
```
|
|
||||||
Metodo per pulsante globale causava null reference se chiamato
|
|
||||||
```
|
|
||||||
|
|
||||||
**Fix:**
|
|
||||||
```csharp
|
|
||||||
// Rimosso dalla chiamata InitializeComponent()
|
|
||||||
webView.CoreWebView2InitializationCompleted += ...;
|
|
||||||
// ? UpdatePauseButtonContent(); // RIMOSSO
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. Border griglia: `Margin="12,0,12,0"` ? `Margin="12,0,12,8"`
|
|
||||||
2. DataGrid: `Margin="8,8,8,12"` ? `Margin="8,8,8,8"`
|
|
||||||
3. Rimosso `<Button x:Name="PauseBidButton" ... />` globale
|
|
||||||
4. Grid controlli: 5 colonne ? 3 colonne
|
|
||||||
5. Aggiunto `<DataTrigger Binding="{Binding IsPaused}" Value="True">` con colore #78350F
|
|
||||||
6. Header dettagli: 1 pulsante ? 2 pulsanti
|
|
||||||
7. Pulsanti: `Content="? Pausa"` ? `Content="Pausa"` (senza icone)
|
|
||||||
|
|
||||||
**Righe modificate:** ~30
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. `IsPaused`: Da property semplice ? Observable property con backing field
|
|
||||||
2. `PauseAuctionButton_Click`: Da toggle ? Set true
|
|
||||||
3. Aggiunto `ResumeAuctionButton_Click`: Set false
|
|
||||||
4. Aggiunto `UpdateAuctionButtonStates()`: Gestisce enable/opacity
|
|
||||||
5. `UpdateSelectedAuctionDetails`: Usa `UpdateAuctionButtonStates()`
|
|
||||||
6. Rimosso `UpdatePauseButtonContent()`
|
|
||||||
7. Constructor: Rimossa chiamata `UpdatePauseButtonContent()`
|
|
||||||
|
|
||||||
**Righe modificate:** ~60
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Testing
|
|
||||||
|
|
||||||
### Build
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Funzionalità da Testare
|
|
||||||
|
|
||||||
- [ ] Click [Pausa] ? Riga diventa marrone + opacity 70%
|
|
||||||
- [ ] Click [Pausa] ? Pulsante si disabilita
|
|
||||||
- [ ] Click [Pausa] ? [Riprendi] si abilita
|
|
||||||
- [ ] Click [Riprendi] ? Riga torna normale
|
|
||||||
- [ ] Click [Riprendi] ? [Pausa] si abilita
|
|
||||||
- [ ] Asta in pausa viene skippata nel loop
|
|
||||||
- [ ] Margini simmetrici griglia/dettagli
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Testare
|
|
||||||
|
|
||||||
### Test Pausa Visiva
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Vai su Multi-Asta (default)
|
|
||||||
3. Aggiungi 3 aste ai preferiti
|
|
||||||
4. Avvia monitoraggio
|
|
||||||
5. Click su un'asta
|
|
||||||
6. Click [Pausa]
|
|
||||||
7. ? Verifica riga diventa MARRONE
|
|
||||||
8. ? Verifica [Pausa] disabilitato (50% opacity)
|
|
||||||
9. ? Verifica [Riprendi] abilitato (100% opacity)
|
|
||||||
10. Click [Riprendi]
|
|
||||||
11. ? Verifica riga torna normale
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Funzionale Pausa
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Pausa un'asta con timer basso (es: 2s)
|
|
||||||
2. ? Verifica nel log: "? Asta messa in pausa"
|
|
||||||
3. ? Verifica loop skippa quell'asta
|
|
||||||
4. ? Verifica altre aste continuano
|
|
||||||
5. Riprendi l'asta
|
|
||||||
6. ? Verifica nel log: "? Asta riattivata"
|
|
||||||
7. ? Verifica loop riprende a processarla
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Riepilogo Colori UI
|
|
||||||
|
|
||||||
### Palette Griglia v2.4
|
|
||||||
|
|
||||||
| Stato | Background | Opacity | Font Weight |
|
|
||||||
|-------|------------|---------|-------------|
|
|
||||||
| Normale | #0B1220 | 1.0 | Normal |
|
|
||||||
| Alternato | #081016 | 1.0 | Normal |
|
|
||||||
| Selezionata | #1E40AF | 1.0 | Normal |
|
|
||||||
| Mia puntata | #15803D | 1.0 | **Bold** |
|
|
||||||
| **In pausa** | **#78350F** | **0.7** | Normal |
|
|
||||||
|
|
||||||
### Palette Pulsanti
|
|
||||||
|
|
||||||
| Pulsante | Colore | Codice | Stato |
|
|
||||||
|----------|--------|--------|-------|
|
|
||||||
| Pausa | Giallo | #F59E0B | Attivo se asta NON pausa |
|
|
||||||
| Riprendi | Verde | #16A34A | Attivo se asta pausa |
|
|
||||||
| Disabilitato | - | opacity 0.5 | Grigio out |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione v2.4
|
|
||||||
|
|
||||||
### Obiettivi Raggiunti
|
|
||||||
|
|
||||||
? **UI Pulita**
|
|
||||||
- Rimosso pulsante globale confuso
|
|
||||||
- Margini perfettamente simmetrici
|
|
||||||
- Icone rimosse (più spazio)
|
|
||||||
|
|
||||||
? **Feedback Visivo Immediato**
|
|
||||||
- Colore marrone per aste in pausa
|
|
||||||
- Opacity ridotta per disabilitato
|
|
||||||
- Stati pulsanti chiari
|
|
||||||
|
|
||||||
? **Semplicità**
|
|
||||||
- Due pulsanti distinti (no toggle)
|
|
||||||
- Azioni chiare (Pausa vs Riprendi)
|
|
||||||
- Comportamento prevedibile
|
|
||||||
|
|
||||||
### Progressione Versioni
|
|
||||||
|
|
||||||
**v2.3:**
|
|
||||||
- ? Gestione per-asta
|
|
||||||
- ? Reset per-asta
|
|
||||||
- ? Evidenziazione verde
|
|
||||||
- ? Pausa globale ancora presente
|
|
||||||
- ? Toggle con icone
|
|
||||||
- ? Aste in pausa non visibili
|
|
||||||
|
|
||||||
**v2.4:**
|
|
||||||
- ? Tutto di v2.3
|
|
||||||
- ? **Solo pausa per-asta** ?
|
|
||||||
- ? **Due pulsanti separati** ?
|
|
||||||
- ? **Colore marrone pausa** ?
|
|
||||||
- ? **Margini simmetrici** ?
|
|
||||||
- ? **Niente icone** ?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Immediate
|
|
||||||
1. Test completo pausa/riprendi
|
|
||||||
2. Verifica colori su diversi monitor
|
|
||||||
3. Test con 10+ aste
|
|
||||||
|
|
||||||
### Future v2.5
|
|
||||||
- [ ] Salvataggio stato pausa
|
|
||||||
- [ ] Shortcuts tastiera (P = Pausa, R = Riprendi)
|
|
||||||
- [ ] Pausa multipla (checkbox per ogni riga)
|
|
||||||
- [ ] Statistiche aste in pausa
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.4 - UI Refinements Complete*
|
|
||||||
*Clean, Clear, Immediate! ???*
|
|
||||||
@@ -1,554 +0,0 @@
|
|||||||
# ?? AutoBidder v2.5 - Bidders Grid Per-Auction
|
|
||||||
|
|
||||||
## ? Modifica Completata
|
|
||||||
|
|
||||||
### ?? Richiesta
|
|
||||||
|
|
||||||
**Aggiungere griglia utenti per-asta** nel pannello dettagli, affiancata al log con GridSplitter ridimensionabile.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Layout Dettagli Asta v2.5
|
|
||||||
|
|
||||||
### PRIMA (v2.4)
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Utenti su questa asta: 3 ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?
|
|
||||||
? Log asta... ?
|
|
||||||
? ?
|
|
||||||
? ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
### ORA (v2.5)
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Utenti: 3 ? ? Log asta ?
|
|
||||||
? ???????????????? ? ????????????????????? ?
|
|
||||||
? ? Utente Punt?? ? ? 10:23 - Click #1 ? ?
|
|
||||||
? ? user1 5 ?? ? ? 10:24 - Reset #1 ? ?
|
|
||||||
? ? user2 3 ?? ? ? 10:25 - Puntata ? ?
|
|
||||||
? ? Tu 2 ?? ? ? di: user1 ? ?
|
|
||||||
? ???????????????? ? ????????????????????? ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? = GridSplitter ridimensionabile
|
|
||||||
```
|
|
||||||
|
|
||||||
**Layout 50/50 ridimensionabile!** ??
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche UI (XAML)
|
|
||||||
|
|
||||||
### 1. Struttura Grid Dettagli
|
|
||||||
|
|
||||||
**PRIMA:**
|
|
||||||
```xml
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Header -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Impostazioni -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Label Bidders -->
|
|
||||||
<RowDefinition Height="*" /> <!-- Log -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA:**
|
|
||||||
```xml
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Header -->
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Impostazioni -->
|
|
||||||
<RowDefinition Height="*" /> <!-- Bidders + Log affiancati ? -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Semplificato e più spazioso!**
|
|
||||||
|
|
||||||
### 2. Grid Row 2 con Splitter
|
|
||||||
|
|
||||||
**Nuova struttura:**
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,4">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" MinWidth="100" /> <!-- Utenti -->
|
|
||||||
<ColumnDefinition Width="6" /> <!-- Splitter -->
|
|
||||||
<ColumnDefinition Width="*" MinWidth="100" /> <!-- Log -->
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<!-- Colonna 0: Griglia Utenti -->
|
|
||||||
<Grid Grid.Column="0">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Header -->
|
|
||||||
<RowDefinition Height="*" /> <!-- DataGrid -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Grid Grid.Row="0">
|
|
||||||
<TextBlock Text="Utenti su questa asta" />
|
|
||||||
<TextBlock x:Name="SelectedAuctionBiddersCount" Text="0" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<DataGrid x:Name="SelectedAuctionBiddersGrid" Grid.Row="1" ... />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- Colonna 1: GridSplitter -->
|
|
||||||
<GridSplitter Grid.Column="1" Width="6" ... />
|
|
||||||
|
|
||||||
<!-- Colonna 2: Log -->
|
|
||||||
<Grid Grid.Column="2">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" /> <!-- Header -->
|
|
||||||
<RowDefinition Height="*" /> <!-- TextBox -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Text="Log asta" />
|
|
||||||
<TextBox x:Name="SelectedAuctionLog" Grid.Row="1" ... />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. DataGrid Bidders Configurazione
|
|
||||||
|
|
||||||
**Nuovi elementi:**
|
|
||||||
```xml
|
|
||||||
<DataGrid x:Name="SelectedAuctionBiddersGrid"
|
|
||||||
AutoGenerateColumns="False" IsReadOnly="True">
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn Header="Utente" Binding="{Binding Key}" Width="*" />
|
|
||||||
<DataGridTextColumn Header="Puntate" Binding="{Binding Value}" Width="60" />
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Font size 10px (compatto)
|
|
||||||
- Row height 24px (denso)
|
|
||||||
- Stile dark theme coerente
|
|
||||||
- Colonne: Utente (espandibile) + Puntate (fissa 60px)
|
|
||||||
|
|
||||||
### 4. GridSplitter Configurazione
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<GridSplitter Grid.Column="1"
|
|
||||||
Width="6"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Background="#1f2937"
|
|
||||||
ShowsPreview="True"
|
|
||||||
ResizeDirection="Columns"
|
|
||||||
Cursor="SizeWE" />
|
|
||||||
```
|
|
||||||
|
|
||||||
**Proprietà:**
|
|
||||||
- Larghezza: 6px
|
|
||||||
- Direzione: Orizzontale (Columns)
|
|
||||||
- Preview: Sì
|
|
||||||
- Cursor: SizeWE (??)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Code-Behind (C#)
|
|
||||||
|
|
||||||
### 1. UpdateSelectedAuctionDetails - Popola Griglia
|
|
||||||
|
|
||||||
**PRIMA:**
|
|
||||||
```csharp
|
|
||||||
// Solo contatore
|
|
||||||
var biddersCount = FindName("SelectedAuctionBiddersCount") as TextBlock;
|
|
||||||
if (biddersCount != null)
|
|
||||||
biddersCount.Text = auction.AuctionBidders.Count.ToString();
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA:**
|
|
||||||
```csharp
|
|
||||||
// ? Griglia + contatore
|
|
||||||
var biddersGrid = FindName("SelectedAuctionBiddersGrid") as DataGrid;
|
|
||||||
var biddersCount = FindName("SelectedAuctionBiddersCount") as TextBlock;
|
|
||||||
|
|
||||||
if (biddersGrid != null)
|
|
||||||
{
|
|
||||||
var biddersList = auction.AuctionBidders
|
|
||||||
.OrderByDescending(kvp => kvp.Value) // Ordina per numero puntate
|
|
||||||
.ToList();
|
|
||||||
biddersGrid.ItemsSource = biddersList;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (biddersCount != null)
|
|
||||||
biddersCount.Text = auction.AuctionBidders.Count.ToString();
|
|
||||||
```
|
|
||||||
|
|
||||||
**Binding automatico a Dictionary:**
|
|
||||||
- `Key` ? Nome utente
|
|
||||||
- `Value` ? Numero puntate
|
|
||||||
|
|
||||||
### 2. UpdateMultiAuctionGrid - Aggiorna Real-Time
|
|
||||||
|
|
||||||
**PRIMA:**
|
|
||||||
```csharp
|
|
||||||
if (_selectedAuction == displayModel)
|
|
||||||
{
|
|
||||||
var biddersCount = FindName("SelectedAuctionBiddersCount") as TextBlock;
|
|
||||||
if (biddersCount != null)
|
|
||||||
biddersCount.Text = displayModel.AuctionBidders.Count.ToString();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA:**
|
|
||||||
```csharp
|
|
||||||
if (_selectedAuction == displayModel)
|
|
||||||
{
|
|
||||||
// ? Aggiorna contatore
|
|
||||||
var biddersCount = FindName("SelectedAuctionBiddersCount") as TextBlock;
|
|
||||||
if (biddersCount != null)
|
|
||||||
biddersCount.Text = displayModel.AuctionBidders.Count.ToString();
|
|
||||||
|
|
||||||
// ? Aggiorna griglia real-time
|
|
||||||
var biddersGrid = FindName("SelectedAuctionBiddersGrid") as DataGrid;
|
|
||||||
if (biddersGrid != null)
|
|
||||||
{
|
|
||||||
var biddersList = displayModel.AuctionBidders
|
|
||||||
.OrderByDescending(kvp => kvp.Value)
|
|
||||||
.ToList();
|
|
||||||
biddersGrid.ItemsSource = biddersList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Aggiornamento automatico quando:**
|
|
||||||
- Cambia il bidder dell'asta
|
|
||||||
- Utente fa una puntata
|
|
||||||
- Asta è selezionata
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Workflow Utente v2.5
|
|
||||||
|
|
||||||
### Selezione Asta
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Click su "Galaxy S25" nella griglia
|
|
||||||
2. Pannello dettagli si apre
|
|
||||||
3. ? Griglia utenti (sinistra) popolata
|
|
||||||
4. ? Log asta (destra) popolato
|
|
||||||
```
|
|
||||||
|
|
||||||
### Visualizzazione Bidders
|
|
||||||
|
|
||||||
**Griglia Utenti mostra:**
|
|
||||||
```
|
|
||||||
????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
????????????????????
|
|
||||||
? user1 5 ? ? Più attivo
|
|
||||||
? user2 3 ?
|
|
||||||
? Tu 2 ? ? Le tue puntate
|
|
||||||
? user3 1 ?
|
|
||||||
????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ordinamento:**
|
|
||||||
- Decrescente per numero puntate
|
|
||||||
- Chi punta di più in alto
|
|
||||||
|
|
||||||
### Aggiornamento Real-Time
|
|
||||||
|
|
||||||
**Quando qualcuno punta:**
|
|
||||||
```
|
|
||||||
1. Griglia si aggiorna automaticamente
|
|
||||||
2. Contatore incrementato
|
|
||||||
3. Se nuovo utente ? aggiunto in fondo
|
|
||||||
4. Se utente esistente ? riordinato
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ridimensionamento
|
|
||||||
|
|
||||||
**Utente può:**
|
|
||||||
- Trascinare splitter ? ?
|
|
||||||
- Dare più spazio agli utenti
|
|
||||||
- Dare più spazio al log
|
|
||||||
- MinWidth 100px per parte
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Confronto Versioni
|
|
||||||
|
|
||||||
### Layout Dettagli
|
|
||||||
|
|
||||||
| Versione | Utenti | Log | Ridimensionabile |
|
|
||||||
|----------|--------|-----|------------------|
|
|
||||||
| v2.4 | Solo contatore | Full width | ? |
|
|
||||||
| v2.5 | **Griglia 50%** ? | **50%** ? | **?** ? |
|
|
||||||
|
|
||||||
### Informazioni Utenti
|
|
||||||
|
|
||||||
| Versione | Info visualizzate |
|
|
||||||
|----------|-------------------|
|
|
||||||
| v2.4 | Solo numero totale (es: "3") |
|
|
||||||
| v2.5 | **Lista completa con puntate** ? |
|
|
||||||
|
|
||||||
### Space Usage
|
|
||||||
|
|
||||||
| Elemento | v2.4 | v2.5 |
|
|
||||||
|----------|------|------|
|
|
||||||
| Header | Auto | Auto |
|
|
||||||
| Settings | Auto | Auto |
|
|
||||||
| Bidders | Label only | **50% Grid** ? |
|
|
||||||
| Log | 100% | **50%** ? |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Benefici v2.5
|
|
||||||
|
|
||||||
### 1. Informazioni Complete
|
|
||||||
|
|
||||||
**v2.4:**
|
|
||||||
```
|
|
||||||
Utenti su questa asta: 3
|
|
||||||
```
|
|
||||||
? Chi sono? Quanti click ciascuno?
|
|
||||||
|
|
||||||
**v2.5:**
|
|
||||||
```
|
|
||||||
Utenti su questa asta: 3
|
|
||||||
????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
? user1 5 ?
|
|
||||||
? user2 3 ?
|
|
||||||
? Tu 2 ?
|
|
||||||
????????????????????
|
|
||||||
```
|
|
||||||
? **Tutto chiaro!**
|
|
||||||
|
|
||||||
### 2. Analisi Competizione
|
|
||||||
|
|
||||||
**Ora puoi vedere:**
|
|
||||||
- Chi punta di più sull'asta
|
|
||||||
- Quanti competitor attivi
|
|
||||||
- Quanto sei competitivo
|
|
||||||
- Distribuzione puntate
|
|
||||||
|
|
||||||
### 3. Flessibilità
|
|
||||||
|
|
||||||
**Ridimensionamento:**
|
|
||||||
- Più utenti? ? Allarga griglia
|
|
||||||
- Log verboso? ? Allarga log
|
|
||||||
- Equilibrio perfetto
|
|
||||||
|
|
||||||
### 4. Coerenza UI
|
|
||||||
|
|
||||||
**Stesso pattern dell'asta singola:**
|
|
||||||
- Griglia bidders a sinistra
|
|
||||||
- Log a destra
|
|
||||||
- Ridimensionabile
|
|
||||||
- Stile identico
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Dettagli Visivi
|
|
||||||
|
|
||||||
### Griglia Bidders Styling
|
|
||||||
|
|
||||||
**Colori:**
|
|
||||||
- Background: #091018
|
|
||||||
- Row normale: #0B1220
|
|
||||||
- Row alternata: #081016
|
|
||||||
- Header: #0F1720
|
|
||||||
- Testo: #E6EDF3
|
|
||||||
|
|
||||||
**Font:**
|
|
||||||
- Size: 10px (compatto)
|
|
||||||
- Weight: SemiBold (header)
|
|
||||||
- Height: 24px (row)
|
|
||||||
|
|
||||||
### GridSplitter
|
|
||||||
|
|
||||||
**Visual:**
|
|
||||||
- Larghezza: 6px
|
|
||||||
- Colore: #1f2937 (grigio scuro)
|
|
||||||
- Preview: Sì (linea durante drag)
|
|
||||||
- Cursor: ? ? (SizeWE)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. Grid.RowDefinitions: 4 rows ? 3 rows
|
|
||||||
2. Grid.Row="2": Singolo elemento ? Grid con 3 colonne
|
|
||||||
3. Aggiunto `SelectedAuctionBiddersGrid` DataGrid
|
|
||||||
4. Aggiunto GridSplitter orizzontale
|
|
||||||
5. Spostato `SelectedAuctionLog` in colonna 2
|
|
||||||
|
|
||||||
**Righe modificate:** ~60
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. `UpdateSelectedAuctionDetails`: Popola griglia bidders
|
|
||||||
2. `UpdateMultiAuctionGrid`: Aggiorna griglia quando bidder cambia
|
|
||||||
|
|
||||||
**Righe modificate:** ~20
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build Status
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
? Pronto per il test!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Testing Checklist
|
|
||||||
|
|
||||||
### Layout
|
|
||||||
- [ ] Griglia bidders visible a sinistra
|
|
||||||
- [ ] Log visible a destra
|
|
||||||
- [ ] GridSplitter funzionante
|
|
||||||
- [ ] MinWidth 100px rispettato
|
|
||||||
- [ ] Split 50/50 di default
|
|
||||||
|
|
||||||
### Funzionalità
|
|
||||||
- [ ] Click su asta ? Griglia popolata
|
|
||||||
- [ ] Bidders ordinati per puntate (desc)
|
|
||||||
- [ ] Contatore aggiornato
|
|
||||||
- [ ] Log aggiornato
|
|
||||||
- [ ] Nuova puntata ? Griglia update
|
|
||||||
|
|
||||||
### Ridimensionamento
|
|
||||||
- [ ] Drag splitter ? Resize funziona
|
|
||||||
- [ ] Trascinare a sinistra ? Log si restringe
|
|
||||||
- [ ] Trascinare a destra ? Bidders si restringe
|
|
||||||
- [ ] MinWidth blocca a 100px
|
|
||||||
|
|
||||||
### Real-Time
|
|
||||||
- [ ] Puntata su asta selezionata ? Griglia update
|
|
||||||
- [ ] Nuovo bidder ? Appare in griglia
|
|
||||||
- [ ] Bidder esistente ? Contatore incrementa + riordina
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Casi d'Uso
|
|
||||||
|
|
||||||
### Scenario 1: Asta Popolare
|
|
||||||
|
|
||||||
```
|
|
||||||
Galaxy S25 - 15 utenti
|
|
||||||
|
|
||||||
????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
? bot123 45 ? ? Bot sospetto?
|
|
||||||
? user1 12 ?
|
|
||||||
? user2 8 ?
|
|
||||||
? Tu 3 ? ? Poco competitivo
|
|
||||||
? ... ?
|
|
||||||
????????????????????
|
|
||||||
|
|
||||||
Decisione: Troppa competizione, pausa?
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scenario 2: Asta Tranquilla
|
|
||||||
|
|
||||||
```
|
|
||||||
MacBook Pro - 3 utenti
|
|
||||||
|
|
||||||
????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
? Tu 18 ? ? Dominante!
|
|
||||||
? user1 2 ?
|
|
||||||
? user2 1 ?
|
|
||||||
????????????????????
|
|
||||||
|
|
||||||
Decisione: Buone probabilità di vincita!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Scenario 3: Analisi Competitore
|
|
||||||
|
|
||||||
```
|
|
||||||
RTX 5080 - 8 utenti
|
|
||||||
|
|
||||||
????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
? user1 25 ? ? Sempre questo!
|
|
||||||
? Tu 12 ?
|
|
||||||
? user2 5 ?
|
|
||||||
? ... ?
|
|
||||||
????????????????????
|
|
||||||
|
|
||||||
Scoperta: user1 è competitor principale
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione v2.5
|
|
||||||
|
|
||||||
### Obiettivo Raggiunto
|
|
||||||
|
|
||||||
? **Griglia Bidders Per-Asta implementata con successo!**
|
|
||||||
|
|
||||||
### Cosa Hai Ora
|
|
||||||
|
|
||||||
**v2.4:**
|
|
||||||
- ? Pausa per-asta
|
|
||||||
- ? Reset per-asta
|
|
||||||
- ? Log per-asta
|
|
||||||
- ? Solo contatore bidders
|
|
||||||
|
|
||||||
**v2.5:**
|
|
||||||
- ? Tutto di v2.4
|
|
||||||
- ? **Griglia bidders completa** ?
|
|
||||||
- ? **Ridimensionabile** ?
|
|
||||||
- ? **Aggiornamento real-time** ?
|
|
||||||
- ? **Layout 50/50** ?
|
|
||||||
|
|
||||||
### Il Risultato
|
|
||||||
|
|
||||||
**Informazioni Complete Per-Asta:**
|
|
||||||
- ?? Chi sta puntando
|
|
||||||
- ?? Quante puntate per utente
|
|
||||||
- ?? Classifica competitività
|
|
||||||
- ?? Log eventi
|
|
||||||
- ?? Impostazioni personalizzate
|
|
||||||
- ?? Controllo pausa
|
|
||||||
|
|
||||||
**Tutto in un'unica schermata!** ??
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Immediate
|
|
||||||
1. Test griglia bidders
|
|
||||||
2. Verifica ridimensionamento
|
|
||||||
3. Test aggiornamento real-time
|
|
||||||
|
|
||||||
### Se Problemi
|
|
||||||
- **Griglia vuota**: Verifica ItemsSource binding
|
|
||||||
- **Non ridimensiona**: Check GridSplitter MinWidth
|
|
||||||
- **Non aggiorna**: Verifica `_selectedAuction` reference
|
|
||||||
|
|
||||||
### Future v2.6
|
|
||||||
- [ ] Export dati bidders CSV
|
|
||||||
- [ ] Grafici puntate nel tempo
|
|
||||||
- [ ] Statistiche avanzate per bidder
|
|
||||||
- [ ] Highlight bidder sospetti (troppi click)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.5 - Complete Per-Auction Bidders Analysis*
|
|
||||||
*Know your competition! ????*
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
# ? v2.5 - BIDDERS PER-AUCTION COMPLETATA
|
|
||||||
|
|
||||||
## ?? Modifica Implementata
|
|
||||||
|
|
||||||
### Richiesta
|
|
||||||
**Aggiungere griglia utenti per-asta** affiancata al log con ridimensionamento.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Nuovo Layout Dettagli
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Utenti: 3 ? ? Log asta ?
|
|
||||||
? ???????????????? ? ????????????????????? ?
|
|
||||||
? ? Utente Punt?? ? ? 10:23 - Click #1 ? ?
|
|
||||||
? ? user1 5 ?? ? ? 10:24 - Reset #1 ? ?
|
|
||||||
? ? user2 3 ?? ? ? 10:25 - Puntata ? ?
|
|
||||||
? ? Tu 2 ?? ? ? ? ?
|
|
||||||
? ???????????????? ? ????????????????????? ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? = GridSplitter ridimensionabile (??)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Layout 50/50 ridimensionabile!** ??
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Cosa C'è di Nuovo
|
|
||||||
|
|
||||||
### 1. ? Griglia Bidders Per-Asta
|
|
||||||
- Colonne: **Utente** + **Puntate**
|
|
||||||
- Ordinamento: **Decrescente** per numero puntate
|
|
||||||
- Stile: Dark theme coerente
|
|
||||||
- Font: 10px compatto
|
|
||||||
|
|
||||||
### 2. ? GridSplitter Orizzontale
|
|
||||||
- Larghezza: 6px
|
|
||||||
- Ridimensionabile: ? ?
|
|
||||||
- MinWidth: 100px per lato
|
|
||||||
- Preview drag: Sì
|
|
||||||
|
|
||||||
### 3. ? Aggiornamento Real-Time
|
|
||||||
- Nuova puntata ? Griglia aggiornata
|
|
||||||
- Nuovo utente ? Aggiunto in lista
|
|
||||||
- Utente esistente ? Contatore incrementato + riordinato
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Tecniche
|
|
||||||
|
|
||||||
### XAML
|
|
||||||
```xml
|
|
||||||
<!-- Prima: Log solo -->
|
|
||||||
<TextBox x:Name="SelectedAuctionLog" Grid.Row="3" ... />
|
|
||||||
|
|
||||||
<!-- Ora: Grid con 3 colonne -->
|
|
||||||
<Grid Grid.Row="2">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" MinWidth="100" /> <!-- Bidders -->
|
|
||||||
<ColumnDefinition Width="6" /> <!-- Splitter -->
|
|
||||||
<ColumnDefinition Width="*" MinWidth="100" /> <!-- Log -->
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<DataGrid x:Name="SelectedAuctionBiddersGrid" Grid.Column="0" ... />
|
|
||||||
<GridSplitter Grid.Column="1" ... />
|
|
||||||
<TextBox x:Name="SelectedAuctionLog" Grid.Column="2" ... />
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
### C#
|
|
||||||
```csharp
|
|
||||||
// Popola griglia
|
|
||||||
var biddersList = auction.AuctionBidders
|
|
||||||
.OrderByDescending(kvp => kvp.Value) // Top puntatori in alto
|
|
||||||
.ToList();
|
|
||||||
biddersGrid.ItemsSource = biddersList;
|
|
||||||
|
|
||||||
// Binding automatico
|
|
||||||
// kvp.Key ? Colonna "Utente"
|
|
||||||
// kvp.Value ? Colonna "Puntate"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Come Funziona
|
|
||||||
|
|
||||||
### Selezione Asta
|
|
||||||
1. Click su "Galaxy S25"
|
|
||||||
2. ? Griglia bidders popolata (sinistra)
|
|
||||||
3. ? Log popolato (destra)
|
|
||||||
|
|
||||||
### Aggiornamento
|
|
||||||
**Quando qualcuno punta:**
|
|
||||||
1. Griglia si aggiorna
|
|
||||||
2. Contatore incrementa
|
|
||||||
3. Lista riordinata
|
|
||||||
|
|
||||||
### Ridimensionamento
|
|
||||||
- Trascina splitter ? ? per bilanciare spazio
|
|
||||||
- MinWidth 100px garantito
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Esempio Output
|
|
||||||
|
|
||||||
### Griglia Bidders
|
|
||||||
```
|
|
||||||
????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
????????????????????
|
|
||||||
? user1 5 ? ? Più attivo
|
|
||||||
? user2 3 ?
|
|
||||||
? Tu 2 ?
|
|
||||||
? user3 1 ?
|
|
||||||
????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ordinamento automatico per competitività!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Test Rapido
|
|
||||||
|
|
||||||
1. Apri AutoBidder ? Multi-Asta
|
|
||||||
2. Aggiungi aste ai preferiti
|
|
||||||
3. Avvia monitoraggio
|
|
||||||
4. **Click su asta** ? Pannello dettagli
|
|
||||||
5. ? Vedi griglia bidders (sinistra)?
|
|
||||||
6. ? Vedi log (destra)?
|
|
||||||
7. **Trascina splitter** ? ?
|
|
||||||
8. ? Ridimensiona correttamente?
|
|
||||||
9. **Aspetta puntate**
|
|
||||||
10. ? Griglia si aggiorna?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Documentazione
|
|
||||||
|
|
||||||
- **v2.5_BIDDERS_PER_AUCTION.md** - Guida completa
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**v2.5 Completata! Analisi completa per-asta! ?????**
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
# ? v2.6 - UI POLISH & AUTO-NAVIGATION
|
|
||||||
|
|
||||||
## ?? Modifiche Completate
|
|
||||||
|
|
||||||
### 1. ? Margini Simmetrici Utenti/Log
|
|
||||||
|
|
||||||
**PRIMA:**
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,4">
|
|
||||||
```
|
|
||||||
? Top 8px, Bottom 4px (asimmetrico)
|
|
||||||
|
|
||||||
**ORA:**
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,8">
|
|
||||||
```
|
|
||||||
? Top 8px, Bottom 8px (simmetrico)
|
|
||||||
|
|
||||||
**Visual balance perfetto! ??**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. ? Navigazione Automatica ai Preferiti
|
|
||||||
|
|
||||||
**All'avvio (se Multi-Asta default):**
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. ? Naviga automaticamente a: https://it.bidoo.com/?tab=FAV
|
|
||||||
3. ? Address bar aggiornata
|
|
||||||
4. ? Aste preferite già visibili
|
|
||||||
```
|
|
||||||
|
|
||||||
**Switch a Multi-Asta:**
|
|
||||||
```
|
|
||||||
1. Click Multi-Asta
|
|
||||||
2. ? Controlla URL corrente
|
|
||||||
3. ? Naviga SOLO se non già sui Preferiti
|
|
||||||
4. ? Evita reload inutili
|
|
||||||
```
|
|
||||||
|
|
||||||
**Intelligente e veloce! ?**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Tecniche
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
- Margin Grid Row 2: `8,8,8,4` ? `8,8,8,8`
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
|
|
||||||
**1. Costruttore:**
|
|
||||||
```csharp
|
|
||||||
if (_isMultiAuctionMode)
|
|
||||||
{
|
|
||||||
Loaded += MainWindow_Loaded; // ? Auto-navigate
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Nuovo Handler:**
|
|
||||||
```csharp
|
|
||||||
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
const string favUrl = "https://it.bidoo.com/?tab=FAV";
|
|
||||||
|
|
||||||
if (webView.CoreWebView2 == null)
|
|
||||||
await webView.EnsureCoreWebView2Async();
|
|
||||||
|
|
||||||
webView.CoreWebView2?.Navigate(favUrl);
|
|
||||||
addressBar.Text = favUrl;
|
|
||||||
|
|
||||||
Log($"?? Navigazione automatica a: {favUrl}");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. MultiAuctionButton_Click:**
|
|
||||||
```csharp
|
|
||||||
// ? Smart check: naviga solo se necessario
|
|
||||||
var currentUrl = webView.CoreWebView2?.Source ?? "";
|
|
||||||
|
|
||||||
if (!currentUrl.Contains("tab=FAV", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
webView.CoreWebView2?.Navigate(favUrl);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Benefici
|
|
||||||
|
|
||||||
### UX Migliorata
|
|
||||||
- **-40% step iniziali** (da 5 a 3)
|
|
||||||
- **Accesso immediato** ai Preferiti
|
|
||||||
- **Zero configurazione** manuale
|
|
||||||
|
|
||||||
### UI Professionale
|
|
||||||
- **Margini perfettamente simmetrici**
|
|
||||||
- **Visual balance** coerente
|
|
||||||
- **Aspetto pulito**
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
- **Smart navigation** (no reload inutili)
|
|
||||||
- **URL check** prima di navigate
|
|
||||||
- **Async loading** WebView2
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Test Rapido
|
|
||||||
|
|
||||||
### Test 1: Primo Avvio
|
|
||||||
1. Chiudi AutoBidder
|
|
||||||
2. Riapri
|
|
||||||
3. ? Va automaticamente ai Preferiti?
|
|
||||||
4. ? Address bar mostra "...?tab=FAV"?
|
|
||||||
5. ? Log conferma navigazione?
|
|
||||||
|
|
||||||
### Test 2: Margini
|
|
||||||
1. Apri dettagli asta
|
|
||||||
2. ? Spazio sopra/sotto Utenti e Log uguale?
|
|
||||||
3. ? Visual balance simmetrico?
|
|
||||||
|
|
||||||
### Test 3: Switch Modalità
|
|
||||||
1. Già sui Preferiti
|
|
||||||
2. Click Asta Singola
|
|
||||||
3. Click Multi-Asta
|
|
||||||
4. ? NON reload pagina?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Documentazione
|
|
||||||
|
|
||||||
- **v2.6_UI_POLISH.md** - Guida completa
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**v2.6 Completata! UI perfetta, UX ottimizzata! ????**
|
|
||||||
@@ -1,476 +0,0 @@
|
|||||||
# ?? AutoBidder v2.6 - UI Polish & Auto-Navigation
|
|
||||||
|
|
||||||
## ? Modifiche Completate
|
|
||||||
|
|
||||||
### ?? Lista Richieste
|
|
||||||
|
|
||||||
1. ? **Margini simmetrici** Utenti/Log (8px bottom)
|
|
||||||
2. ? **Navigazione automatica** ai Preferiti all'avvio (se Multi-Asta)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifica 1: Margini Simmetrici
|
|
||||||
|
|
||||||
### PRIMA (v2.5)
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,4">
|
|
||||||
<!-- Top: 8px, Bottom: 4px ? -->
|
|
||||||
```
|
|
||||||
|
|
||||||
**Problema:**
|
|
||||||
- Top margin: 8px
|
|
||||||
- Bottom margin: 4px
|
|
||||||
- **Asimmetrico** ?
|
|
||||||
|
|
||||||
### ORA (v2.6)
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,8">
|
|
||||||
<!-- Top: 8px, Bottom: 8px ? -->
|
|
||||||
```
|
|
||||||
|
|
||||||
**Risultato:**
|
|
||||||
- Top margin: 8px
|
|
||||||
- Bottom margin: 8px
|
|
||||||
- **Perfettamente simmetrico** ?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Visual Comparison
|
|
||||||
|
|
||||||
### Prima (v2.5)
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ? 8px top margin ?
|
|
||||||
? ???????????????? ? ???????????????????? ?
|
|
||||||
? ? Utenti ? ? ? Log ? ?
|
|
||||||
? ???????????????? ? ???????????????????? ?
|
|
||||||
? ? 4px bottom (asimmetrico) ? ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
### Ora (v2.6)
|
|
||||||
|
|
||||||
```
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
? ? 8px top margin ?
|
|
||||||
? ???????????????? ? ???????????????????? ?
|
|
||||||
? ? Utenti ? ? ? Log ? ?
|
|
||||||
? ???????????????? ? ???????????????????? ?
|
|
||||||
? ? 8px bottom (simmetrico) ? ?
|
|
||||||
???????????????????????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Equilibrio visivo perfetto! ??**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifica 2: Navigazione Automatica Preferiti
|
|
||||||
|
|
||||||
### Comportamento v2.5
|
|
||||||
|
|
||||||
**All'avvio:**
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Multi-Asta già selezionato
|
|
||||||
3. Pagina: https://it.bidoo.com (homepage)
|
|
||||||
4. ? Devi cliccare Multi-Asta per andare ai Preferiti
|
|
||||||
```
|
|
||||||
|
|
||||||
**Manuale e ripetitivo! ?**
|
|
||||||
|
|
||||||
### Comportamento v2.6
|
|
||||||
|
|
||||||
**All'avvio:**
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Multi-Asta già selezionato
|
|
||||||
3. ? Naviga AUTOMATICAMENTE a: https://it.bidoo.com/?tab=FAV
|
|
||||||
4. ? Aste preferite già visibili!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Automatico e veloce! ?**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Code (C#)
|
|
||||||
|
|
||||||
### 1. Costruttore MainWindow
|
|
||||||
|
|
||||||
**PRIMA (v2.5):**
|
|
||||||
```csharp
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
// ... inizializzazione ...
|
|
||||||
|
|
||||||
UpdateModeButtons();
|
|
||||||
|
|
||||||
// ? Nessuna navigazione automatica
|
|
||||||
|
|
||||||
webView.NavigationCompleted += ...;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.6):**
|
|
||||||
```csharp
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
// ... inizializzazione ...
|
|
||||||
|
|
||||||
UpdateModeButtons();
|
|
||||||
|
|
||||||
// ? NUOVO: Naviga automaticamente se Multi-Asta
|
|
||||||
if (_isMultiAuctionMode)
|
|
||||||
{
|
|
||||||
Loaded += MainWindow_Loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
webView.NavigationCompleted += ...;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Trigger evento Loaded per navigazione automatica!**
|
|
||||||
|
|
||||||
### 2. Nuovo Handler MainWindow_Loaded
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const string favUrl = "https://it.bidoo.com/?tab=FAV";
|
|
||||||
|
|
||||||
// Aspetta inizializzazione WebView2
|
|
||||||
if (webView.CoreWebView2 == null)
|
|
||||||
{
|
|
||||||
await webView.EnsureCoreWebView2Async();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Naviga ai preferiti
|
|
||||||
webView.CoreWebView2?.Navigate(favUrl);
|
|
||||||
|
|
||||||
// Aggiorna address bar
|
|
||||||
var addressBar = FindName("AddressBar") as TextBox;
|
|
||||||
if (addressBar != null) addressBar.Text = favUrl;
|
|
||||||
|
|
||||||
Log($"?? Navigazione automatica a: {favUrl}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log($"Errore navigazione automatica: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- ? Aspetta inizializzazione WebView2
|
|
||||||
- ? Naviga a Preferiti
|
|
||||||
- ? Aggiorna address bar
|
|
||||||
- ? Log conferma
|
|
||||||
- ? Error handling
|
|
||||||
|
|
||||||
### 3. MultiAuctionButton_Click Aggiornato
|
|
||||||
|
|
||||||
**PRIMA (v2.5):**
|
|
||||||
```csharp
|
|
||||||
private async void MultiAuctionButton_Click(...)
|
|
||||||
{
|
|
||||||
_isMultiAuctionMode = true;
|
|
||||||
UpdateModeButtons();
|
|
||||||
|
|
||||||
// Naviga SEMPRE ai preferiti
|
|
||||||
const string favUrl = "https://it.bidoo.com/?tab=FAV";
|
|
||||||
webView.CoreWebView2?.Navigate(favUrl);
|
|
||||||
AddressBar.Text = favUrl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**ORA (v2.6):**
|
|
||||||
```csharp
|
|
||||||
private async void MultiAuctionButton_Click(...)
|
|
||||||
{
|
|
||||||
_isMultiAuctionMode = true;
|
|
||||||
UpdateModeButtons();
|
|
||||||
|
|
||||||
// ? Naviga SOLO se non già sui preferiti
|
|
||||||
const string favUrl = "https://it.bidoo.com/?tab=FAV";
|
|
||||||
var currentUrl = webView.CoreWebView2?.Source ?? "";
|
|
||||||
|
|
||||||
if (!currentUrl.Contains("tab=FAV", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
webView.CoreWebView2?.Navigate(favUrl);
|
|
||||||
addressBar.Text = favUrl;
|
|
||||||
Log($"?? Navigazione a: {favUrl}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ottimizzazione:**
|
|
||||||
- ? Controlla URL corrente
|
|
||||||
- ? Naviga solo se necessario
|
|
||||||
- ? Evita reload inutili
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Workflow Utente v2.6
|
|
||||||
|
|
||||||
### Scenario 1: Primo Avvio
|
|
||||||
|
|
||||||
**v2.5:**
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. Vedi homepage Bidoo
|
|
||||||
3. Click Multi-Asta
|
|
||||||
4. Ora vai ai Preferiti
|
|
||||||
5. Puoi usare il programma
|
|
||||||
```
|
|
||||||
**5 step** ?
|
|
||||||
|
|
||||||
**v2.6:**
|
|
||||||
```
|
|
||||||
1. Apri AutoBidder
|
|
||||||
2. ? Già sui Preferiti!
|
|
||||||
3. Puoi usare subito
|
|
||||||
```
|
|
||||||
**3 step, -40% tempo!** ?
|
|
||||||
|
|
||||||
### Scenario 2: Switch Modalità
|
|
||||||
|
|
||||||
**Da Asta Singola ? Multi-Asta:**
|
|
||||||
|
|
||||||
**v2.5:**
|
|
||||||
```
|
|
||||||
1. Click Multi-Asta
|
|
||||||
2. Sempre navigate ai Preferiti
|
|
||||||
(anche se ci sei già)
|
|
||||||
```
|
|
||||||
|
|
||||||
**v2.6:**
|
|
||||||
```
|
|
||||||
1. Click Multi-Asta
|
|
||||||
2. ? Naviga SOLO se serve
|
|
||||||
(controlla URL corrente)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Intelligente e efficiente!** ?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Confronto Versioni
|
|
||||||
|
|
||||||
### Margini UI
|
|
||||||
|
|
||||||
| Elemento | v2.5 | v2.6 | Miglioramento |
|
|
||||||
|----------|------|------|---------------|
|
|
||||||
| Top margin | 8px | 8px | - |
|
|
||||||
| Bottom margin | 4px | **8px** ? | **Simmetria** |
|
|
||||||
| Visual balance | ? | ? | **Perfetto** |
|
|
||||||
|
|
||||||
### Navigazione Automatica
|
|
||||||
|
|
||||||
| Scenario | v2.5 | v2.6 | Beneficio |
|
|
||||||
|----------|------|------|-----------|
|
|
||||||
| Avvio app | Homepage | **Preferiti** ? | **Immediato** |
|
|
||||||
| Click Multi-Asta | Sempre navigate | **Solo se serve** ? | **Ottimizzato** |
|
|
||||||
| Step iniziali | 5 | **3** ? | **-40%** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Benefici v2.6
|
|
||||||
|
|
||||||
### 1. UI Più Pulita
|
|
||||||
|
|
||||||
**Margini simmetrici:**
|
|
||||||
- Visual balance perfetto
|
|
||||||
- Aspetto professionale
|
|
||||||
- Coerenza con resto UI
|
|
||||||
|
|
||||||
### 2. UX Migliorata
|
|
||||||
|
|
||||||
**Navigazione automatica:**
|
|
||||||
- ? Risparmio tempo all'avvio
|
|
||||||
- ? Meno click necessari
|
|
||||||
- ? Esperienza fluida
|
|
||||||
- ? Immediate access ai Preferiti
|
|
||||||
|
|
||||||
### 3. Efficienza
|
|
||||||
|
|
||||||
**Smart navigation:**
|
|
||||||
- Naviga solo quando necessario
|
|
||||||
- Evita reload inutili
|
|
||||||
- Controlla stato corrente
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
|
|
||||||
**Modifica:**
|
|
||||||
```xml
|
|
||||||
<!-- Prima -->
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,4">
|
|
||||||
|
|
||||||
<!-- Ora -->
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,8,8">
|
|
||||||
```
|
|
||||||
|
|
||||||
**Righe modificate:** 1
|
|
||||||
|
|
||||||
### MainWindow.xaml.cs
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. Costruttore: Aggiungi `Loaded` event handler se Multi-Asta
|
|
||||||
2. Nuovo metodo: `MainWindow_Loaded` per auto-navigazione
|
|
||||||
3. `MultiAuctionButton_Click`: Check URL prima di navigate
|
|
||||||
|
|
||||||
**Righe aggiunte:** ~25
|
|
||||||
**Righe modificate:** ~10
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build Status
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
? Pronto per il test!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Testing Checklist
|
|
||||||
|
|
||||||
### Margini UI
|
|
||||||
- [ ] Apri dettagli asta
|
|
||||||
- [ ] Verifica spazio sopra Utenti/Log: 8px
|
|
||||||
- [ ] Verifica spazio sotto Utenti/Log: 8px
|
|
||||||
- [ ] Simmetria visiva confermata
|
|
||||||
|
|
||||||
### Navigazione Automatica
|
|
||||||
- [ ] **Test 1:** Apri AutoBidder (prima volta)
|
|
||||||
- ? Va automaticamente a Preferiti?
|
|
||||||
- ? Address bar aggiornata?
|
|
||||||
- ? Log conferma navigazione?
|
|
||||||
|
|
||||||
- [ ] **Test 2:** Switch Asta Singola ? Multi-Asta
|
|
||||||
- ? Naviga a Preferiti?
|
|
||||||
|
|
||||||
- [ ] **Test 3:** Già sui Preferiti, click Multi-Asta
|
|
||||||
- ? NON reload pagina?
|
|
||||||
- ? Rimane stabile?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Dettagli Tecnici
|
|
||||||
|
|
||||||
### Event Lifecycle
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Constructor executes
|
|
||||||
2. InitializeComponent()
|
|
||||||
3. UpdateModeButtons()
|
|
||||||
4. if (_isMultiAuctionMode) ? Register Loaded handler
|
|
||||||
5. Window shows
|
|
||||||
6. ? Loaded event fires
|
|
||||||
7. MainWindow_Loaded() executes
|
|
||||||
8. Navigate to Preferiti
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timing perfetto! ??**
|
|
||||||
|
|
||||||
### URL Check Logic
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var currentUrl = webView.CoreWebView2?.Source ?? "";
|
|
||||||
|
|
||||||
if (!currentUrl.Contains("tab=FAV", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// Navigate only if NOT already on Favorites
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Smart check:**
|
|
||||||
- Case-insensitive
|
|
||||||
- Safe null handling
|
|
||||||
- Efficient string check
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione v2.6
|
|
||||||
|
|
||||||
### Obiettivi Raggiunti
|
|
||||||
|
|
||||||
? **UI Polish Completato**
|
|
||||||
- Margini perfettamente simmetrici
|
|
||||||
- Visual balance professionale
|
|
||||||
|
|
||||||
? **UX Ottimizzata**
|
|
||||||
- Navigazione automatica all'avvio
|
|
||||||
- Accesso immediato ai Preferiti
|
|
||||||
- -40% step iniziali
|
|
||||||
|
|
||||||
### Progressione Versioni
|
|
||||||
|
|
||||||
**v2.5:**
|
|
||||||
- ? Griglia bidders per-asta
|
|
||||||
- ? Layout ridimensionabile
|
|
||||||
- ? Margini asimmetrici
|
|
||||||
- ? Navigazione manuale
|
|
||||||
|
|
||||||
**v2.6:**
|
|
||||||
- ? Tutto di v2.5
|
|
||||||
- ? **Margini simmetrici** ?
|
|
||||||
- ? **Auto-navigate Preferiti** ?
|
|
||||||
- ? **Smart URL check** ?
|
|
||||||
|
|
||||||
### Il Risultato
|
|
||||||
|
|
||||||
**Esperienza Utente Ottimale:**
|
|
||||||
|
|
||||||
1. **Apri app** ? Già sui Preferiti ?
|
|
||||||
2. **Visual balance** ? Perfetto ?
|
|
||||||
3. **Zero step manuali** ? Tutto automatico ?
|
|
||||||
4. **Performance** ? Smart navigation ?
|
|
||||||
|
|
||||||
**Ready to bid! ??**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi
|
|
||||||
|
|
||||||
### Test Immediate
|
|
||||||
1. Verifica navigazione automatica
|
|
||||||
2. Controlla margini simmetrici
|
|
||||||
3. Test switch modalità
|
|
||||||
|
|
||||||
### Se Problemi
|
|
||||||
- **Navigazione non parte**: Check WebView2 initialization
|
|
||||||
- **URL non aggiornato**: Verifica `AddressBar.Text` update
|
|
||||||
- **Margini non simmetrici**: Force refresh UI
|
|
||||||
|
|
||||||
### Future v2.7
|
|
||||||
- [ ] Salva stato navigazione
|
|
||||||
- [ ] Remember last visited auction
|
|
||||||
- [ ] Quick jump to specific auction
|
|
||||||
- [ ] Bookmark favorite auctions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*AutoBidder v2.6 - Polished & Smart!*
|
|
||||||
*One click to start bidding! ???*
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
# ? v2.7 - VERTICAL LAYOUT
|
|
||||||
|
|
||||||
## ?? Modifica Completata
|
|
||||||
|
|
||||||
### Separazione Verticale Utenti/Log
|
|
||||||
|
|
||||||
**PRIMA (v2.6):**
|
|
||||||
```
|
|
||||||
???????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? ??????????? ? ???????????? ?
|
|
||||||
? ? Utenti ? ? Log ? ?
|
|
||||||
? ??????????? ???????????? ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
```
|
|
||||||
? **Layout orizzontale** (affiancati)
|
|
||||||
|
|
||||||
**ORA (v2.7):**
|
|
||||||
```
|
|
||||||
???????????????????????????????????????
|
|
||||||
? ?? Galaxy S25 [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Timer: [1] Min: [10] Max: [150] ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Utenti su questa asta: 3 ?
|
|
||||||
? ????????????????????????????????????
|
|
||||||
? ? user1 5 ??
|
|
||||||
? ? user2 3 ??
|
|
||||||
? ? Tu 2 ??
|
|
||||||
? ????????????????????????????????????
|
|
||||||
? ??????????????????????????????????? ? ? GridSplitter (?)
|
|
||||||
? Log asta ?
|
|
||||||
? ????????????????????????????????????
|
|
||||||
? ? 10:23 - Click #1 ??
|
|
||||||
? ? 10:24 - Reset #1 ??
|
|
||||||
? ????????????????????????????????????
|
|
||||||
???????????????????????????????????????
|
|
||||||
```
|
|
||||||
? **Layout verticale** (uno sopra l'altro)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Modifiche Codice (XAML)
|
|
||||||
|
|
||||||
### PRIMA
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,12,8">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" /> <!-- Utenti -->
|
|
||||||
<ColumnDefinition Width="6" /> <!-- Splitter -->
|
|
||||||
<ColumnDefinition Width="*" /> <!-- Log -->
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Grid Grid.Column="0">...</Grid>
|
|
||||||
<GridSplitter Grid.Column="1" Width="6" ... ResizeDirection="Columns" Cursor="SizeWE" />
|
|
||||||
<Grid Grid.Column="2">...</Grid>
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
### ORA
|
|
||||||
```xml
|
|
||||||
<Grid Grid.Row="2" Margin="8,8,12,8">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" MinHeight="80" /> <!-- Utenti -->
|
|
||||||
<RowDefinition Height="6" /> <!-- Splitter -->
|
|
||||||
<RowDefinition Height="*" MinHeight="80" /> <!-- Log -->
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Grid Grid.Row="0">...</Grid>
|
|
||||||
<GridSplitter Grid.Row="1" Height="6" ... ResizeDirection="Rows" Cursor="SizeNS" />
|
|
||||||
<Grid Grid.Row="2">...</Grid>
|
|
||||||
</Grid>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Differenze chiave:**
|
|
||||||
- `ColumnDefinitions` ? `RowDefinitions`
|
|
||||||
- `Grid.Column` ? `Grid.Row`
|
|
||||||
- `Width="6"` ? `Height="6"`
|
|
||||||
- `ResizeDirection="Columns"` ? `ResizeDirection="Rows"`
|
|
||||||
- `Cursor="SizeWE"` (?) ? `Cursor="SizeNS"` (?)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Caratteristiche Layout v2.7
|
|
||||||
|
|
||||||
### GridSplitter Verticale
|
|
||||||
- **Height:** 6px
|
|
||||||
- **Background:** `#1f2937` (grigio scuro)
|
|
||||||
- **Cursor:** `SizeNS` (? resize verticale)
|
|
||||||
- **ShowsPreview:** True
|
|
||||||
- **ResizeDirection:** Rows
|
|
||||||
|
|
||||||
### Sezioni Ridimensionabili
|
|
||||||
- **Utenti (sopra):**
|
|
||||||
- Height: `*` (espandibile)
|
|
||||||
- MinHeight: `80px` (garantito)
|
|
||||||
|
|
||||||
- **Log (sotto):**
|
|
||||||
- Height: `*` (espandibile)
|
|
||||||
- MinHeight: `80px` (garantito)
|
|
||||||
|
|
||||||
### Margini Simmetrici
|
|
||||||
```
|
|
||||||
Left: 8px (dal bordo interno)
|
|
||||||
Top: 8px (dal header impostazioni)
|
|
||||||
Right: 12px (verso GridSplitter principale)
|
|
||||||
Bottom: 8px (verso bordo bottom)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Benefici
|
|
||||||
|
|
||||||
### UX Migliorata
|
|
||||||
- ? **Più spazio verticale** per log (più visibile)
|
|
||||||
- ? **Griglia utenti più compatta** (nomi spesso corti)
|
|
||||||
- ? **Separazione logica** (dati vs eventi)
|
|
||||||
|
|
||||||
### Usabilità
|
|
||||||
- ? **Resize intuitivo** ? (trascina in alto/basso)
|
|
||||||
- ? **MinHeight garantito** (80px) evita collasso
|
|
||||||
- ? **Layout professionale** simile a IDE
|
|
||||||
|
|
||||||
### Coerenza
|
|
||||||
- ? **Stesso pattern** della griglia aste principale
|
|
||||||
- ? **Margini uniformi** in tutta l'app
|
|
||||||
- ? **GridSplitter visibili** e facili da usare
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Test Checklist
|
|
||||||
|
|
||||||
### Funzionalità Base
|
|
||||||
- [x] GridSplitter visibile tra Utenti e Log
|
|
||||||
- [x] Cursore ? appare sul separatore
|
|
||||||
- [x] Trascina separatore ridimensiona correttamente
|
|
||||||
- [x] MinHeight rispettato (80px)
|
|
||||||
|
|
||||||
### Edge Cases
|
|
||||||
- [x] Ridimensiona a dimensione minima
|
|
||||||
- [x] Ridimensiona a dimensione massima
|
|
||||||
- [x] Griglia utenti aggiornamento con resize
|
|
||||||
- [x] Log scroll automatico con resize
|
|
||||||
|
|
||||||
### Visual
|
|
||||||
- [x] Margini simmetrici rispetto ai bordi
|
|
||||||
- [x] Spazio corretto verso GridSplitter principale (12px)
|
|
||||||
- [x] Header Utenti/Log allineati
|
|
||||||
- [x] Colori coerenti con dark theme
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? File Modificati
|
|
||||||
|
|
||||||
### MainWindow.xaml
|
|
||||||
**Sezione modificata:**
|
|
||||||
- Grid Row 2 dei dettagli asta selezionata (Multi-Asta)
|
|
||||||
|
|
||||||
**Righe modificate:** ~60 (intero blocco Utenti/Log)
|
|
||||||
|
|
||||||
**Modifiche:**
|
|
||||||
1. ColumnDefinitions ? RowDefinitions
|
|
||||||
2. Grid.Column ? Grid.Row
|
|
||||||
3. GridSplitter Width ? Height
|
|
||||||
4. ResizeDirection Columns ? Rows
|
|
||||||
5. Cursor SizeWE ? SizeNS
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? Build Status
|
|
||||||
|
|
||||||
```
|
|
||||||
? Compilazione: SUCCESS
|
|
||||||
? Errori: 0
|
|
||||||
? Warning: 0
|
|
||||||
? Pronto per deploy!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Prossimi Passi Suggeriti
|
|
||||||
|
|
||||||
### v2.8 - Persistenza Dati
|
|
||||||
- [ ] Salva impostazioni per-asta su file JSON
|
|
||||||
- [ ] Carica automaticamente all'avvio
|
|
||||||
- [ ] Export/Import configurazioni
|
|
||||||
|
|
||||||
### v2.9 - Statistiche Avanzate
|
|
||||||
- [ ] Grafico vincite/perdite
|
|
||||||
- [ ] Tempo medio tra click
|
|
||||||
- [ ] Costo totale speso
|
|
||||||
- [ ] ROI per asta
|
|
||||||
|
|
||||||
### v3.0 - Machine Learning
|
|
||||||
- [ ] Predizione timer ottimale per asta
|
|
||||||
- [ ] Analisi pattern utenti competitor
|
|
||||||
- [ ] Suggerimenti strategici automatici
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**v2.7 Completata! Layout verticale ottimizzato! ???**
|
|
||||||
@@ -1,591 +1,158 @@
|
|||||||
# ?? AutoBidder - Bidoo Automation Tool
|
# AutoBidder - Guida completa all'uso
|
||||||
|
|
||||||
> **Programma intelligente per automatizzare le offerte su Bidoo.com**
|
> AutoBidder è uno strumento desktop per Windows (WPF, .NET 8) pensato per automatizzare le offerte sul sito Bidoo.com. Questa guida descrive caratteristiche, installazione, configurazione, modalità operative, strategie avanzate, dettagli tecnici e risoluzione dei problemi.
|
||||||
> Monitora le aste in tempo reale e piazza offerte precise al secondo ottimale per massimizzare le probabilità di vincita.
|
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ?? Indice
|
Sommario
|
||||||
|
- Caratteristiche principali
|
||||||
- [Caratteristiche Principali](#-caratteristiche-principali)
|
- Requisiti di sistema
|
||||||
- [Requisiti di Sistema](#-requisiti-di-sistema)
|
- Installazione e avvio
|
||||||
- [Installazione](#-installazione)
|
- Guida rapida (primi passi)
|
||||||
- [Guida Rapida](#-guida-rapida)
|
- Modalità operative: Asta Singola e Multi-Asta
|
||||||
- [Modalità Operative](#?-modalità-operative)
|
- Strategie e consigli pratici
|
||||||
- [Funzionalità Avanzate](#-funzionalità-avanzate)
|
- Dettagli tecnici: Polling, Click HTTP e sincronizzazione cookie
|
||||||
- [Impostazioni](#?-impostazioni)
|
- Impostazioni e persistenza
|
||||||
- [FAQ](#-faq)
|
- Esportazione e diagnostica
|
||||||
- [Changelog](#-changelog)
|
- FAQ e risoluzione problemi
|
||||||
- [Documentazione Dettagliata](#-documentazione-dettagliata)
|
- Changelog sintetico
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ?? Caratteristiche Principali
|
## Caratteristiche principali
|
||||||
|
- Monitoraggio in tempo reale di singole aste o molte aste contemporaneamente
|
||||||
|
- Due modalità operative: `Asta Singola` (massima precisione) e `Multi-Asta` (monitoraggio e auto-switch)
|
||||||
|
- Polling adattivo (HTTP / WebView2 / Active) per ridurre uso di CPU e RAM
|
||||||
|
- Click HTTP diretto (reverse engineered) con sincronizzazione dei cookie dal WebView2
|
||||||
|
- Persistenza della lista aste (`auctions.json`) e esportazione CSV delle statistiche
|
||||||
|
- UI dark theme moderna con griglia in tempo reale, dettagli asta, log e contatori
|
||||||
|
|
||||||
### ? Automazione Intelligente
|
## Requisiti di sistema
|
||||||
- **Click ultra-precisi** al secondo esatto del timer
|
- Windows 10 (1809+) o Windows 11
|
||||||
- **Polling dinamico** (20-400ms) basato sul timer dell'asta
|
- .NET 8.0 Runtime
|
||||||
- **Lettura diretta** delle variabili JavaScript di Bidoo
|
- RAM: 4 GB (consigliati 8 GB)
|
||||||
- **Multi-click paralleli** per massima affidabilità
|
- Connessione internet stabile
|
||||||
|
|
||||||
### ?? Due Modalità Operative
|
## Installazione e avvio
|
||||||
|
1. Assicurarsi di avere .NET 8.0 Runtime installato: `dotnet --version` (output: 8.0.x)
|
||||||
|
2. Clonare il repository (privato):
|
||||||
|
- `git clone https://192.168.30.23/Alby96/Mimante`
|
||||||
|
3. Costruire il progetto:
|
||||||
|
- `dotnet restore`
|
||||||
|
- `dotnet build --configuration Release`
|
||||||
|
4. Eseguire l'app:
|
||||||
|
- `dotnet run` (dalla cartella del progetto) oppure avviare `AutoBidder.exe` in `bin\\Release\\net8.0-windows`
|
||||||
|
|
||||||
#### ?? Modalità Asta Singola
|
## Guida rapida (primi passi)
|
||||||
- Monitoraggio **intensivo** di una singola asta
|
1. Avvia l'app: l'interfaccia principale mostra due pannelli (controlli a sinistra, browser WebView2 a destra).
|
||||||
- Statistiche in tempo reale (click, reset, prezzo)
|
2. Login: accedi a `bidoo.com` tramite il browser integrato (se vuoi usare il Click HTTP diretto devi essere loggato).
|
||||||
- Elenco completo degli utenti competitori
|
3. Scegli modalità:
|
||||||
- Log dettagliato di ogni operazione
|
- `Asta Singola` per concentrarti su un solo oggetto
|
||||||
|
- `Multi-Asta` per monitorare più aste e lasciare che l'app esegua auto-switch
|
||||||
|
4. Aggiungi aste (Multi-Asta):
|
||||||
|
- Metodo Automatico: vai sulla pagina Preferiti e lascia che l'app rilevi le aste
|
||||||
|
- Metodo Manuale: clicca `+ URL` o `Pagina` e incolla/aggiungi l'URL dell'asta
|
||||||
|
5. Configura impostazioni globali o per-asta (Timer Click, Min/Max Price, Max Clicks, Max Resets, Ritardo, Multi-Click)
|
||||||
|
6. Premi `Avvia` per attivare il Click Loop; il background polling rimane sempre attivo anche senza Avvia.
|
||||||
|
|
||||||
#### ?? Modalità Multi-Asta
|
## Modalità operative
|
||||||
- Monitoraggio **simultaneo** di tutte le aste preferite
|
|
||||||
- **Auto-switch** sull'asta con timer più basso
|
|
||||||
- Gestione **indipendente** per ogni asta:
|
|
||||||
- Impostazioni personalizzate (timer, prezzi)
|
|
||||||
- Pausa/Riprendi per-asta
|
|
||||||
- Log e statistiche separate
|
|
||||||
- Griglia in tempo reale con aggiornamenti istantanei
|
|
||||||
|
|
||||||
### ?? Interfaccia Moderna
|
### Asta Singola
|
||||||
- **Dark theme** professionale GitHub-style
|
- Ideale per oggetti di valore dove la precisione è critica.
|
||||||
- **Layout ridimensionabile** con GridSplitter
|
- Monitoraggio intensivo del DOM tramite WebView2, contatori dettagliati, lista utenti e log dedicato.
|
||||||
- **Visualizzazione dual-panel** (controlli + browser)
|
- Supporta `Multi-Click` (click multipli paralleli) per aumentare probabilità in connessione instabile.
|
||||||
- **Indicatori visivi** di stato (verde = tua puntata, arancione = pausa)
|
- Impostazioni consigliate per asta singola: `Timer Click` 0-1, `Multi-Click` ON, `Ritardo` 0ms.
|
||||||
|
|
||||||
### ?? Sicurezza
|
### Multi-Asta
|
||||||
- Navigazione **limitata a Bidoo.com**
|
- Monitoraggio simultaneo di molte aste.
|
||||||
- **Blocco automatico** di link esterni
|
- L'app punta solo sull'asta con `timer` più basso (auto-switch) per evitare concorrere contro se stessa.
|
||||||
- **Validazione URL** su tutti i domini Bidoo internazionali
|
- Per ogni asta è possibile impostare opzioni indipendenti (Timer Click, Min/Max Price, Pausa/Riprendi).
|
||||||
|
- Metodo manuale (URL diretto) è raccomandato per monitoraggi massivi (consumo risorse minimo).
|
||||||
|
|
||||||
|
## Strategie consigliate
|
||||||
|
- Monitoraggio massivo (50+ aste): usa `URL Manuale`, `Timer Click` 0, limiti di prezzo bassi.
|
||||||
|
- Asta singola ad alto valore: `Timer Click` 0-1, `Multi-Click` ON, `Ritardo` 0ms.
|
||||||
|
- Caccia all'affare: `Max Price` molto basso, monitora molte aste con Timer Click 0.
|
||||||
|
|
||||||
|
## Approfondimento tecnico
|
||||||
|
|
||||||
|
### Polling adattivo (Dual-Track)
|
||||||
|
- Track 1 — Background Polling: esegue richieste HTTP ogni ~5s per aggiornare timer, prezzo e ultimo bidder. Mantiene uso CPU/RAM minimo.
|
||||||
|
- Track 2 — Click Loop: attivo solo dopo `Avvia`. Polling dinamico 20-400ms per aste critiche e invio dei click (HTTP diretto o WebView2 fallback).
|
||||||
|
|
||||||
|
### Click HTTP diretto
|
||||||
|
- Al momento dell'azione, il client costruisce una GET verso l'endpoint reverse engineered di Bidoo tipo:
|
||||||
|
`GET https://it.bidoo.com/bid.php?AID=81204347&sup=0&shock=0`
|
||||||
|
- Richiede i cookie di sessione (PHPSESSID, user_token, ecc.) che vengono sincronizzati dal WebView2.
|
||||||
|
- Latenza tipica: 10-30ms (molto più veloce del click via WebView2 che può impiegare 50-100ms)
|
||||||
|
- Se il Click HTTP fallisce, l'app esegue fallback automatico con `ExecuteScript` su WebView2.
|
||||||
|
|
||||||
|
### Sincronizzazione cookie
|
||||||
|
- Al primo `Avvia` viene letto il `CookieManager` di `CoreWebView2`, copiato in un `CookieContainer` per l'`HttpClient` utilizzato dai Click HTTP.
|
||||||
|
- I cookie sono conservati solo in memoria, mai su disco. Devono essere rinfrescati ri-effettuando il login nel WebView2 se scadono.
|
||||||
|
|
||||||
|
## Persistenza e file locali
|
||||||
|
- Lista aste manuali salvata in:
|
||||||
|
`%AppData%\\AutoBidder\\auctions.json`
|
||||||
|
- La lista viene ricaricata automaticamente all'avvio dell'app.
|
||||||
|
- Esportazione CSV: la funzionalità `Export CSV` genera un file contenente statistiche per ogni asta (nome, ID, URL, timer, prezzo, strategy, click/resets, impostazioni per-asta).
|
||||||
|
|
||||||
|
## Impostazioni principali
|
||||||
|
- `Timer Click` (0-8): secondo del countdown al quale si desidera effettuare il click (0 = 0.0-0.9s)
|
||||||
|
- `Max Clicks` / `Max Resets`: limiti operativi (0 = illimitato)
|
||||||
|
- `Min/Max Price`: evita puntate fuori dal range desiderato
|
||||||
|
- `Ritardo (ms)`: delay aggiuntivo prima di inviare il click
|
||||||
|
- `Multi-Click`: invia più click paralleli (utile su connessioni con jitter)
|
||||||
|
|
||||||
|
## Interfaccia e controlli
|
||||||
|
- Pannello sinistro: controlli principali (modalità, Avvia, Pausa, Stop, aggiungi/rimuovi aste, esporta CSV)
|
||||||
|
- Pannello destro: browser integrato (WebView2) + dettagli asta quando selezionata
|
||||||
|
- Griglia aste (multi-asta): mostra Timer, Prezzo, Strategia, Clicks, Resets, Ultimo bidder
|
||||||
|
- Log in tempo reale per ogni asta con dettagli di latenza, risposta server e fallimenti
|
||||||
|
|
||||||
|
## Diagnostica ed esportazione
|
||||||
|
- Abilita log dettagliato prima di aprire issue o per analisi locali
|
||||||
|
- Usa `Export CSV` per conservare storici e confrontare strategie
|
||||||
|
- Mantieni screenshot del pannello log per report più chiari
|
||||||
|
|
||||||
|
## FAQ e risoluzione dei problemi
|
||||||
|
- "Non vedo Click HTTP riuscito": assicurati di essere loggato nel WebView2 e che la sincronizzazione cookie sia avvenuta (vedi log "Cookie sincronizzati (X cookie)"). Premi `Avvia` dopo il login.
|
||||||
|
- "Aste non rilevate": assicurati di essere nella pagina Preferiti per il metodo automatico oppure aggiungi gli URL manualmente.
|
||||||
|
- "Il programma non si avvia": verifica .NET 8.0 Runtime installato e che il build sia andato a buon fine.
|
||||||
|
- "Click non funzionano": verifica Timer Click, limiti di prezzo e connessione internet. Controlla se il fallback WebView è attivo nei log.
|
||||||
|
|
||||||
|
## Avvisi e responsabilità
|
||||||
|
- L'automazione potrebbe violare i Termini di Servizio di Bidoo. L'uso è a rischio e responsabilità dell'utente.
|
||||||
|
- Non salvare credenziali su disco: l'app non memorizza login, usa il WebView2 per la sessione.
|
||||||
|
- Cookie e dati di sessione rimangono in memoria e vengono rimossi alla chiusura dell'app.
|
||||||
|
|
||||||
|
## Changelog sintetico (ultime versioni)
|
||||||
|
- v2.10: Click HTTP diretto, sincronizzazione cookie automatica, miglioramenti prestazionali
|
||||||
|
- v2.9: Persistenza automatica, UI improvements, export CSV
|
||||||
|
- v2.8: Polling adattivo e strategie ibride
|
||||||
|
|
||||||
|
## Supporto
|
||||||
|
- Repository privato Gitea: `https://192.168.30.23/Alby96/Mimante`
|
||||||
|
- Per problemi tecnici aprire issue nel repository privato (se abilitato) o contattare il manutentore del progetto.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ?? Requisiti di Sistema
|
Note tecniche per sviluppatori
|
||||||
|
- Progetto target: `.NET 8.0` (WPF + WebView2)
|
||||||
### Minimi
|
- Aree chiave del codice:
|
||||||
- **Sistema Operativo:** Windows 10 (1809+) o Windows 11
|
- `Services\\BidooApiClient.cs` — gestione Click HTTP e parsing risposte
|
||||||
- **Framework:** .NET 8.0 Runtime
|
- `Services\\AuctionMonitor.cs` — loop di polling e logica auto-switch
|
||||||
- **RAM:** 4 GB
|
- `Services\\SessionManager.cs` — sincronizzazione cookie e HttpClient creation
|
||||||
- **Spazio Disco:** 100 MB
|
- `Utilities\\PersistenceManager.cs` — salvataggio/ricaricamento `auctions.json`
|
||||||
- **Connessione Internet:** Stabile e veloce
|
- `ViewModels\\AuctionViewModel.cs` + XAML corrispondenti — visualizzazione e binding UI
|
||||||
|
|
||||||
### Consigliati
|
## Contributi
|
||||||
- **RAM:** 8 GB o superiore
|
- Questo repository è privato. Per contribuire, aprire PR verso branch `main` e seguire le convenzioni del progetto.
|
||||||
- **Processore:** Quad-core o superiore
|
|
||||||
- **Connessione:** Fibra/ADSL (latenza < 50ms)
|
## Licenza
|
||||||
|
- Privato — non distribuire senza autorizzazione del proprietario.
|
||||||
---
|
|
||||||
|
Buona fortuna con le aste e usa AutoBidder responsabilmente.
|
||||||
## ?? Installazione
|
|
||||||
|
|
||||||
### 1. Prerequisiti
|
|
||||||
```bash
|
|
||||||
# Scarica e installa .NET 8.0 Runtime Desktop
|
|
||||||
# https://dotnet.microsoft.com/download/dotnet/8.0
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Clone Repository (Privato)
|
|
||||||
```bash
|
|
||||||
git clone https://192.168.30.23/Alby96/Mimante
|
|
||||||
cd Mimante\Mimante
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Build
|
|
||||||
```bash
|
|
||||||
dotnet restore
|
|
||||||
dotnet build --configuration Release
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Esecuzione
|
|
||||||
```bash
|
|
||||||
dotnet run
|
|
||||||
# oppure avvia AutoBidder.exe dalla cartella bin\Release\net8.0-windows
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Guida Rapida
|
|
||||||
|
|
||||||
### Primo Avvio (Modalità Multi-Asta)
|
|
||||||
|
|
||||||
1. **Apertura automatica**
|
|
||||||
? Il programma si apre direttamente sui **Preferiti di Bidoo**
|
|
||||||
|
|
||||||
2. **Aggiungi aste ai preferiti**
|
|
||||||
Naviga su Bidoo e clicca ? sulle aste che vuoi monitorare
|
|
||||||
|
|
||||||
3. **Avvia monitoraggio**
|
|
||||||
Clicca **"Avvia"** ? Le aste vengono scansionate automaticamente
|
|
||||||
|
|
||||||
4. **Seleziona un'asta** (opzionale)
|
|
||||||
Click sulla griglia ? Visualizza dettagli, log e utenti
|
|
||||||
|
|
||||||
5. **Personalizza** (opzionale)
|
|
||||||
Imposta Timer Click, Min/Max prezzo per ogni asta
|
|
||||||
|
|
||||||
6. **Osserva**
|
|
||||||
Il programma punta automaticamente sull'asta più vicina al momento del click
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ??? Modalità Operative
|
|
||||||
|
|
||||||
### ?? Asta Singola
|
|
||||||
|
|
||||||
**Quando usarla:**
|
|
||||||
- Focus totale su **un'asta specifica**
|
|
||||||
- Massima precisione e controllo
|
|
||||||
- Analisi dettagliata della competizione
|
|
||||||
|
|
||||||
**Workflow:**
|
|
||||||
```
|
|
||||||
1. Click "Asta Singola"
|
|
||||||
2. Naviga all'asta su Bidoo
|
|
||||||
3. Imposta Timer Click (0-8 secondi)
|
|
||||||
4. Click "Avvia"
|
|
||||||
5. Il programma punta al secondo esatto
|
|
||||||
```
|
|
||||||
|
|
||||||
**Impostazioni disponibili:**
|
|
||||||
- ?? **Timer Click:** Secondo del timer per puntare (0-8)
|
|
||||||
- ?? **Max Clicks:** Limite massimo di click (0 = illimitato)
|
|
||||||
- ?? **Max Resets:** Limite di reset dell'asta (0 = illimitato)
|
|
||||||
- ?? **Min/Max Price:** Range di prezzo accettabile
|
|
||||||
- ? **Ritardo (ms):** Delay aggiuntivo prima del click
|
|
||||||
- ??? **Multi-Click:** Click multipli paralleli per affidabilità
|
|
||||||
|
|
||||||
**Visualizzazione:**
|
|
||||||
- Contatori click/reset in tempo reale
|
|
||||||
- Prezzo corrente aggiornato
|
|
||||||
- Elenco utenti con numero puntate
|
|
||||||
- Log operazioni dettagliato
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### ?? Multi-Asta
|
|
||||||
|
|
||||||
**Quando usarla:**
|
|
||||||
- Monitorare **10+ aste contemporaneamente**
|
|
||||||
- Puntare automaticamente sulla **più conveniente**
|
|
||||||
- Gestire più strategie simultaneamente
|
|
||||||
|
|
||||||
**Workflow:**
|
|
||||||
```
|
|
||||||
1. Click "Multi-Asta" (già attivo di default)
|
|
||||||
2. Le aste preferite vengono rilevate automaticamente
|
|
||||||
3. Click "Avvia"
|
|
||||||
4. Il programma sceglie autonomamente dove puntare
|
|
||||||
```
|
|
||||||
|
|
||||||
**Strategia automatica:**
|
|
||||||
```
|
|
||||||
1. Legge timer di tutte le aste
|
|
||||||
2. Identifica quella con timer più basso
|
|
||||||
3. Verifica limiti prezzo (se impostati)
|
|
||||||
4. Verifica se in pausa
|
|
||||||
5. Punta al momento giusto
|
|
||||||
```
|
|
||||||
|
|
||||||
**Griglia Aste - Colonne:**
|
|
||||||
- ?? **Asta:** Nome prodotto
|
|
||||||
- ?? **Timer:** Tempo rimanente (aggiornamento real-time)
|
|
||||||
- ?? **Prezzo:** Prezzo corrente
|
|
||||||
- ??? **Clicks:** Tue puntate su questa asta
|
|
||||||
- ?? **Resets:** Numero di reset rilevati
|
|
||||||
- ?? **Ultimo:** Ultimo utente che ha puntato
|
|
||||||
|
|
||||||
**Indicatori visivi:**
|
|
||||||
- ?? **Verde:** Tua ultima puntata
|
|
||||||
- ?? **Arancione:** Asta in pausa
|
|
||||||
- ?? **Blu:** Asta selezionata
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ??? Funzionalità Avanzate
|
|
||||||
|
|
||||||
### ?? Gestione Per-Asta (Multi-Asta)
|
|
||||||
|
|
||||||
**Seleziona un'asta** dalla griglia per accedere a:
|
|
||||||
|
|
||||||
#### Pannello Dettagli
|
|
||||||
```
|
|
||||||
???????????????????????????????????????
|
|
||||||
? ?? [Nome Asta] [Pausa] [Riprendi] ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Timer Click: [0] Min€: [10] Max€: [150] ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
? Utenti su questa asta: 5 ?
|
|
||||||
? ??????????????????????????????? ?
|
|
||||||
? ? user1 12 puntate ? ?
|
|
||||||
? ? user2 8 puntate ? ?
|
|
||||||
? ? Tu 3 puntate ? ?
|
|
||||||
? ??????????????????????????????? ?
|
|
||||||
? ??????????????????????????????????? ?
|
|
||||||
? Log asta ?
|
|
||||||
? ??????????????????????????????? ?
|
|
||||||
? ? 10:23 - Click #1 ? ?
|
|
||||||
? ? 10:24 - Reset #1 ? ?
|
|
||||||
? ??????????????????????????????? ?
|
|
||||||
???????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Funzioni
|
|
||||||
- ?? **Pausa:** Stoppa temporaneamente questa asta (le altre continuano)
|
|
||||||
- ?? **Riprendi:** Riattiva l'asta
|
|
||||||
- ?? **Impostazioni:** Timer, Min/Max prezzo **solo per questa asta**
|
|
||||||
- ?? **Utenti:** Elenco ordinato per numero puntate
|
|
||||||
- ?? **Log:** Storico eventi specifico dell'asta
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### ?? Analisi Competizione
|
|
||||||
|
|
||||||
**Griglia Utenti (Asta Singola):**
|
|
||||||
```
|
|
||||||
????????????????????????????????????
|
|
||||||
? Utente Puntate Ultima ?
|
|
||||||
????????????????????????????????????
|
|
||||||
? user1 25 10:34 ?
|
|
||||||
? user2 18 10:33 ?
|
|
||||||
? Tu 12 10:35 ? ? Le tue
|
|
||||||
? user3 3 10:30 ?
|
|
||||||
????????????????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Griglia Utenti Per-Asta (Multi-Asta):**
|
|
||||||
```
|
|
||||||
????????????????????????
|
|
||||||
? Utente Puntate ?
|
|
||||||
????????????????????????
|
|
||||||
? user1 5 ?
|
|
||||||
? user2 3 ?
|
|
||||||
? Tu 2 ?
|
|
||||||
????????????????????????
|
|
||||||
```
|
|
||||||
|
|
||||||
**Cosa puoi scoprire:**
|
|
||||||
- ?? Chi punta di più (competitor principale)
|
|
||||||
- ?? Livello di competizione sull'asta
|
|
||||||
- ? Pattern temporali delle puntate
|
|
||||||
- ?? Bot sospetti (troppi click)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Impostazioni
|
|
||||||
|
|
||||||
### Impostazioni Globali (Asta Singola)
|
|
||||||
|
|
||||||
| Impostazione | Range | Default | Descrizione |
|
|
||||||
|--------------|-------|---------|-------------|
|
|
||||||
| **Max Clicks** | 0-? | 0 | Limite click totali (0 = illimitato) |
|
|
||||||
| **Max Resets** | 0-? | 0 | Limite reset asta (0 = illimitato) |
|
|
||||||
| **Min Price €** | 0-? | 0 | Prezzo minimo per puntare (0 = no limite) |
|
|
||||||
| **Max Price €** | 0-? | 0 | Prezzo massimo (0 = no limite) |
|
|
||||||
| **Timer Click** | 0-8 | 0 | Secondo del timer per click |
|
|
||||||
| **Ritardo (ms)** | 0-2000 | 0 | Delay aggiuntivo prima del click |
|
|
||||||
| **Multi-Click** | On/Off | Off | Click multipli paralleli |
|
|
||||||
|
|
||||||
### Impostazioni Per-Asta (Multi-Asta)
|
|
||||||
|
|
||||||
| Impostazione | Descrizione |
|
|
||||||
|--------------|-------------|
|
|
||||||
| **Timer Click** | Momento del click **solo per questa asta** |
|
|
||||||
| **Min €** | Prezzo minimo **solo per questa asta** |
|
|
||||||
| **Max €** | Prezzo massimo **solo per questa asta** |
|
|
||||||
| **Pausa/Riprendi** | Stato **solo per questa asta** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Controlli UI
|
|
||||||
|
|
||||||
### Pulsanti Principali
|
|
||||||
|
|
||||||
| Pulsante | Scorciatoia | Funzione |
|
|
||||||
|----------|-------------|----------|
|
|
||||||
| **Asta Singola** | - | Attiva modalità asta singola |
|
|
||||||
| **Multi-Asta** | - | Attiva modalità multi-asta |
|
|
||||||
| **Avvia** | - | Avvia automazione |
|
|
||||||
| **Pausa** | - | Pausa globale (tutte le aste) |
|
|
||||||
| **Stop** | - | Ferma automazione |
|
|
||||||
|
|
||||||
### Navigazione Browser
|
|
||||||
|
|
||||||
| Pulsante | Funzione |
|
|
||||||
|----------|----------|
|
|
||||||
| **Indietro** | Torna alla pagina precedente |
|
|
||||||
| **Aggiorna** | Ricarica la pagina corrente |
|
|
||||||
| **Vai** | Naviga all'URL inserito |
|
|
||||||
|
|
||||||
### Ridimensionamento
|
|
||||||
|
|
||||||
- **Pannello sinistro:** Trascina il separatore verticale ?
|
|
||||||
- **Griglia aste:** Trascina il separatore orizzontale ? (sopra dettagli)
|
|
||||||
- **Utenti/Log:** Trascina il separatore ? (tra utenti e log)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Strategie Consigliate
|
|
||||||
|
|
||||||
### Asta Singola - Oggetto di Valore Alto
|
|
||||||
```
|
|
||||||
Timer Click: 0-1 (molto aggressivo)
|
|
||||||
Max Price: [valore massimo disposto]
|
|
||||||
Multi-Click: ON
|
|
||||||
Ritardo: 0ms
|
|
||||||
```
|
|
||||||
**Perché:** Massima velocità su asta competitiva
|
|
||||||
|
|
||||||
### Multi-Asta - Aste a Basso Costo
|
|
||||||
```
|
|
||||||
Timer Click per asta: 2-3 (conservativo)
|
|
||||||
Min Price: 1€
|
|
||||||
Max Price: 20€
|
|
||||||
Pausa aste troppo alte
|
|
||||||
```
|
|
||||||
**Perché:** Punta solo su occasioni convenienti
|
|
||||||
|
|
||||||
### Multi-Asta - Caccia all'Affare
|
|
||||||
```
|
|
||||||
Max Price molto basso (es: 10€)
|
|
||||||
Timer Click: 0 (aggressivo)
|
|
||||||
Monitora 20+ aste
|
|
||||||
```
|
|
||||||
**Perché:** Prima o poi una scende sotto la soglia
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ? FAQ
|
|
||||||
|
|
||||||
### Come funziona il Timer Click?
|
|
||||||
Il **Timer Click** indica a quale **secondo** del countdown vuoi che il programma clicchi.
|
|
||||||
- **Timer Click = 0** ? Clicca tra 0.0s e 0.9s
|
|
||||||
- **Timer Click = 1** ? Clicca tra 1.0s e 1.9s
|
|
||||||
- **Timer Click = 2** ? Clicca tra 2.0s e 2.9s
|
|
||||||
|
|
||||||
?? **Consiglio:** 0-1 per massima aggressività, 2-3 per essere conservativi
|
|
||||||
|
|
||||||
### Perché l'asta si resetta?
|
|
||||||
Un **reset** avviene quando qualcuno vince l'asta (timer arriva a 0). Il timer riparte e l'asta continua.
|
|
||||||
Il programma **rileva automaticamente** i reset e mostra il vincitore.
|
|
||||||
|
|
||||||
### Posso puntare su più aste contemporaneamente?
|
|
||||||
**No**, il programma (in Multi-Asta) punta solo sull'asta con **timer più basso** in ogni momento.
|
|
||||||
Questo massimizza l'efficienza evitando sprechi.
|
|
||||||
|
|
||||||
### Cosa succede se imposto Min/Max Price?
|
|
||||||
Il programma **salta il click** se il prezzo è fuori dal range:
|
|
||||||
- Prezzo < Min ? ?? Click bloccato
|
|
||||||
- Prezzo > Max ? ?? Click bloccato
|
|
||||||
- Nel range ? ? Click eseguito
|
|
||||||
|
|
||||||
### Come metto in pausa una singola asta?
|
|
||||||
1. Passa a **Multi-Asta**
|
|
||||||
2. **Seleziona** l'asta dalla griglia
|
|
||||||
3. Click **"Pausa"** nel pannello dettagli
|
|
||||||
4. Solo quella asta viene fermata, le altre continuano
|
|
||||||
|
|
||||||
### Il Multi-Click migliora le probabilità?
|
|
||||||
**Sì!** Invia **2 click paralleli** a 20ms di distanza per compensare lag di rete.
|
|
||||||
?? Usa solo in Asta Singola su connessioni instabili.
|
|
||||||
|
|
||||||
### Posso usare AutoBidder su più computer?
|
|
||||||
**Tecnicamente sì**, ma **non consigliato**:
|
|
||||||
- Rischio di competere contro te stesso
|
|
||||||
- Spreco di click
|
|
||||||
- Ban potenziale da Bidoo
|
|
||||||
|
|
||||||
### È rilevabile da Bidoo?
|
|
||||||
Il programma **emula comportamento umano**:
|
|
||||||
- Usa il browser Microsoft Edge (WebView2)
|
|
||||||
- Click via JavaScript nativo
|
|
||||||
- Timing realistico
|
|
||||||
|
|
||||||
?? **Disclaimer:** Usa a tuo rischio. Bidoo potrebbe avere sistemi anti-bot.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Changelog
|
|
||||||
|
|
||||||
### v2.7 (Corrente) - Layout Verticale
|
|
||||||
- ? **Separazione verticale** Utenti/Log con GridSplitter
|
|
||||||
- ? **Margini ottimizzati** rispetto al bordo principale
|
|
||||||
- ? **MinHeight** garantito (80px) per entrambe le sezioni
|
|
||||||
|
|
||||||
### v2.6 - UI Polish & Auto-Navigation
|
|
||||||
- ? **Margini simmetrici** tra pannelli
|
|
||||||
- ? **Navigazione automatica** ai Preferiti all'avvio (Multi-Asta)
|
|
||||||
- ? **Smart URL check** evita reload inutili
|
|
||||||
|
|
||||||
### v2.5 - Bidders Per-Auction
|
|
||||||
- ? **Griglia utenti per-asta** con numero puntate
|
|
||||||
- ? **Layout 50/50 ridimensionabile** (Utenti | Log)
|
|
||||||
- ? **Aggiornamento real-time** quando qualcuno punta
|
|
||||||
|
|
||||||
### v2.4 - UI Refinements
|
|
||||||
- ? **Pausa/Riprendi per-asta** separati
|
|
||||||
- ? **Visual feedback** (aste in pausa colorate)
|
|
||||||
- ? **GridSplitter ingrandito** (12px) per migliore UX
|
|
||||||
|
|
||||||
### v2.3 - Multi-Auction Improvements
|
|
||||||
- ? **Log e bidders separati** per ogni asta
|
|
||||||
- ? **Impostazioni indipendenti** per-asta
|
|
||||||
- ? **Evidenziazione** riga verde quando è la tua puntata
|
|
||||||
|
|
||||||
### v2.2 - Per-Auction Management
|
|
||||||
- ? **Pannello dettagli asta selezionata**
|
|
||||||
- ? **Pausa individuale** (non globale)
|
|
||||||
- ? **Impostazioni personalizzate** per ogni asta
|
|
||||||
|
|
||||||
### v2.1 - Multi-Auction Core
|
|
||||||
- ? **Modalità Multi-Asta** implementata
|
|
||||||
- ? **Scansione automatica** aste preferite
|
|
||||||
- ? **Auto-switch** sull'asta con timer più basso
|
|
||||||
- ? **Griglia real-time** con 6 colonne
|
|
||||||
|
|
||||||
### v2.0 - Major Refactor
|
|
||||||
- ? **Dark theme** GitHub-style
|
|
||||||
- ? **Dual-panel layout** ridimensionabile
|
|
||||||
- ? **WebView2** integrato
|
|
||||||
- ? **Sicurezza navigazione** (solo Bidoo)
|
|
||||||
|
|
||||||
### v1.x - Initial Release
|
|
||||||
- ? **Automazione base** asta singola
|
|
||||||
- ?? **Lettura timer** da DOM
|
|
||||||
- ??? **Click automatico** al secondo target
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Documentazione Dettagliata
|
|
||||||
|
|
||||||
### File di Documentazione (nella cartella progetto)
|
|
||||||
|
|
||||||
| File | Descrizione |
|
|
||||||
|------|-------------|
|
|
||||||
| `PROJECT_SUMMARY.md` | Panoramica completa del progetto |
|
|
||||||
| `CHANGELOG.md` | Storico completo delle modifiche |
|
|
||||||
| `QUICK_REFERENCE.md` | Riferimento rapido comandi |
|
|
||||||
| `MULTI_AUCTION_GUIDE.md` | Guida dettagliata modalità Multi-Asta |
|
|
||||||
| `MULTI_AUCTION_GRID_GUIDE.md` | Funzionamento griglia aste |
|
|
||||||
| `IMPLEMENTATION_SUMMARY.md` | Dettagli tecnici implementazione |
|
|
||||||
|
|
||||||
### Versioni Dettagliate
|
|
||||||
|
|
||||||
| File | Versione | Contenuto |
|
|
||||||
|------|----------|-----------|
|
|
||||||
| `v2.7_VERTICAL_LAYOUT.md` | 2.7 | Separazione verticale Utenti/Log |
|
|
||||||
| `v2.6_UI_POLISH.md` | 2.6 | Margini e auto-navigazione |
|
|
||||||
| `v2.5_BIDDERS_PER_AUCTION.md` | 2.5 | Griglia utenti per-asta |
|
|
||||||
| `v2.4_UI_REFINEMENTS.md` | 2.4 | Pausa per-asta e feedback visivi |
|
|
||||||
| `v2.3_MULTI_AUCTION_IMPROVEMENTS.md` | 2.3 | Log/bidders separati |
|
|
||||||
| `v2.2_PER_AUCTION_MANAGEMENT.md` | 2.2 | Gestione aste individuali |
|
|
||||||
| `v2.1_README.md` | 2.1 | Modalità Multi-Asta core |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Sicurezza e Privacy
|
|
||||||
|
|
||||||
### Navigazione Limitata
|
|
||||||
- ? **Solo domini Bidoo** consentiti (bidoo.com, .it, .fr, .es, .de)
|
|
||||||
- ? **Link esterni bloccati** automaticamente
|
|
||||||
- ? **Validazione URL** su ogni navigazione
|
|
||||||
|
|
||||||
### Dati Locali
|
|
||||||
- ? **Nessun dato inviato** a server esterni
|
|
||||||
- ? **Log solo in memoria** (mai salvati su disco)
|
|
||||||
- ? **Nessun tracking** o analytics
|
|
||||||
|
|
||||||
### Credenziali Bidoo
|
|
||||||
- ?? **Non salvate** dal programma
|
|
||||||
- ?? **Gestite da WebView2** (come Edge browser)
|
|
||||||
- ?? **Cancella cache browser** per logout completo
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Supporto
|
|
||||||
|
|
||||||
### Problemi Comuni
|
|
||||||
|
|
||||||
**Il programma non si avvia:**
|
|
||||||
```bash
|
|
||||||
# Verifica .NET 8.0 installato
|
|
||||||
dotnet --version
|
|
||||||
# Output atteso: 8.0.x
|
|
||||||
```
|
|
||||||
|
|
||||||
**Click non funzionano:**
|
|
||||||
- Verifica di essere **loggato su Bidoo**
|
|
||||||
- Controlla impostazioni **Timer Click**
|
|
||||||
- Verifica **connessione internet stabile**
|
|
||||||
|
|
||||||
**Aste non rilevate (Multi-Asta):**
|
|
||||||
- Assicurati di essere sulla **pagina Preferiti**
|
|
||||||
- Clicca ? sulle aste per aggiungerle ai preferiti
|
|
||||||
- Clicca **"Avvia"** per avviare la scansione
|
|
||||||
|
|
||||||
**Navigazione bloccata:**
|
|
||||||
- Stai cercando di aprire un link **non-Bidoo**
|
|
||||||
- Solo i domini Bidoo sono consentiti per sicurezza
|
|
||||||
|
|
||||||
### Contatti
|
|
||||||
|
|
||||||
- ?? **Email:** [Alby96]
|
|
||||||
- ?? **Issues:** Repository privato Gitea
|
|
||||||
- ?? **Git:** `https://192.168.30.23/Alby96/Mimante`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Disclaimer
|
|
||||||
|
|
||||||
?? **Uso a Proprio Rischio**
|
|
||||||
|
|
||||||
Questo software è fornito "così com'è" senza garanzie di alcun tipo.
|
|
||||||
L'uso di bot/automazione potrebbe **violare i Termini di Servizio di Bidoo**.
|
|
||||||
|
|
||||||
**Responsabilità dell'utente:**
|
|
||||||
- ? Verificare compatibilità con ToS Bidoo
|
|
||||||
- ? Usare in modo responsabile
|
|
||||||
- ? Non abusare del sistema
|
|
||||||
- ? Non creare account multipli
|
|
||||||
- ? Non utilizzare per frode
|
|
||||||
|
|
||||||
**L'autore non è responsabile per:**
|
|
||||||
- Ban o sospensioni account Bidoo
|
|
||||||
- Perdite finanziarie
|
|
||||||
- Malfunzionamenti del software
|
|
||||||
- Uso improprio del programma
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Licenza
|
|
||||||
|
|
||||||
**Privato** - Non redistribuire senza autorizzazione
|
|
||||||
|
|
||||||
© 2024 Alby96. Tutti i diritti riservati.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ?? Conclusione
|
|
||||||
|
|
||||||
**AutoBidder** è uno strumento potente per ottimizzare le tue strategie su Bidoo.
|
|
||||||
|
|
||||||
### Punti di Forza
|
|
||||||
- ? **Precisione al millisecondo** nei click
|
|
||||||
- ? **Gestione multipla aste** simultanea
|
|
||||||
- ? **Controllo totale** su ogni parametro
|
|
||||||
- ? **Analisi competizione** dettagliata
|
|
||||||
- ? **Interfaccia intuitiva** e moderna
|
|
||||||
|
|
||||||
### Usa con Saggezza
|
|
||||||
- ?? Imposta **limiti di prezzo** ragionevoli
|
|
||||||
- ?? Non puntare su **troppe aste** contemporaneamente
|
|
||||||
- ?? Monitora il **budget** speso
|
|
||||||
- ?? **Pausa** le aste diventate troppo costose
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Buona fortuna con le tue aste! ????**
|
|
||||||
|
|
||||||
*Happy Bidding!*
|
|
||||||
Reference in New Issue
Block a user