Aggiornamento alla versione 4.0.0

- Aggiunta dipendenza per WebView2 per integrare un browser.
- Introdotto layout a schede (TabControl) per organizzare le funzionalità.
- Aggiunto browser WebView2 per navigazione e aggiunta aste.
- Implementata gestione delle impostazioni di esportazione (CSV, JSON, XML).
- Aggiunta funzionalità di caricamento e analisi delle aste chiuse.
- Introdotta gestione dei cookie di sessione tramite la scheda "Impostazioni".
- Creato controllo personalizzato `SimpleToolbar` per layout modulare.
- Migliorata gestione dello stato utente e fallback per dati mancanti.
- Rimossi stili e animazioni obsolete per semplificare il codice.
- Salvate le impostazioni utente in un file JSON locale.
- Correzioni di bug e miglioramenti di leggibilità del codice.
This commit is contained in:
Alberto Balbo
2025-11-04 23:05:49 +01:00
parent 967005b96a
commit 8717a3b6ef
7 changed files with 1274 additions and 537 deletions

View File

@@ -23,6 +23,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1343.22" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6584" />
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,16 @@
<UserControl x:Class="AutoBidder.Controls.SimpleToolbar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="48" d:DesignWidth="800">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Content="{Binding LeftContent, RelativeSource={RelativeSource AncestorType=UserControl}}" VerticalAlignment="Center" />
<ContentPresenter Grid.Column="1" Content="{Binding RightContent, RelativeSource={RelativeSource AncestorType=UserControl}}" VerticalAlignment="Center" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,28 @@
using System.Windows;
using System.Windows.Controls;
namespace AutoBidder.Controls
{
public partial class SimpleToolbar : UserControl
{
public static readonly DependencyProperty LeftContentProperty = DependencyProperty.Register("LeftContent", typeof(object), typeof(SimpleToolbar));
public static readonly DependencyProperty RightContentProperty = DependencyProperty.Register("RightContent", typeof(object), typeof(SimpleToolbar));
public object? LeftContent
{
get => GetValue(LeftContentProperty);
set => SetValue(LeftContentProperty, value);
}
public object? RightContent
{
get => GetValue(RightContentProperty);
set => SetValue(RightContentProperty, value);
}
public SimpleToolbar()
{
InitializeComponent();
}
}
}

View File

@@ -2,6 +2,7 @@
<Window x:Class="AutoBidder.Dialogs.AddAuctionSimpleDialog" <Window x:Class="AutoBidder.Dialogs.AddAuctionSimpleDialog"
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:controls="clr-namespace:AutoBidder.Controls"
Title="Aggiungi Asta" Height="320" Width="700" Title="Aggiungi Asta" Height="320" Width="700"
Background="#0a0a0a" Foreground="#FFFFFF" Background="#0a0a0a" Foreground="#FFFFFF"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
@@ -24,12 +25,16 @@
Padding="8" FontSize="13" ToolTip="Inserisci uno o pi&#x00F9; URL/ID dell'asta. Separali con a capo, spazio o ';'" Padding="8" FontSize="13" ToolTip="Inserisci uno o pi&#x00F9; URL/ID dell'asta. Separali con a capo, spazio o ';'"
AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Height="160" /> AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Height="160" />
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,8,0,0"> <controls:SimpleToolbar Grid.Row="3" Margin="0,8,0,0">
<Button x:Name="OkButton" Content="OK" Width="110" Margin="6" Padding="10,8" <controls:SimpleToolbar.RightContent>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="OK" Width="110" Margin="6" Padding="10,8"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66" Foreground="White" Click="OkButton_Click" /> Style="{StaticResource SmallButtonStyle}" Background="#00CC66" Foreground="White" Click="OkButton_Click" />
<Button x:Name="CancelButton" Content="Annulla" Width="110" Margin="6" Padding="10,8" <Button Content="Annulla" Width="110" Margin="6" Padding="10,8"
Style="{StaticResource SmallButtonStyle}" Background="#666" Foreground="White" Click="CancelButton_Click" /> Style="{StaticResource SmallButtonStyle}" Background="#666" Foreground="White" Click="CancelButton_Click" />
</StackPanel> </StackPanel>
</controls:SimpleToolbar.RightContent>
</controls:SimpleToolbar>
</Grid> </Grid>
</Border> </Border>
</Window> </Window>

View File

