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:
@@ -23,6 +23,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
16
Mimante/Controls/SimpleToolbar.xaml
Normal file
16
Mimante/Controls/SimpleToolbar.xaml
Normal 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>
|
||||
28
Mimante/Controls/SimpleToolbar.xaml.cs
Normal file
28
Mimante/Controls/SimpleToolbar.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
<Window x:Class="AutoBidder.Dialogs.AddAuctionSimpleDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:AutoBidder.Controls"
|
||||
Title="Aggiungi Asta" Height="320" Width="700"
|
||||
Background="#0a0a0a" Foreground="#FFFFFF"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
@@ -24,12 +25,16 @@
|
||||
Padding="8" FontSize="13" ToolTip="Inserisci uno o più URL/ID dell'asta. Separali con a capo, spazio o ';'"
|
||||
AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Height="160" />
|
||||
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,8,0,0">
|
||||
<Button x:Name="OkButton" Content="OK" Width="110" Margin="6" Padding="10,8"
|
||||
<controls:SimpleToolbar Grid.Row="3" Margin="0,8,0,0">
|
||||
<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" />
|
||||
<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" />
|
||||
</StackPanel>
|
||||
</controls:SimpleToolbar.RightContent>
|
||||
</controls:SimpleToolbar>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -19,9 +26,9 @@ namespace AutoBidder
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
// SERVIZI CORE
|
||||
// SERVIZI CORE
|
||||
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
|
||||
private AuctionViewModel? _selectedAuction;
|
||||
private bool _isAutomationActive = false;
|
||||
@@ -40,6 +47,9 @@ namespace AutoBidder
|
||||
private System.Windows.Threading.DispatcherTimer _userBannerTimer;
|
||||
private System.Windows.Threading.DispatcherTimer _userHtmlTimer;
|
||||
|
||||
// export cancellation
|
||||
private CancellationTokenSource? _exportCts;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
@@ -71,6 +81,9 @@ namespace AutoBidder
|
||||
// Carica aste salvate
|
||||
LoadSavedAuctions();
|
||||
|
||||
// Load export/settings UI
|
||||
LoadExportSettings();
|
||||
|
||||
// Ensure initial global button states (pause/stop disabled until starting)
|
||||
UpdateGlobalControlButtons();
|
||||
|
||||
@@ -84,7 +97,7 @@ namespace AutoBidder
|
||||
_userBannerTimer.Start();
|
||||
_ = 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.Interval = TimeSpan.FromMinutes(3);
|
||||
_userHtmlTimer.Tick += UserHtmlTimer_Tick;
|
||||
@@ -482,7 +495,7 @@ namespace AutoBidder
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -493,7 +506,7 @@ namespace AutoBidder
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -528,7 +541,7 @@ namespace AutoBidder
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -539,7 +552,7 @@ namespace AutoBidder
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -550,7 +563,7 @@ namespace AutoBidder
|
||||
{
|
||||
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;
|
||||
SaveAuctions(); // Persist change immediately
|
||||
@@ -570,12 +583,12 @@ namespace AutoBidder
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
_selectedAuction.TimerClick = 0;
|
||||
_selectedAuction.AuctionInfo.DelayMs = 50;
|
||||
_selectedAuction.MinPrice = 0;
|
||||
_selectedAuction.MaxPrice = 0;
|
||||
_selectedAuction.AuctionInfo.MinResets = 0;
|
||||
_selectedAuction.AuctionInfo.MaxResets = 0;
|
||||
_selectedAuction.TimerClick =0;
|
||||
_selectedAuction.AuctionInfo.DelayMs =50;
|
||||
_selectedAuction.MinPrice =0;
|
||||
_selectedAuction.MaxPrice =0;
|
||||
_selectedAuction.AuctionInfo.MinResets =0;
|
||||
_selectedAuction.AuctionInfo.MaxResets =0;
|
||||
|
||||
UpdateSelectedAuctionDetails(_selectedAuction);
|
||||
Log($"Reset impostazioni: {_selectedAuction.Name}");
|
||||
@@ -1112,8 +1125,198 @@ namespace AutoBidder
|
||||
Log($"[ERRORE] Errore salvataggio: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private enum LogLevel { Info, Warn, Error }
|
||||
|
||||
// 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 void Log(string message, LogLevel level = LogLevel.Info)
|
||||
{
|
||||
@@ -1170,6 +1373,8 @@ namespace AutoBidder
|
||||
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 ===
|
||||
private void GridOpenAuction_Click(object sender, RoutedEventArgs e)
|
||||
@@ -1248,7 +1453,7 @@ namespace AutoBidder
|
||||
|
||||
private void PauseAllButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int paused = 0;
|
||||
int paused =0;
|
||||
foreach (var vm in _auctionViewModels)
|
||||
{
|
||||
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
|
||||
if (allActive)
|
||||
{
|
||||
StartButton.IsEnabled = false; StartButton.Opacity = 0.5;
|
||||
StartButton.IsEnabled = false; StartButton.Opacity =0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
StartButton.IsEnabled = true; StartButton.Opacity = 1.0;
|
||||
StartButton.IsEnabled = true; StartButton.Opacity =1.0;
|
||||
}
|
||||
|
||||
// PauseAll button: darken if allPaused or allStopped
|
||||
if (allPaused || allStopped)
|
||||
{
|
||||
PauseAllButton.IsEnabled = false; PauseAllButton.Opacity = 0.5;
|
||||
PauseAllButton.IsEnabled = false; PauseAllButton.Opacity =0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
PauseAllButton.IsEnabled = true; PauseAllButton.Opacity = 1.0;
|
||||
PauseAllButton.IsEnabled = true; PauseAllButton.Opacity =1.0;
|
||||
}
|
||||
|
||||
// Stop button: darken if allStopped
|
||||
if (allStopped)
|
||||
{
|
||||
StopButton.IsEnabled = false; StopButton.Opacity = 0.5;
|
||||
StopButton.IsEnabled = false; StopButton.Opacity =0.5;
|
||||
}
|
||||
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();
|
||||
if (info != null)
|
||||
{
|
||||
BannerAsteDaRiscattare.Text = $"{info.nAsteVinte - info.nAsteConfermate}";
|
||||
// BannerPuntateBonus.Text = $"Bonus: {info.nPuntateBonus}"; // RIMOSSO
|
||||
// Map banner info to available UI fields
|
||||
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
|
||||
{
|
||||
// fallback: show total won minus confirmed if meaningful
|
||||
if (info.nAsteVinte >= info.nAsteConfermate)
|
||||
RemainingBidsText.Text = (info.nAsteVinte - info.nAsteConfermate).ToString();
|
||||
else
|
||||
RemainingBidsText.Text = "--";
|
||||
}
|
||||
}
|
||||
catch { RemainingBidsText.Text = "--"; }
|
||||
}
|
||||
else
|
||||
{
|
||||
BannerAsteDaRiscattare.Text = "--";
|
||||
// BannerPuntateBonus.Text = "Bonus: --"; // RIMOSSO
|
||||
RemainingBidsText.Text = "--";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1358,9 +1582,9 @@ namespace AutoBidder
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rimuovi newline e taglia a max 20 caratteri
|
||||
// Rimuovi newline e taglia a max20 caratteri
|
||||
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();
|
||||
}
|
||||
@@ -1377,7 +1601,7 @@ namespace AutoBidder
|
||||
{
|
||||
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"
|
||||
};
|
||||
|
||||
@@ -1538,5 +1762,168 @@ namespace AutoBidder
|
||||
if (v == null) return string.Empty;
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
Mimante/Utilities/SettingsManager.cs
Normal file
46
Mimante/Utilities/SettingsManager.cs
Normal 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 { }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user