@@ -1,23 +1,25 @@
<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"
Title="AutoBidder v3.0" Height="800" Width="1400" xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
Title="AutoBidder v4.0" Height="800" Width="1400"
Background="#0a0a0a" Foreground="#FFFFFF" Background="#0a0a0a" Foreground="#FFFFFF"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
Icon="pack://application:,,,/Icon/favicon.ico"> Icon="pack://application:,,,/Icon/favicon.ico"
Loaded="Window_Loaded">
<Window.Resources> <Window.Resources>
<!-- Stile pulsanti stile vecchia versione --> <!-- Stili pulsanti -->
<Style x:Key="MainButtonStyle" TargetType="Button"> <Style x:Key="SmallButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="White" /> <Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="Bold" /> <Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="14" /> <Setter Property="FontSize" Value="12" />
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="Cursor" Value="Hand" /> <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}" <Border Background="{TemplateBinding Background}"
CornerRadius="8" CornerRadius="6"
Padding="{TemplateBinding Padding}"> Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border> </Border>
@@ -26,35 +28,19 @@
</Setter> </Setter>
</Style> </Style>
<!-- Grid action button styles (enable/opacity based on auction state) --> <!-- Grid action button styles -->
<Style x:Key="GridStartButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallButtonStyle}"> <Style x:Key="GridStartButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallButtonStyle}">
<Setter Property="IsEnabled" Value="True" /> <Setter Property="IsEnabled" Value="True" />
<Setter Property="Opacity" Value="1" /> <Setter Property="Opacity" Value="1" />
<Style.Triggers> <Style.Triggers>
<MultiDataTrigger> <MultiDataTrigger>
<MultiDataTrigger.Conditions> <MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsActive}" Value="True" /> <Condition Binding="{Binding IsActive}" Value="True" />
<Condition Binding="{Binding IsPaused}" Value="False" /> <Condition Binding="{Binding IsPaused}" Value="False" />
</MultiDataTrigger.Conditions> </MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False" /> <Setter Property="IsEnabled" Value="False" />
<Setter Property="Opacity" Value="0.5" /> <Setter Property="Opacity" Value="0.5" />
</MultiDataTrigger> </MultiDataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
@@ -70,22 +56,6 @@
<Setter Property="IsEnabled" Value="True" /> <Setter Property="IsEnabled" Value="True" />
<Setter Property="Opacity" Value="1" /> <Setter Property="Opacity" Value="1" />
</MultiDataTrigger> </MultiDataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
@@ -97,26 +67,10 @@
<Setter Property="IsEnabled" Value="True" /> <Setter Property="IsEnabled" Value="True" />
<Setter Property="Opacity" Value="1" /> <Setter Property="Opacity" Value="1" />
</DataTrigger> </DataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.15" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<Style x:Key="GridManualBidButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallButtonStyle}"> <Style x:Key="GridManualBidButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallButtonStyle}">
<Setter Property="IsEnabled" Value="False" /> <Setter Property="IsEnabled" Value="False" />
<Setter Property="Opacity" Value="0.5" /> <Setter Property="Opacity" Value="0.5" />
<Style.Triggers> <Style.Triggers>
@@ -128,27 +82,51 @@
<Setter Property="IsEnabled" Value="True" /> <Setter Property="IsEnabled" Value="True" />
<Setter Property="Opacity" Value="1" /> <Setter Property="Opacity" Value="1" />
</MultiDataTrigger> </MultiDataTrigger>
<Trigger Property="IsEnabled" Value="False"> </Style.Triggers>
<Trigger.EnterActions> </Style>
<BeginStoryboard>
<Storyboard> <!-- Vertical Tab Header Style -->
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.15" /> <Style x:Key="VerticalTabHeaderStyle" TargetType="Border">
</Storyboard> <Setter Property="Background" Value="#1a1a1a" />
</BeginStoryboard> <Setter Property="BorderThickness" Value="0,0,0,1" />
</Trigger.EnterActions> <Setter Property="BorderBrush" Value="#333333" />
<Trigger.ExitActions> <Setter Property="Padding" Value="12,16" />
<BeginStoryboard> <Setter Property="Cursor" Value="Hand" />
<Storyboard> <Style.Triggers>
<DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.15" /> <Trigger Property="IsMouseOver" Value="True">
</Storyboard> <Setter Property="Background" Value="#2a2a2a" />
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<!-- TabControl vertical style -->
<Style x:Key="VerticalTabControlStyle" TargetType="TabControl">
<Setter Property="TabStripPlacement" Value="Left" />
<Setter Property="Background" Value="#0a0a0a" />
<Setter Property="BorderThickness" Value="0" />
</Style>
</Window.Resources> </Window.Resources>
<Grid Margin="0" Background="#0a0a0a">
<!-- TAB NAVIGATION (Vertical Sidebar) -->
<TabControl x:Name="MainTabControl" Style="{StaticResource VerticalTabControlStyle}">
<!-- TAB 1: ASTE ATTIVE -->
<TabItem>
<TabItem.Header>
<Border Style="{StaticResource VerticalTabHeaderStyle}" Width="160">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📊" FontSize="20" Margin="0,0,12,0" />
<StackPanel>
<TextBlock Text="Aste Attive" FontWeight="Bold" FontSize="13" Foreground="#00CC66" />
<TextBlock Text="Monitoraggio" FontSize="10" Foreground="#999" />
</StackPanel>
</StackPanel>
</Border>
</TabItem.Header>
<TabItem.Content>
<!-- EXISTING MAIN WINDOW CONTENT -->
<Grid Margin="12" Background="#0a0a0a"> <Grid Margin="12" Background="#0a0a0a">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -186,10 +164,8 @@
Style="{StaticResource SmallButtonStyle}" Style="{StaticResource SmallButtonStyle}"
Background="#8B5CF6" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" /> Background="#8B5CF6" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" />
<!-- separator between Config and action group -->
<Border Width="2" Height="36" Background="#333333" Margin="12,0" VerticalAlignment="Center" CornerRadius="2" /> <Border Width="2" Height="36" Background="#333333" Margin="12,0" VerticalAlignment="Center" CornerRadius="2" />
<!-- Group: Start / Pause / Stop -->
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"> <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Button x:Name="StartButton" Content="Avvia Tutti" Command="{Binding StartAllCommand}" IsEnabled="False" <Button x:Name="StartButton" Content="Avvia Tutti" Command="{Binding StartAllCommand}" IsEnabled="False"
Style="{StaticResource SmallButtonStyle}" Style="{StaticResource SmallButtonStyle}"
@@ -198,27 +174,13 @@
Style="{StaticResource SmallButtonStyle}" Style="{StaticResource SmallButtonStyle}"
Background="#FF9933" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" /> Background="#FF9933" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="110" />
<Button x:Name="StopButton" Content="Ferma Tutti" Command="{Binding StopAllCommand}" IsEnabled="False" <Button x:Name="StopButton" Content="Ferma Tutti" Command="{Binding StopAllCommand}" IsEnabled="False"
Style="{StaticResource SmallButtonStyle}" Style="{StaticResource SmallButtonStyle}"
Background="#CC0000" Padding="20,10" Opacity="0.5" Height="40" MinWidth="110" /> Background="#CC0000" Padding="20,10" Opacity="0.5" Height="40" MinWidth="110" />
</StackPanel> </StackPanel>
<!-- separator graphic -->
<Border Width="2" Height="36" Background="#333333" Margin="12,0" VerticalAlignment="Center" CornerRadius="2" />
<!-- Group: Closed auctions + Free bids (free bids disabled for now) -->
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Button x:Name="ClosedAuctionsButton" Content="Aste Chiuse" Click="OpenClosedAuctionsButton_Click"
Style="{StaticResource SmallButtonStyle}"
Background="#0099FF" Padding="20,10" Margin="0,0,6,0" Height="40" MinWidth="120" />
<Button x:Name="FreeBidsButton" Content="Puntate Gratis" IsEnabled="False" ToolTip="Funzionalita in sviluppo"
Style="{StaticResource SmallButtonStyle}"
Background="#666" Padding="20,10" Height="40" MinWidth="140" />
</StackPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Border> </Border>
<!-- Riga vuota (toolbar rimossa) -->
<Grid Grid.Row="1" Height="0" /> <Grid Grid.Row="1" Height="0" />
<!-- Griglia Aste + Log --> <!-- Griglia Aste + Log -->
@@ -237,7 +199,6 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Header con titolo e pulsanti -->
<Grid Grid.Row="0" Margin="0,0,0,12"> <Grid Grid.Row="0" Margin="0,0,0,12">
<TextBlock x:Name="MonitorateTitle" Text="Aste monitorate: 0" FontSize="14" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" /> <TextBlock x:Name="MonitorateTitle" Text="Aste monitorate: 0" FontSize="14" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
@@ -267,7 +228,6 @@
<Style TargetType="DataGridRow"> <Style TargetType="DataGridRow">
<Setter Property="Height" Value="36" /> <Setter Property="Height" Value="36" />
<Style.Triggers> <Style.Triggers>
<!-- Colore basato sullo stato dell'asta -->
<DataTrigger Binding="{Binding StatusDisplay}" Value="VINTA"> <DataTrigger Binding="{Binding StatusDisplay}" Value="VINTA">
<Setter Property="Background" Value="#1B5E20" /> <Setter Property="Background" Value="#1B5E20" />
<Setter Property="Foreground" Value="#FFFFFF" /> <Setter Property="Foreground" Value="#FFFFFF" />
@@ -287,14 +247,13 @@
<Setter Property="Background" Value="#424242" /> <Setter Property="Background" Value="#424242" />
<Setter Property="Foreground" Value="#AAAAAA" /> <Setter Property="Foreground" Value="#AAAAAA" />
</DataTrigger> </DataTrigger>
<!-- Override quando selezionata -->
<Trigger Property="IsSelected" Value="True"> <Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#0099FF" /> <Setter Property="Background" Value="#0099FF" />
<Setter Property="Foreground" Value="White" /> <Setter Property="Foreground" Value="White" />
</Trigger> </Trigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<Style TargetType="DataGridCell"> <Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="10,6" /> <Setter Property="Padding" Value="10,6" />
</Style> </Style>
@@ -348,7 +307,7 @@
<GridSplitter Grid.Row="3" Height="8" HorizontalAlignment="Stretch" Background="#333333" /> <GridSplitter Grid.Row="3" Height="8" HorizontalAlignment="Stretch" Background="#333333" />
<!-- Dettagli Asta Selezionata - 3 Pannelli Affiancati --> <!-- Dettagli Asta Selezionata -->
<Border Grid.Row="4" Background="#1a1a1a" Padding="8" CornerRadius="6" BorderBrush="#333333" BorderThickness="1"> <Border Grid.Row="4" Background="#1a1a1a" Padding="8" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -368,18 +327,15 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Header -->
<Grid Grid.Row="0" Margin="0,0,0,12"> <Grid Grid.Row="0" Margin="0,0,0,12">
<TextBlock Text="Impostazioni" FontSize="13" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" /> <TextBlock Text="Impostazioni" FontSize="13" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" />
</Grid> </Grid>
<!-- Nome Asta -->
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"> <ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel> <StackPanel>
<TextBlock x:Name="SelectedAuctionName" Text="Seleziona un'asta dalla griglia" <TextBlock x:Name="SelectedAuctionName" Text="Seleziona un'asta dalla griglia"
FontSize="12" FontWeight="SemiBold" Foreground="#FFFFFF" TextWrapping="Wrap" Margin="0,0,0,16" /> FontSize="12" FontWeight="SemiBold" Foreground="#FFFFFF" TextWrapping="Wrap" Margin="0,0,0,16" />
<!-- Link asta e pulsanti -->
<Grid Margin="0,0,0,12"> <Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
@@ -388,7 +344,7 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<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" /> <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" />
<Button Content="Apri" x:Name="OpenAuctionButton" Click="GridOpenAuction_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="Apri" x:Name="OpenAuctionButton" Click="GridOpenAuction_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" /> <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" />
<Button Content="Esporta" x:Name="ExportAuctionButton" Click="ExportSelectedAuction_Click" Style="{StaticResource SmallButtonStyle}" Background="#8B5CF6" Padding="10,6" Height="28" MinWidth="80" FontSize="11" Grid.Column="3" Margin="6,0,0,0" /> <Button Content="Esporta" x:Name="ExportAuctionButton" Click="ExportSelectedAuction_Click" Style="{StaticResource SmallButtonStyle}" Background="#8B5CF6" Padding="10,6" Height="28" MinWidth="80" FontSize="11" Grid.Column="3" Margin="6,0,0,0" />
</Grid> </Grid>
@@ -442,7 +398,6 @@
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
<!-- Reset Button -->
<Button Grid.Row="2" x:Name="ResetSettingsButton" Content="Reset Impostazioni" Click="ResetSettingsButton_Click" <Button Grid.Row="2" x:Name="ResetSettingsButton" Content="Reset Impostazioni" Click="ResetSettingsButton_Click"
Style="{StaticResource SmallButtonStyle}" IsEnabled="False" Style="{StaticResource SmallButtonStyle}" IsEnabled="False"
Background="#666" Padding="10,8" Height="32" FontSize="11" Margin="0,8,0,0" /> Background="#666" Padding="10,8" Height="32" FontSize="11" Margin="0,8,0,0" />
@@ -533,4 +488,303 @@
</Grid> </Grid>
</Border> </Border>
</Grid> </Grid>
</Window> </TabItem.Content>
</TabItem>
<!-- TAB 2: BROWSER -->
<TabItem>
<TabItem.Header>
<Border Style="{StaticResource VerticalTabHeaderStyle}" Width="160">
<StackPanel Orientation="Horizontal">
<TextBlock Text="🌐" FontSize="20" Margin="0,0,12,0" />
<StackPanel>
<TextBlock Text="Browser" FontWeight="Bold" FontSize="13" Foreground="#0099FF" />
<TextBlock Text="Navigazione" FontSize="10" Foreground="#999" />
</StackPanel>
</StackPanel>
</Border>
</TabItem.Header>
<TabItem.Content>
<Grid Margin="12" Background="#0a0a0a">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Browser Toolbar -->
<Border Grid.Row="0" Background="#1a1a1a" Padding="12" CornerRadius="8" Margin="0,0,0,12">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Navigation Buttons -->
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0,0,12,0">
<Button x:Name="BrowserBackButton" Content="◀︎" Click="BrowserBackButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#666"
Padding="12,8" Margin="0,0,4,0" Height="36" MinWidth="40" />
<Button x:Name="BrowserForwardButton" Content="▶︎" Click="BrowserForwardButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#666"
Padding="12,8" Margin="0,0,4,0" Height="36" MinWidth="40" />
<Button x:Name="BrowserRefreshButton" Content="⟳" Click="BrowserRefreshButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#666"
Padding="12,8" Margin="0,0,4,0" Height="36" MinWidth="40" />
<Button x:Name="BrowserHomeButton" Content="🏠" Click="BrowserHomeButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66"
Padding="12,8" Height="36" MinWidth="40" />
</StackPanel>
<!-- Address Bar -->
<TextBox x:Name="BrowserAddress" Grid.Column="1" Text="https://it.bidoo.com/"
Background="#0f0f0f" Foreground="#FFFFFF"
Padding="12,8" FontSize="13" BorderBrush="#333" BorderThickness="1"
VerticalAlignment="Center" Margin="0,0,12,0" />
<!-- Action Buttons -->
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button x:Name="BrowserGoButton" Content="Vai" Click="BrowserGoButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#0099FF"
Padding="16,8" Margin="0,0,8,0" Height="36" MinWidth="70" />
<Button x:Name="BrowserAddAuctionButton" Content="+ Aggiungi Asta" Click="BrowserAddAuctionButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66"
Padding="16,8" Height="36" MinWidth="140" IsEnabled="False" />
</StackPanel>
</Grid>
</Border>
<!-- WebView2 Browser -->
<Border Grid.Row="1" Background="#0f0f0f" BorderBrush="#333333" BorderThickness="1" CornerRadius="6">
<wv2:WebView2 x:Name="EmbeddedWebView"
Source="https://it.bidoo.com/"
NavigationStarting="EmbeddedWebView_NavigationStarting"
NavigationCompleted="EmbeddedWebView_NavigationCompleted" />
</Border>
</Grid>
</TabItem.Content>
</TabItem>
<!-- TAB 3: PUNTATE GRATIS (DISABLED) -->
<TabItem IsEnabled="False">
<TabItem.Header>
<Border Style="{StaticResource VerticalTabHeaderStyle}" Width="160" Background="#424242">
<StackPanel Orientation="Horizontal">
<TextBlock Text="🎁" FontSize="20" Margin="0,0,12,0" Opacity="0.5" />
<StackPanel>
<TextBlock Text="Puntate Gratis" FontWeight="Bold" FontSize="13" Foreground="#999" />
<TextBlock Text="In sviluppo" FontSize="10" Foreground="#666" />
</StackPanel>
</StackPanel>
</Border>
</TabItem.Header>
<TabItem.Content>
<Grid Margin="12" Background="#0a0a0a">
<Border Background="#1a1a1a" Padding="40" CornerRadius="8" BorderBrush="#333333" BorderThickness="1"
HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="🎁" FontSize="60" HorizontalAlignment="Center" Margin="0,0,0,20" Opacity="0.3" />
<TextBlock Text="Puntate Gratis" FontSize="20" FontWeight="Bold"
Foreground="#999" HorizontalAlignment="Center" Margin="0,0,0,8" />
<TextBlock Text="Questa funzione è attualmente in sviluppo" FontSize="14"
Foreground="#666" HorizontalAlignment="Center" />
</StackPanel>
</Border>
</Grid>
</TabItem.Content>
</TabItem>
<!-- TAB 4: DATI STATISTICI -->
<TabItem>
<TabItem.Header>
<Border Style="{StaticResource VerticalTabHeaderStyle}" Width="160">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📈" FontSize="20" Margin="0,0,12,0" />
<StackPanel>
<TextBlock Text="Dati Statistici" FontWeight="Bold" FontSize="13" Foreground="#FF9933" />
<TextBlock Text="Analisi" FontSize="10" Foreground="#999" />
</StackPanel>
</StackPanel>
</Border>
</TabItem.Header>
<TabItem.Content>
<Grid Margin="12" Background="#0a0a0a">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#1a1a1a" Padding="12" CornerRadius="8" Margin="0,0,0,12">
<Grid>
<TextBlock Text="Statistiche Aste Chiuse" FontSize="18" FontWeight="Bold" Foreground="#FF9933" VerticalAlignment="Center" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="LoadClosedAuctionsButton" Content="📥 Carica Aste Chiuse" Click="LoadClosedAuctionsButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#0099FF"
Padding="16,10" Height="40" MinWidth="180" Margin="0,0,8,0" />
<Button x:Name="ExportStatsButton" Content="📊 Esporta Statistiche" Click="ExportStatsButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66"
Padding="16,10" Height="40" MinWidth="180" />
</StackPanel>
</Grid>
</Border>
<!-- Data Grid for Statistics -->
<Border Grid.Row="1" Background="#1a1a1a" Padding="12" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
<DataGrid x:Name="StatsDataGrid" AutoGenerateColumns="False"
Background="#1a1a1a" Foreground="#FFFFFF"
BorderBrush="#333333" BorderThickness="0"
GridLinesVisibility="Horizontal" HorizontalGridLinesBrush="#333333"
RowBackground="#1a1a1a" AlternatingRowBackground="#222222"
IsReadOnly="True">
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#2a2a2a" />
<Setter Property="Foreground" Value="#FFFFFF" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Padding" Value="10,8" />
<Setter Property="BorderThickness" Value="0,0,0,2" />
<Setter Property="BorderBrush" Value="#FF9933" />
</Style>
<Style TargetType="DataGridRow">
<Setter Property="Height" Value="32" />
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Prodotto" Binding="{Binding ProductName}" Width="2*" />
<DataGridTextColumn Header="Prezzo Finale" Binding="{Binding FinalPrice, StringFormat='{}{0:F2}€'}" Width="120" />
<DataGridTextColumn Header="Vincitore" Binding="{Binding Winner}" Width="150" />
<DataGridTextColumn Header="Puntate Usate" Binding="{Binding BidsUsed}" Width="120" />
<DataGridTextColumn Header="URL Asta" Binding="{Binding AuctionUrl}" Width="*" />
</DataGrid.Columns>
</DataGrid>
</Border>
<!-- Status Bar -->
<Border Grid.Row="2" Background="#1a1a1a" Padding="12" CornerRadius="8" Margin="0,12,0,0">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="StatsStatusText" Text="Nessuna statistica caricata"
FontSize="12" Foreground="#999" VerticalAlignment="Center" />
</StackPanel>
</Border>
</Grid>
</TabItem.Content>
</TabItem>
<!-- TAB 5: IMPOSTAZIONI -->
<TabItem>
<TabItem.Header>
<Border Style="{StaticResource VerticalTabHeaderStyle}" Width="160">
<StackPanel Orientation="Horizontal">
<TextBlock Text="⚙️" FontSize="20" Margin="0,0,12,0" />
<StackPanel>
<TextBlock Text="Impostazioni" FontWeight="Bold" FontSize="13" Foreground="#8B5CF6" />
<TextBlock Text="Configurazione" FontSize="10" Foreground="#999" />
</StackPanel>
</StackPanel>
</Border>
</TabItem.Header>
<TabItem.Content>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid Margin="12" Background="#0a0a0a">
<StackPanel MaxWidth="800">
<!-- Cookie Configuration -->
<Border Background="#1a1a1a" Padding="20" CornerRadius="8" Margin="0,0,0,16" BorderBrush="#333333" BorderThickness="1">
<StackPanel>
<TextBlock Text="🔧 Configurazione Cookie" FontSize="16" FontWeight="Bold" Foreground="#8B5CF6" Margin="0,0,0,16" />
<TextBlock Text="Cookie di sessione (__stattrb):" FontSize="12" Foreground="#999" Margin="0,0,0,8" />
<TextBox x:Name="SettingsCookieTextBox"
Background="#0f0f0f" Foreground="#FFFFFF"
Padding="12" FontSize="12" BorderBrush="#444" BorderThickness="1"
TextWrapping="Wrap" MinHeight="80" Margin="0,0,0,12" />
<TextBlock Text=" Inserisci il valore del cookie __stattrb dal browser"
FontSize="11" Foreground="#666" FontStyle="Italic" Margin="0,0,0,12" />
<Button x:Name="SaveCookieButton" Content="Salva Cookie" Click="SaveCookieButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#8B5CF6"
Padding="16,10" Height="40" HorizontalAlignment="Left" MinWidth="150" />
</StackPanel>
</Border>
<!-- Export Settings -->
<Border Background="#1a1a1a" Padding="20" CornerRadius="8" Margin="0,0,0,16" BorderBrush="#333333" BorderThickness="1">
<StackPanel>
<TextBlock Text="📤 Impostazioni Esportazione" FontSize="16" FontWeight="Bold" Foreground="#8B5CF6" Margin="0,0,0,16" />
<!-- Export Path -->
<TextBlock Text="Percorso di esportazione:" FontSize="12" Foreground="#999" Margin="0,0,0,8" />
<Grid Margin="0,0,0,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="ExportPathTextBox" Grid.Column="0"
Background="#0f0f0f" Foreground="#FFFFFF"
Padding="12" FontSize="12" BorderBrush="#444" BorderThickness="1"
Margin="0,0,8,0" />
<Button x:Name="ExportBrowseButton" Grid.Column="1" Content="Sfoglia..." Click="ExportBrowseButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#666"
Padding="16,10" Height="38" MinWidth="100" />
</Grid>
<!-- File Format -->
<TextBlock Text="Formato file:" FontSize="12" Foreground="#999" Margin="0,0,0,8" />
<StackPanel Orientation="Horizontal" Margin="0,0,0,16">
<RadioButton x:Name="ExtCsv" Content="CSV" Foreground="#FFFFFF" Margin="0,0,20,0" IsChecked="True" />
<RadioButton x:Name="ExtJson" Content="JSON" Foreground="#FFFFFF" Margin="0,0,20,0" />
<RadioButton x:Name="ExtXml" Content="XML" Foreground="#FFFFFF" />
</StackPanel>
<!-- Export Scope -->
<TextBlock Text="Aste da esportare:" FontSize="12" Foreground="#999" Margin="0,0,0,8" />
<ComboBox x:Name="ExportScopeCombo"
Background="#0f0f0f" Foreground="#FFFFFF"
Padding="12,8" FontSize="12" BorderBrush="#444" BorderThickness="1"
Margin="0,0,0,16" SelectedIndex="0">
<ComboBoxItem Content="Tutte le aste" />
<ComboBoxItem Content="Solo aste terminate" />
<ComboBoxItem Content="Solo aste sconosciute" />
</ComboBox>
<!-- Data to Include -->
<TextBlock Text="Dati da includere:" FontSize="12" Foreground="#999" Margin="0,0,0,8" />
<CheckBox x:Name="IncludeOnlyUsedBids" Content="Solo puntate usate e prezzo finale"
Foreground="#FFFFFF" Margin="0,0,0,8" IsChecked="True" />
<CheckBox x:Name="IncludeLogs" Content="Includi log completo"
Foreground="#FFFFFF" Margin="0,0,0,8" />
<CheckBox x:Name="IncludeUserBids" Content="Includi puntate singoli utenti"
Foreground="#FFFFFF" Margin="0,0,0,16" />
<!-- Save/Cancel Buttons -->
<StackPanel Orientation="Horizontal">
<Button x:Name="SaveSettingsButton" Content="Salva Impostazioni" Click="SaveSettingsButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66"
Padding="16,10" Height="40" MinWidth="150" Margin="0,0,8,0" />
<Button x:Name="CancelSettingsButton" Content="Annulla" Click="CancelSettingsButton_Click"
Style="{StaticResource SmallButtonStyle}" Background="#666"
Padding="16,10" Height="40" MinWidth="100" />
</StackPanel>
</StackPanel>
</Border>
<!-- Progress Indicators (hidden by default) -->
<Border x:Name="ExportProgressContainer" Background="#1a1a1a" Padding="20" CornerRadius="8"
BorderBrush="#333333" BorderThickness="1" Visibility="Collapsed">
<StackPanel>
<ProgressBar x:Name="ExportProgressBar" Height="8" Margin="0,0,0,8" />
<TextBlock x:Name="ExportProgressText" Text="Esportazione in corso..."
FontSize="12" Foreground="#999" HorizontalAlignment="Center" />
</StackPanel>
</Border>
<!-- Toggle Button (collapsed/hidden placeholder) -->
<ToggleButton x:Name="ToggleTabsButton" Visibility="Collapsed"
Checked="ToggleTabsButton_Checked" Unchecked="ToggleTabsButton_Unchecked" />
</StackPanel>
</Grid>
</ScrollViewer>
</TabItem.Content>
</TabItem>
</TabControl>
</Grid>
</Window>

View File

@@ -1,4 +1,11 @@
using System.Collections.ObjectModel; using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Text.Json;
using System.Collections.Generic;
using System.Text;
using System.Net; using System.Net;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -21,7 +28,7 @@ namespace AutoBidder
{ {
// SERVIZI CORE // SERVIZI CORE
private readonly AuctionMonitor _auctionMonitor; private readonly AuctionMonitor _auctionMonitor;
private readonly ObservableCollection<AuctionViewModel> _auctionViewModels = new(); private readonly System.Collections.ObjectModel.ObservableCollection<AuctionViewModel> _auctionViewModels = new System.Collections.ObjectModel.ObservableCollection<AuctionViewModel>();
// UI State // UI State
private AuctionViewModel? _selectedAuction; private AuctionViewModel? _selectedAuction;
private bool _isAutomationActive = false; private bool _isAutomationActive = false;
@@ -40,6 +47,9 @@ namespace AutoBidder
private System.Windows.Threading.DispatcherTimer _userBannerTimer; private System.Windows.Threading.DispatcherTimer _userBannerTimer;
private System.Windows.Threading.DispatcherTimer _userHtmlTimer; private System.Windows.Threading.DispatcherTimer _userHtmlTimer;
// export cancellation
private CancellationTokenSource? _exportCts;
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
@@ -71,6 +81,9 @@ namespace AutoBidder
// Carica aste salvate // Carica aste salvate
LoadSavedAuctions(); LoadSavedAuctions();
// Load export/settings UI
LoadExportSettings();
// Ensure initial global button states (pause/stop disabled until starting) // Ensure initial global button states (pause/stop disabled until starting)
UpdateGlobalControlButtons(); UpdateGlobalControlButtons();
@@ -84,7 +97,7 @@ namespace AutoBidder
_userBannerTimer.Start(); _userBannerTimer.Start();
_ = UpdateUserBannerInfoAsync(); _ = UpdateUserBannerInfoAsync();
// Timer per aggiornamento dati utente da HTML ogni 3 minuti // Timer per aggiornamento dati utente da HTML ogni3 minuti
_userHtmlTimer = new System.Windows.Threading.DispatcherTimer(); _userHtmlTimer = new System.Windows.Threading.DispatcherTimer();
_userHtmlTimer.Interval = TimeSpan.FromMinutes(3); _userHtmlTimer.Interval = TimeSpan.FromMinutes(3);
_userHtmlTimer.Tick += UserHtmlTimer_Tick; _userHtmlTimer.Tick += UserHtmlTimer_Tick;
@@ -482,7 +495,7 @@ namespace AutoBidder
{ {
if (_selectedAuction != null && sender is TextBox tb) if (_selectedAuction != null && sender is TextBox tb)
{ {
if (int.TryParse(tb.Text, out var value) && value >= 0 && value <= 8) if (int.TryParse(tb.Text, out var value) && value >=0 && value <=8)
{ {
_selectedAuction.TimerClick = value; _selectedAuction.TimerClick = value;
} }
@@ -493,7 +506,7 @@ namespace AutoBidder
{ {
if (_selectedAuction != null && sender is TextBox tb) if (_selectedAuction != null && sender is TextBox tb)
{ {
if (int.TryParse(tb.Text, out var value) && value >= 0) if (int.TryParse(tb.Text, out var value) && value >=0)
{ {
_selectedAuction.AuctionInfo.DelayMs = value; _selectedAuction.AuctionInfo.DelayMs = value;
} }
@@ -528,7 +541,7 @@ namespace AutoBidder
{ {
if (_selectedAuction != null && sender is TextBox tb) if (_selectedAuction != null && sender is TextBox tb)
{ {
if (int.TryParse(tb.Text, out var value) && value >= 0) if (int.TryParse(tb.Text, out var value) && value >=0)
{ {
_selectedAuction.AuctionInfo.MinResets = value; _selectedAuction.AuctionInfo.MinResets = value;
} }
@@ -539,7 +552,7 @@ namespace AutoBidder
{ {
if (_selectedAuction != null && sender is TextBox tb) if (_selectedAuction != null && sender is TextBox tb)
{ {
if (int.TryParse(tb.Text, out var value) && value >= 0) if (int.TryParse(tb.Text, out var value) && value >=0)
{ {
_selectedAuction.AuctionInfo.MaxResets = value; _selectedAuction.AuctionInfo.MaxResets = value;
} }
@@ -550,7 +563,7 @@ namespace AutoBidder
{ {
if (_selectedAuction != null && sender is TextBox tb) if (_selectedAuction != null && sender is TextBox tb)
{ {
if (int.TryParse(tb.Text, out var value) && value >= 0) if (int.TryParse(tb.Text, out var value) && value >=0)
{ {
_selectedAuction.MaxClicks = value; _selectedAuction.MaxClicks = value;
SaveAuctions(); // Persist change immediately SaveAuctions(); // Persist change immediately
@@ -570,12 +583,12 @@ namespace AutoBidder
if (result == MessageBoxResult.Yes) if (result == MessageBoxResult.Yes)
{ {
_selectedAuction.TimerClick = 0; _selectedAuction.TimerClick =0;
_selectedAuction.AuctionInfo.DelayMs = 50; _selectedAuction.AuctionInfo.DelayMs =50;
_selectedAuction.MinPrice = 0; _selectedAuction.MinPrice =0;
_selectedAuction.MaxPrice = 0; _selectedAuction.MaxPrice =0;
_selectedAuction.AuctionInfo.MinResets = 0; _selectedAuction.AuctionInfo.MinResets =0;
_selectedAuction.AuctionInfo.MaxResets = 0; _selectedAuction.AuctionInfo.MaxResets =0;
UpdateSelectedAuctionDetails(_selectedAuction); UpdateSelectedAuctionDetails(_selectedAuction);
Log($"Reset impostazioni: {_selectedAuction.Name}"); Log($"Reset impostazioni: {_selectedAuction.Name}");
@@ -1113,6 +1126,196 @@ namespace AutoBidder
} }
} }
// Add LoadExportSettings to initialize UI from saved settings
private void LoadExportSettings()
{
try
{
var s = Utilities.SettingsManager.Load();
if (s != null)
{
ExportPathTextBox.Text = s.ExportPath ?? string.Empty;
if (!string.IsNullOrEmpty(s.LastExportExt))
{
var ext = s.LastExportExt.ToLowerInvariant();
if (ext == ".json") ExtJson.IsChecked = true;
else if (ext == ".xml") ExtXml.IsChecked = true;
else ExtCsv.IsChecked = true;
}
else
{
ExtCsv.IsChecked = true;
}
switch (s.ExportScope)
{
case "Closed": ExportScopeCombo.SelectedIndex =1; break;
case "Unknown": ExportScopeCombo.SelectedIndex =2; break;
default: ExportScopeCombo.SelectedIndex =0; break;
}
IncludeOnlyUsedBids.IsChecked = s.IncludeOnlyUsedBids;
IncludeLogs.IsChecked = s.IncludeLogs;
IncludeUserBids.IsChecked = s.IncludeUserBids;
}
}
catch { }
finally
{
try { ExportProgressBar.Visibility = Visibility.Collapsed; ExportProgressText.Visibility = Visibility.Collapsed; } catch { }
}
}
// Export all (simple async wrapper)
private async void ExportAllButton_Click(object sender, RoutedEventArgs e)
{
try
{
var settings = Utilities.SettingsManager.Load();
string ext = ExtJson.IsChecked == true ? ".json" : ExtXml.IsChecked == true ? ".xml" : ".csv";
var dlg = new Microsoft.Win32.SaveFileDialog() { FileName = "auctions_export" + ext, Filter = "CSV files|*.csv|JSON files|*.json|XML files|*.xml|All files|*.*" };
if (dlg.ShowDialog(this) != true) return;
var path = dlg.FileName;
var all = _auctionMonitor.GetAuctions();
var selection = all.AsEnumerable();
var scope = settings.ExportScope ?? "All";
if (scope == "Closed") selection = selection.Where(a => !a.IsActive);
else if (scope == "Unknown") selection = selection.Where(a => (a.BidHistory == null || a.BidHistory.Count ==0) && (a.BidderStats == null || a.BidderStats.Count ==0));
var list = selection.ToList();
if (list.Count ==0)
{
MessageBox.Show(this, "Nessuna asta da esportare.", "Esporta Aste", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
ExportProgressBar.Visibility = Visibility.Visible;
ExportProgressText.Visibility = Visibility.Visible;
ExportProgressText.Text = "Esportazione in corso...";
await Task.Run(() =>
{
if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
{
var json = System.Text.Json.JsonSerializer.Serialize(list, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
System.IO.File.WriteAllText(path, json, System.Text.Encoding.UTF8);
}
else if (path.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
{
var doc = new XDocument(new XElement("Auctions",
from a in list
select new XElement("Auction",
new XElement("AuctionId", a.AuctionId),
new XElement("Name", a.Name),
new XElement("OriginalUrl", a.OriginalUrl ?? string.Empty)
)
));
doc.Save(path);
}
else
{
// Use existing exporter
CsvExporter.ExportAllAuctions(list, path);
}
});
try { ExportPreferences.SaveLastExportExtension(System.IO.Path.GetExtension(path)); } catch { }
MessageBox.Show(this, "Esportazione completata.", "Esporta Aste", MessageBoxButton.OK, MessageBoxImage.Information);
Log($"[EXPORT] Aste esportate -> {path}");
}
catch (Exception ex)
{
Log($"[ERRORE] Esportazione massiva: {ex.Message}");
MessageBox.Show(this, "Errore durante esportazione: " + ex.Message, "Esporta Aste", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
ExportProgressBar.Visibility = Visibility.Collapsed;
ExportProgressText.Visibility = Visibility.Collapsed;
}
}
// Browser handlers (simple)
private void BrowserBackButton_Click(object sender, RoutedEventArgs e)
{
try { if (EmbeddedWebView?.CoreWebView2 != null && EmbeddedWebView.CoreWebView2.CanGoBack) EmbeddedWebView.CoreWebView2.GoBack(); } catch { }
}
private void BrowserForwardButton_Click(object sender, RoutedEventArgs e)
{
try { if (EmbeddedWebView?.CoreWebView2 != null && EmbeddedWebView.CoreWebView2.CanGoForward) EmbeddedWebView.CoreWebView2.GoForward(); } catch { }
}
private void BrowserRefreshButton_Click(object sender, RoutedEventArgs e)
{
try { EmbeddedWebView?.Reload(); } catch { }
}
private void BrowserHomeButton_Click(object sender, RoutedEventArgs e)
{
try { EmbeddedWebView?.CoreWebView2?.Navigate("https://it.bidoo.com/"); BrowserAddress.Text = "https://it.bidoo.com/"; } catch { }
}
private void BrowserGoButton_Click(object sender, RoutedEventArgs e)
{
try
{
var url = BrowserAddress.Text?.Trim(); if (string.IsNullOrEmpty(url)) return; if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) url = "https://" + url;
EmbeddedWebView?.CoreWebView2?.Navigate(url);
}
catch { }
}
private void BrowserAddAuctionButton_Click(object sender, RoutedEventArgs e)
{
try { var url = BrowserAddress.Text?.Trim() ?? EmbeddedWebView?.Source?.ToString(); if (!string.IsNullOrEmpty(url)) _ = AddAuctionFromUrl(url); } catch { }
}
private void BrowserContext_AddAuction_Click(object sender, RoutedEventArgs e)
{
try { var url = EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text; if (!string.IsNullOrEmpty(url)) _ = AddAuctionFromUrl(url); } catch { }
}
private void EmbeddedWebView_NavigationStarting(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationStartingEventArgs e)
{
try { BrowserAddress.Text = e.Uri ?? string.Empty; BrowserAddAuctionButton.IsEnabled = IsValidAuctionUrl(e.Uri ?? string.Empty); } catch { }
}
private void EmbeddedWebView_NavigationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs e)
{
try { var uri = EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text; BrowserAddress.Text = uri; BrowserAddAuctionButton.IsEnabled = IsValidAuctionUrl(uri); } catch { }
}
private void ExportBrowseButton_Click(object sender, RoutedEventArgs e)
{
var dlg = new Microsoft.Win32.SaveFileDialog() { FileName = "export.csv", Filter = "CSV files|*.csv|All files|*.*" };
if (dlg.ShowDialog(this) == true)
{
ExportPathTextBox.Text = System.IO.Path.GetDirectoryName(dlg.FileName) ?? string.Empty;
}
}
private void SaveSettingsButton_Click(object sender, RoutedEventArgs e)
{
try
{
var s = new Utilities.AppSettings()
{
ExportPath = ExportPathTextBox.Text,
LastExportExt = ExtJson.IsChecked == true ? ".json" : ExtXml.IsChecked == true ? ".xml" : ".csv",
ExportScope = ExportScopeCombo.SelectedIndex ==1 ? "Closed" : ExportScopeCombo.SelectedIndex ==2 ? "Unknown" : "All",
IncludeOnlyUsedBids = IncludeOnlyUsedBids.IsChecked == true,
IncludeLogs = IncludeLogs.IsChecked == true,
IncludeUserBids = IncludeUserBids.IsChecked == true
};
Utilities.SettingsManager.Save(s);
ExportPreferences.SaveLastExportExtension(s.LastExportExt);
MessageBox.Show(this, "Impostazioni salvate.", "Salva", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show(this, "Errore salvataggio impostazioni: " + ex.Message, "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void CancelSettingsButton_Click(object sender, RoutedEventArgs e)
{
LoadExportSettings();
}
private enum LogLevel { Info, Warn, Error } private enum LogLevel { Info, Warn, Error }
private void Log(string message, LogLevel level = LogLevel.Info) private void Log(string message, LogLevel level = LogLevel.Info)
@@ -1170,6 +1373,8 @@ namespace AutoBidder
base.OnClosed(e); base.OnClosed(e);
} }
// NOTE: Window_Loaded and ToggleTabsButton handlers were removed because they forced a fixed
// width on `MainTabControl` at runtime, causing the UI to render incorrectly compared to the designer.
// === HANDLER BOTTONI GRIGLIA === // === HANDLER BOTTONI GRIGLIA ===
private void GridOpenAuction_Click(object sender, RoutedEventArgs e) private void GridOpenAuction_Click(object sender, RoutedEventArgs e)
@@ -1248,7 +1453,7 @@ namespace AutoBidder
private void PauseAllButton_Click(object sender, RoutedEventArgs e) private void PauseAllButton_Click(object sender, RoutedEventArgs e)
{ {
int paused = 0; int paused =0;
foreach (var vm in _auctionViewModels) foreach (var vm in _auctionViewModels)
{ {
if (vm.IsActive && !vm.IsPaused) if (vm.IsActive && !vm.IsPaused)
@@ -1283,31 +1488,31 @@ namespace AutoBidder
// According to rule: darken if all in same state that matches the button meaning // According to rule: darken if all in same state that matches the button meaning
if (allActive) if (allActive)
{ {
StartButton.IsEnabled = false; StartButton.Opacity = 0.5; StartButton.IsEnabled = false; StartButton.Opacity =0.5;
} }
else else
{ {
StartButton.IsEnabled = true; StartButton.Opacity = 1.0; StartButton.IsEnabled = true; StartButton.Opacity =1.0;
} }
// PauseAll button: darken if allPaused or allStopped // PauseAll button: darken if allPaused or allStopped
if (allPaused || allStopped) if (allPaused || allStopped)
{ {
PauseAllButton.IsEnabled = false; PauseAllButton.Opacity = 0.5; PauseAllButton.IsEnabled = false; PauseAllButton.Opacity =0.5;
} }
else else
{ {
PauseAllButton.IsEnabled = true; PauseAllButton.Opacity = 1.0; PauseAllButton.IsEnabled = true; PauseAllButton.Opacity =1.0;
} }
// Stop button: darken if allStopped // Stop button: darken if allStopped
if (allStopped) if (allStopped)
{ {
StopButton.IsEnabled = false; StopButton.Opacity = 0.5; StopButton.IsEnabled = false; StopButton.Opacity =0.5;
} }
else else
{ {
StopButton.IsEnabled = true; StopButton.Opacity = 1.0; StopButton.IsEnabled = true; StopButton.Opacity =1.0;
} }
} }
@@ -1321,13 +1526,32 @@ namespace AutoBidder
var info = await _auctionMonitor.GetUserBannerInfoAsync(); var info = await _auctionMonitor.GetUserBannerInfoAsync();
if (info != null) if (info != null)
{ {
BannerAsteDaRiscattare.Text = $"{info.nAsteVinte - info.nAsteConfermate}"; // Map banner info to available UI fields
// BannerPuntateBonus.Text = $"Bonus: {info.nPuntateBonus}"; // RIMOSSO try
{
// Use nPuntateDaRiscattare if available as remaining bids proxy
if (info.nPuntateDaRiscattare >0)
{
RemainingBidsText.Text = info.nPuntateDaRiscattare.ToString();
}
else if (info.nPuntateBonus >0)
{
RemainingBidsText.Text = info.nPuntateBonus.ToString();
} }
else else
{ {
BannerAsteDaRiscattare.Text = "--"; // fallback: show total won minus confirmed if meaningful
// BannerPuntateBonus.Text = "Bonus: --"; // RIMOSSO if (info.nAsteVinte >= info.nAsteConfermate)
RemainingBidsText.Text = (info.nAsteVinte - info.nAsteConfermate).ToString();
else
RemainingBidsText.Text = "--";
}
}
catch { RemainingBidsText.Text = "--"; }
}
else
{
RemainingBidsText.Text = "--";
} }
} }
@@ -1358,9 +1582,9 @@ namespace AutoBidder
} }
else else
{ {
// Rimuovi newline e taglia a max 20 caratteri // Rimuovi newline e taglia a max20 caratteri
var clean = username.Replace("\r", "").Replace("\n", ""); var clean = username.Replace("\r", "").Replace("\n", "");
UsernameText.Text = clean.Length > 20 ? clean.Substring(0, 20) + "..." : clean; UsernameText.Text = clean.Length >20 ? clean.Substring(0,20) + "..." : clean;
} }
RemainingBidsText.Text = remainingBids.ToString(); RemainingBidsText.Text = remainingBids.ToString();
} }
@@ -1377,7 +1601,7 @@ namespace AutoBidder
{ {
var dlg = new Microsoft.Win32.SaveFileDialog() var dlg = new Microsoft.Win32.SaveFileDialog()
{ {
Filter = "CSV files|*.csv|JSON files|*.json|XML files|*.xml|All files|*.*", Filter = "CSV files|*.csv|JSON files|*.json|All files|*.*",
FileName = $"auction_{_selectedAuction.AuctionId}.csv" FileName = $"auction_{_selectedAuction.AuctionId}.csv"
}; };
@@ -1538,5 +1762,168 @@ namespace AutoBidder
if (v == null) return string.Empty; if (v == null) return string.Empty;
return v.Replace("\"", "\"\""); return v.Replace("\"", "\"\"");
} }
private void OpenFreeBids_Click(object sender, RoutedEventArgs e)
{
try { MainTabControl.SelectedIndex =1; } catch { }
}
private void ExportSelectionButton_Click(object sender, RoutedEventArgs e)
{
ExportSelectedAuction_Click(sender, e);
}
// New handlers for Statistics tab
private async void LoadClosedAuctionsButton_Click(object sender, RoutedEventArgs e)
{
try
{
StatsStatusText.Text = "Caricamento aste chiuse in corso...";
Log("[STATS] Avvio caricamento aste chiuse...");
// Use the existing ClosedAuctionsScraper service
var scraper = new Services.ClosedAuctionsScraper(null, null, (msg) => Log($"[SCRAPER] {msg}"));
var closedUrl = "https://it.bidoo.com/closed_auctions.php";
var results = new System.Collections.ObjectModel.ObservableCollection<Models.ClosedAuctionRecord>();
await foreach (var rec in scraper.ScrapeYieldAsync(closedUrl))
{
// Filter out records without bids info
if (!rec.BidsUsed.HasValue)
{
continue;
}
results.Add(rec);
StatsStatusText.Text = $"Caricate {results.Count} aste...";
}
StatsDataGrid.ItemsSource = results;
StatsStatusText.Text = $"Totale: {results.Count} aste caricate";
Log($"[STATS] Caricamento completato: {results.Count} aste");
}
catch (Exception ex)
{
Log($"[ERRORE] Caricamento statistiche: {ex.Message}", LogLevel.Error);
StatsStatusText.Text = "Errore nel caricamento";
MessageBox.Show($"Errore: {ex.Message}", "Errore Caricamento", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void ExportStatsButton_Click(object sender, RoutedEventArgs e)
{
try
{
var items = StatsDataGrid.ItemsSource as System.Collections.ObjectModel.ObservableCollection<Models.ClosedAuctionRecord>;
if (items == null || items.Count ==0)
{
MessageBox.Show("Nessuna statistica da esportare. Carica prima le aste chiuse.", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var dlg = new Microsoft.Win32.SaveFileDialog()
{
Filter = "CSV files|*.csv|JSON files|*.json|All files|*.*",
FileName = "closed_auctions_stats.csv"
};
if (dlg.ShowDialog(this) != true) return;
var path = dlg.FileName;
await Task.Run(() =>
{
if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
{
var json = System.Text.Json.JsonSerializer.Serialize(items, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
System.IO.File.WriteAllText(path, json, System.Text.Encoding.UTF8);
}
else
{
// CSV export
using var sw = new System.IO.StreamWriter(path, false, System.Text.Encoding.UTF8);
sw.WriteLine("ProductName,FinalPrice,Winner,BidsUsed,AuctionUrl");
foreach (var item in items)
{
sw.WriteLine($"\"{EscapeCsv(item.ProductName)}\",{item.FinalPrice:F2},\"{EscapeCsv(item.Winner)}\",{item.BidsUsed},\"{EscapeCsv(item.AuctionUrl)}\"");
}
}
});
MessageBox.Show("Esportazione completata.", "Esporta Statistiche", MessageBoxButton.OK, MessageBoxImage.Information);
Log($"[EXPORT] Statistiche esportate -> {path}");
}
catch (Exception ex)
{
Log($"[ERRORE] Esportazione statistiche: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore: {ex.Message}", "Errore Esportazione", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// New handler for Settings tab
private void SaveCookieButton_Click(object sender, RoutedEventArgs e)
{
try
{
var cookieValue = SettingsCookieTextBox.Text?.Trim();
if (string.IsNullOrWhiteSpace(cookieValue))
{
MessageBox.Show("Inserisci un valore valido per il cookie.", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// Initialize session with the cookie
var cookieString = $"__stattrb={cookieValue}";
_auctionMonitor.InitializeSessionWithCookie(cookieString, "");
StartButton.IsEnabled = true;
// Save session securely
var session = _auctionMonitor.GetSession();
SessionManager.SaveSession(session);
Log("Sessione configurata da impostazioni");
Log("Cookie salvato in modo sicuro");
// Update user info
Task.Run(async () =>
{
var userData = await _auctionMonitor.GetUserDataAsync();
if (userData != null)
{
Dispatcher.Invoke(() =>
{
SetUserBanner(userData.Username, userData.RemainingBids);
Log($"[OK] Utente: {userData.Username}, Puntate residue: {userData.RemainingBids}");
});
}
});
MessageBox.Show("Cookie salvato con successo!", "Salva Cookie", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
Log($"[ERRORE] Salvataggio cookie: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// Add empty handlers required by XAML (no-op to avoid forcing runtime width changes)
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Intentionally left empty to allow designer sizing to take precedence at runtime.
}
private void ToggleTabsButton_Checked(object sender, RoutedEventArgs e)
{
// No runtime width adjustments to avoid layout mismatch with designer.
}
private void ToggleTabsButton_Unchecked(object sender, RoutedEventArgs e)
{
// No runtime width adjustments to avoid layout mismatch with designer.
}
} }
} }

View File

@@ -0,0 +1,46 @@
using System;
using System.IO;
using System.Text.Json;
namespace AutoBidder.Utilities
{
internal class AppSettings
{
public string? ExportPath { get; set; }
public string? LastExportExt { get; set; }
public string ExportScope { get; set; } = "All"; // All, Closed, Unknown
public bool IncludeOnlyUsedBids { get; set; } = true;
public bool IncludeLogs { get; set; } = false;
public bool IncludeUserBids { get; set; } = false;
}
internal static class SettingsManager
{
private static readonly string _folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutoBidder");
private static readonly string _file = Path.Combine(_folder, "settings.json");
public static AppSettings Load()
{
try
{
if (!File.Exists(_file)) return new AppSettings();
var txt = File.ReadAllText(_file);
var s = JsonSerializer.Deserialize<AppSettings>(txt);
if (s == null) return new AppSettings();
return s;
}
catch { return new AppSettings(); }
}
public static void Save(AppSettings settings)
{
try
{
if (!Directory.Exists(_folder)) Directory.CreateDirectory(_folder);
var txt = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(_file, txt);
}
catch { }
}
}
}