From 009fa51155c9e657658483cc32a117ab52a335ce Mon Sep 17 00:00:00 2001 From: Alberto Balbo Date: Fri, 12 Dec 2025 09:32:30 +0100 Subject: [PATCH] Aggiunta UI Blazor moderna e animazioni per AutoBidder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introdotta una nuova interfaccia utente Blazor Server moderna, dark e responsive, con sidebar di navigazione, statistiche animate, banner utente, gestione stato aste e browser integrato. Aggiunti servizi per stato aste e impostazioni, ampio set di stili CSS e animazioni, integrazione JS per l'iframe browser, nuovi layout e configurazione di avvio per sviluppo e produzione. L'app è ora pronta per un'esperienza web professionale e cross-platform. --- Mimante/.dockerignore | 28 + Mimante/App.razor | 12 + Mimante/AutoBidder.csproj | 42 +- Mimante/Dockerfile | 21 + .../Documentation/ARCHITECTURE_OVERVIEW.md | 357 -------- Mimante/Documentation/CHANGELOG.md | 344 -------- .../DEBUG_COOKIE_DETECTION_LOGGING.md | 261 ------ .../Documentation/DIAGNOSTICA_DATI_UTENTE.md | 148 ---- .../FEATURE_AUCTION_BUTTONS_REORGANIZED.md | 437 ---------- .../FEATURE_AUCTION_NAVIGATION_REORDER.md | 340 -------- .../FEATURE_AUTO_FOCUS_AFTER_DELETE.md | 341 -------- .../Documentation/FEATURE_BID_HISTORY_TAB.md | 515 ----------- .../FEATURE_CONFIGURABLE_LOG_LIMITS.md | 410 --------- .../FEATURE_HTML_CACHE_SERVICE.md | 444 ---------- .../FEATURE_INITIAL_AUCTION_STATE.md | 397 --------- .../Documentation/FEATURE_LOG_MAX_LINES.md | 368 -------- .../FEATURE_MINIMUM_BIDS_LIMIT.md | 469 ---------- .../FEATURE_NUMERIC_INPUT_VALIDATION.md | 399 --------- ...ATURE_PRODUCT_INFO_AND_VALUE_CALCULATOR.md | 590 ------------- .../FEATURE_PRODUCT_VALUE_CALCULATOR.md | 192 ----- ...E_WEBVIEW_PRELOAD_AND_COOKIE_EXTRACTION.md | 815 ------------------ .../Documentation/FIX_AUCTION_LOG_COLOR.md | 126 --- .../FIX_BID_COUNT_FROM_SERVER.md | 388 --------- .../FIX_BID_HISTORY_PERSISTENCE.md | 387 --------- .../Documentation/FIX_BROWSER_URL_READONLY.md | 288 ------- .../FIX_CLIPBOARD_FALSE_ERROR.md | 282 ------ .../FIX_COOKIE_LOADING_USER_DATA.md | 398 --------- .../Documentation/FIX_COOKIE_PERSISTENCE.md | 404 --------- .../FIX_COOKIE_SESSION_WARMUP.md | 430 --------- .../FIX_CORRECT_FIELD_INDICES.md | 297 ------- .../FIX_DEFAULT_SETTINGS_PERSISTENCE.md | 327 ------- Mimante/Documentation/FIX_DELETE_KEY.md | 199 ----- .../Documentation/FIX_EMOJI_NOT_DISPLAYED.md | 298 ------- Mimante/Documentation/FIX_LOG_CLEANUP_UX.md | 519 ----------- .../Documentation/FIX_PRODUCT_INFO_PARSING.md | 278 ------ .../FIX_RUNTIME_COOKIE_EVENTS.md | 485 ----------- .../FIX_SETTINGS_SAVE_AND_LOGGING.md | 368 -------- .../FIX_SIDEBAR_VISIBILITY_WEBVIEW_INIT.md | 452 ---------- .../Documentation/FIX_SINGLE_AUCTION_START.md | 234 ----- .../Documentation/FIX_SKIP_BID_IF_WINNER.md | 341 -------- .../FIX_TAB_SETTINGS_WEBVIEW_INIT.md | 380 -------- .../Documentation/FIX_UI_UPDATE_AFTER_BID.md | 425 --------- .../FIX_WEBVIEW_ALREADY_INITIALIZED.md | 296 ------- .../FIX_WEBVIEW_THREADING_ERROR.md | 653 -------------- .../FIX_WEBVIEW_TIMEOUT_USERDATAFOLDER.md | 352 -------- .../FIX_WEBVIEW_VISIBILITY_REQUIREMENT.md | 378 -------- Mimante/Documentation/LOG_CLEANUP_FINAL.md | 334 ------- .../Documentation/PROJECT_REORGANIZATION.md | 363 -------- .../REFACTORING_BROWSER_ADDRESS_BAR.md | 563 ------------ .../REFACTORING_COOKIE_DETECTION_TIMING.md | 802 ----------------- .../REFACTORING_EXECUTIVE_SUMMARY.md | 275 ------ .../REFACTORING_SESSION_SERVICE_COMPLETE.md | 488 ----------- .../REFACTORING_SESSION_SERVICE_PROPOSAL.md | 592 ------------- .../REFACTORING_SETTINGS_PERSISTENCE.md | 611 ------------- Mimante/Documentation/REFACTORING_SUMMARY.md | 172 ---- .../UI_PRODUCT_VALUE_IMPLEMENTATION.md | 335 ------- .../XAML_REFACTORING_CHECKLIST.md | 304 ------- .../Documentation/XAML_REFACTORING_SUMMARY.md | 360 -------- Mimante/Models/BidHistoryEntry.cs | 4 +- Mimante/Pages/Browser.razor | 292 +++++++ Mimante/Pages/FreeBids.razor | 406 +++++++++ Mimante/Pages/Index.razor | 286 ++++++ Mimante/Pages/Index.razor.cs | 366 ++++++++ Mimante/Pages/Settings.razor | 368 ++++++++ Mimante/Pages/Statistics.razor | 200 +++++ Mimante/Pages/_Host.cshtml | 37 + Mimante/Pages/_Layout.cshtml | 32 + Mimante/Program.cs | 125 +++ Mimante/Properties/launchSettings.json | 37 + Mimante/Services/AuctionStateService.cs | 56 ++ Mimante/Services/SessionManager.cs | 48 +- Mimante/Services/Settings.cs | 11 + Mimante/Services/StatsService.cs | 4 +- Mimante/Shared/MainLayout.razor | 28 + Mimante/Shared/NavMenu.razor | 121 +++ Mimante/Shared/UserBanner.razor | 145 ++++ Mimante/Utilities/SettingsManager.cs | 4 +- Mimante/_Imports.razor | 12 + Mimante/appsettings.json | 9 + Mimante/docker-compose.yml | 16 + Mimante/wwwroot/css/animations.css | 554 ++++++++++++ Mimante/wwwroot/css/app.css | 603 +++++++++++++ .../wwwroot/css/bootstrap/bootstrap.min.css | 47 + Mimante/wwwroot/js/browser-interop.js | 161 ++++ 84 files changed, 4053 insertions(+), 21033 deletions(-) create mode 100644 Mimante/.dockerignore create mode 100644 Mimante/App.razor create mode 100644 Mimante/Dockerfile delete mode 100644 Mimante/Documentation/ARCHITECTURE_OVERVIEW.md delete mode 100644 Mimante/Documentation/CHANGELOG.md delete mode 100644 Mimante/Documentation/DEBUG_COOKIE_DETECTION_LOGGING.md delete mode 100644 Mimante/Documentation/DIAGNOSTICA_DATI_UTENTE.md delete mode 100644 Mimante/Documentation/FEATURE_AUCTION_BUTTONS_REORGANIZED.md delete mode 100644 Mimante/Documentation/FEATURE_AUCTION_NAVIGATION_REORDER.md delete mode 100644 Mimante/Documentation/FEATURE_AUTO_FOCUS_AFTER_DELETE.md delete mode 100644 Mimante/Documentation/FEATURE_BID_HISTORY_TAB.md delete mode 100644 Mimante/Documentation/FEATURE_CONFIGURABLE_LOG_LIMITS.md delete mode 100644 Mimante/Documentation/FEATURE_HTML_CACHE_SERVICE.md delete mode 100644 Mimante/Documentation/FEATURE_INITIAL_AUCTION_STATE.md delete mode 100644 Mimante/Documentation/FEATURE_LOG_MAX_LINES.md delete mode 100644 Mimante/Documentation/FEATURE_MINIMUM_BIDS_LIMIT.md delete mode 100644 Mimante/Documentation/FEATURE_NUMERIC_INPUT_VALIDATION.md delete mode 100644 Mimante/Documentation/FEATURE_PRODUCT_INFO_AND_VALUE_CALCULATOR.md delete mode 100644 Mimante/Documentation/FEATURE_PRODUCT_VALUE_CALCULATOR.md delete mode 100644 Mimante/Documentation/FEATURE_WEBVIEW_PRELOAD_AND_COOKIE_EXTRACTION.md delete mode 100644 Mimante/Documentation/FIX_AUCTION_LOG_COLOR.md delete mode 100644 Mimante/Documentation/FIX_BID_COUNT_FROM_SERVER.md delete mode 100644 Mimante/Documentation/FIX_BID_HISTORY_PERSISTENCE.md delete mode 100644 Mimante/Documentation/FIX_BROWSER_URL_READONLY.md delete mode 100644 Mimante/Documentation/FIX_CLIPBOARD_FALSE_ERROR.md delete mode 100644 Mimante/Documentation/FIX_COOKIE_LOADING_USER_DATA.md delete mode 100644 Mimante/Documentation/FIX_COOKIE_PERSISTENCE.md delete mode 100644 Mimante/Documentation/FIX_COOKIE_SESSION_WARMUP.md delete mode 100644 Mimante/Documentation/FIX_CORRECT_FIELD_INDICES.md delete mode 100644 Mimante/Documentation/FIX_DEFAULT_SETTINGS_PERSISTENCE.md delete mode 100644 Mimante/Documentation/FIX_DELETE_KEY.md delete mode 100644 Mimante/Documentation/FIX_EMOJI_NOT_DISPLAYED.md delete mode 100644 Mimante/Documentation/FIX_LOG_CLEANUP_UX.md delete mode 100644 Mimante/Documentation/FIX_PRODUCT_INFO_PARSING.md delete mode 100644 Mimante/Documentation/FIX_RUNTIME_COOKIE_EVENTS.md delete mode 100644 Mimante/Documentation/FIX_SETTINGS_SAVE_AND_LOGGING.md delete mode 100644 Mimante/Documentation/FIX_SIDEBAR_VISIBILITY_WEBVIEW_INIT.md delete mode 100644 Mimante/Documentation/FIX_SINGLE_AUCTION_START.md delete mode 100644 Mimante/Documentation/FIX_SKIP_BID_IF_WINNER.md delete mode 100644 Mimante/Documentation/FIX_TAB_SETTINGS_WEBVIEW_INIT.md delete mode 100644 Mimante/Documentation/FIX_UI_UPDATE_AFTER_BID.md delete mode 100644 Mimante/Documentation/FIX_WEBVIEW_ALREADY_INITIALIZED.md delete mode 100644 Mimante/Documentation/FIX_WEBVIEW_THREADING_ERROR.md delete mode 100644 Mimante/Documentation/FIX_WEBVIEW_TIMEOUT_USERDATAFOLDER.md delete mode 100644 Mimante/Documentation/FIX_WEBVIEW_VISIBILITY_REQUIREMENT.md delete mode 100644 Mimante/Documentation/LOG_CLEANUP_FINAL.md delete mode 100644 Mimante/Documentation/PROJECT_REORGANIZATION.md delete mode 100644 Mimante/Documentation/REFACTORING_BROWSER_ADDRESS_BAR.md delete mode 100644 Mimante/Documentation/REFACTORING_COOKIE_DETECTION_TIMING.md delete mode 100644 Mimante/Documentation/REFACTORING_EXECUTIVE_SUMMARY.md delete mode 100644 Mimante/Documentation/REFACTORING_SESSION_SERVICE_COMPLETE.md delete mode 100644 Mimante/Documentation/REFACTORING_SESSION_SERVICE_PROPOSAL.md delete mode 100644 Mimante/Documentation/REFACTORING_SETTINGS_PERSISTENCE.md delete mode 100644 Mimante/Documentation/REFACTORING_SUMMARY.md delete mode 100644 Mimante/Documentation/UI_PRODUCT_VALUE_IMPLEMENTATION.md delete mode 100644 Mimante/Documentation/XAML_REFACTORING_CHECKLIST.md delete mode 100644 Mimante/Documentation/XAML_REFACTORING_SUMMARY.md create mode 100644 Mimante/Pages/Browser.razor create mode 100644 Mimante/Pages/FreeBids.razor create mode 100644 Mimante/Pages/Index.razor create mode 100644 Mimante/Pages/Index.razor.cs create mode 100644 Mimante/Pages/Settings.razor create mode 100644 Mimante/Pages/Statistics.razor create mode 100644 Mimante/Pages/_Host.cshtml create mode 100644 Mimante/Pages/_Layout.cshtml create mode 100644 Mimante/Program.cs create mode 100644 Mimante/Properties/launchSettings.json create mode 100644 Mimante/Services/AuctionStateService.cs create mode 100644 Mimante/Services/Settings.cs create mode 100644 Mimante/Shared/MainLayout.razor create mode 100644 Mimante/Shared/NavMenu.razor create mode 100644 Mimante/Shared/UserBanner.razor create mode 100644 Mimante/_Imports.razor create mode 100644 Mimante/appsettings.json create mode 100644 Mimante/docker-compose.yml create mode 100644 Mimante/wwwroot/css/animations.css create mode 100644 Mimante/wwwroot/css/app.css create mode 100644 Mimante/wwwroot/css/bootstrap/bootstrap.min.css create mode 100644 Mimante/wwwroot/js/browser-interop.js diff --git a/Mimante/.dockerignore b/Mimante/.dockerignore new file mode 100644 index 0000000..06ddeba --- /dev/null +++ b/Mimante/.dockerignore @@ -0,0 +1,28 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +Documentation/ +.github/ +.vscode/ diff --git a/Mimante/App.razor b/Mimante/App.razor new file mode 100644 index 0000000..f452697 --- /dev/null +++ b/Mimante/App.razor @@ -0,0 +1,12 @@ + + + + + + + Non trovato + +

Spiacenti, non c' nulla a questo indirizzo.

+
+
+
diff --git a/Mimante/AutoBidder.csproj b/Mimante/AutoBidder.csproj index 67b8469..a814d21 100644 --- a/Mimante/AutoBidder.csproj +++ b/Mimante/AutoBidder.csproj @@ -1,24 +1,48 @@ - + - WinExe - net8.0-windows + net8.0 enable enable - true AutoBidder AutoBidder + Linux + + + + + + + + + + + + + + + + + + + + + + + + - - + + + @@ -27,12 +51,12 @@ - - - + + PreserveNewest + diff --git a/Mimante/Dockerfile b/Mimante/Dockerfile new file mode 100644 index 0000000..d861001 --- /dev/null +++ b/Mimante/Dockerfile @@ -0,0 +1,21 @@ +# Usa l'immagine base ASP.NET Runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +WORKDIR /app +EXPOSE 5000 + +# Usa l'immagine SDK per build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src +COPY ["AutoBidder.csproj", "./"] +RUN dotnet restore "AutoBidder.csproj" +COPY . . +RUN dotnet build "AutoBidder.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "AutoBidder.csproj" -c Release -o /app/publish /p:UseAppHost=false + +# Immagine finale +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "AutoBidder.dll"] diff --git a/Mimante/Documentation/ARCHITECTURE_OVERVIEW.md b/Mimante/Documentation/ARCHITECTURE_OVERVIEW.md deleted file mode 100644 index d2781e9..0000000 --- a/Mimante/Documentation/ARCHITECTURE_OVERVIEW.md +++ /dev/null @@ -1,357 +0,0 @@ -# AutoBidder v4.0 - Architettura Completa - -## ?? Diagramma Architettura - -``` -??????????????????????????????????????????????????????????????????????? -? MainWindow.xaml ? -? (TabControl Principale) ? -??????????????????????????????????????????????????????????????????????? -? ? -? ????????????? ????????????? ???????????????? ???????????????? ? -? ? ?? Monitor? ? ?? Browser? ? ?? Statistiche? ? ?? Impostazioni? ? -? ? Aste ? ? ? ? ? ? ? ? -? ????????????? ????????????? ???????????????? ???????????????? ? -? ? ? ? ? ? -? ? ? ? ? ? -? ??????????????????????????????????????????????????????????????? ? -? ? UserControls (4 controlli modulari) ? ? -? ??????????????????????????????????????????????????????????????? ? -? ? -????????????????????????????????????????????????????????????????????? - ? - ? Events & Data Binding - ? - ? -??????????????????????????????????????????????????????????????????????? -? MainWindow Code-Behind ? -? (Partial Classes - 13 file) ? -??????????????????????????????????????????????????????????????????????? -? ? -? MainWindow.xaml.cs ? Core & Initialization ? -? MainWindow.ControlEvents.cs ? NEW: Event Routing ? -? MainWindow.Commands.cs ? Command Pattern ? -? MainWindow.AuctionManagement.cs ? CRUD Aste ? -? MainWindow.EventHandlers.Browser.cs ? Browser Logic ? -? MainWindow.EventHandlers.Export.cs ? Export Features ? -? MainWindow.EventHandlers.Settings.cs ? Settings Management ? -? MainWindow.EventHandlers.Stats.cs ? Statistics Analysis ? -? MainWindow.Logging.cs ? Logging System ? -? MainWindow.UIUpdates.cs ? UI Refresh ? -? MainWindow.UrlParsing.cs ? URL Utilities ? -? MainWindow.UserInfo.cs ? User Session ? -? MainWindow.ButtonHandlers.cs ? Button Events ? -? ? -????????????????????????????????????????????????????????????????????? - ? - ? Service Layer - ? - ? -??????????????????????????????????????????????????????????????????????? -? Services Layer ? -??????????????????????????????????????????????????????????????????????? -? ? -? AuctionMonitor ? Core monitoring service ? -? BidooApiClient ? HTTP API client ? -? SessionManager ? Session persistence ? -? StatsService ? Statistics engine ? -? ClosedAuctionsScraper ? Data scraping ? -? ? -????????????????????????????????????????????????????????????????????? - ? - ? Data Access - ? - ? -??????????????????????????????????????????????????????????????????????? -? Models & Data Layer ? -??????????????????????????????????????????????????????????????????????? -? ? -? Models/ ? -? ??? AuctionInfo ? Dati asta ? -? ??? AuctionState ? Stato runtime ? -? ??? BidResult ? Risultato puntata ? -? ??? BidHistory ? Storico ? -? ??? BidderInfo ? Info utenti ? -? ??? ... ? -? ? -? ViewModels/ ? -? ??? AuctionViewModel ? MVVM pattern ? -? ? -? Data/ ? -? ??? StatisticsContext ? EF Core DbContext ? -? ? -? Utilities/ ? -? ??? PersistenceManager ? Salvataggio JSON ? -? ??? SettingsManager ? App settings ? -? ??? CsvExporter ? Export utilities ? -? ??? ... ? -? ? -??????????????????????????????????????????????????????????????????????? -``` - -## ?? Flusso Dati - -### 1. User Interaction Flow -``` -User Click - ? -UserControl (XAML) - ? -UserControl.xaml.cs (Routed Event) - ? -MainWindow.ControlEvents.cs (Event Router) - ? -MainWindow.[Feature].cs (Business Logic) - ? -Service Layer (AuctionMonitor, ApiClient, etc.) - ? -Models/Data Update - ? -Property Change Notification - ? -UI Update (Data Binding) -``` - -### 2. Auction Monitoring Flow -``` -AuctionMonitor.Start() - ? -Polling Loop (async) - ? -BidooApiClient.PollAuctionStateAsync() - ? -HTTP Request to Bidoo API - ? -Parse JSON Response - ? -Update AuctionState - ? -Fire OnAuctionUpdated Event - ? -MainWindow.AuctionMonitor_OnAuctionUpdated() - ? -Update AuctionViewModel - ? -DataGrid Auto-Refresh (INotifyPropertyChanged) -``` - -### 3. Export Flow -``` -User Click "Esporta" - ? -MainWindow.EventHandlers.Export.cs - ? -Load Export Settings - ? -Filter Auctions (Open/Closed/Unknown) - ? -For Each Auction: - ?? Generate File (CSV/JSON/XML) - ?? CsvExporter / JsonSerializer / XDocument - ?? Save to Disk - ? -Optional: Remove Exported Auctions - ? -Show Completion Message -``` - -## ?? Componenti Chiave - -### UserControls -``` -Controls/ -??? AuctionMonitorControl [430 lines XAML] -? ??? Header (Toolbar) -? ??? MainContent (Grid + Details) -? ??? Footer (Global Log) -? -??? BrowserControl [120 lines XAML] -? ??? Navigation Toolbar -? ??? WebView2 Embedded -? -??? StatisticsControl [80 lines XAML] -? ??? Header (Load Button) -? ??? DataGrid (Stats) -? ??? Footer (Progress) -? -??? SettingsControl [200 lines XAML] - ??? Session Config - ??? Export Settings - ??? Auction Defaults -``` - -### Partial Classes -``` -MainWindow/ -??? xaml.cs [150 lines] Core -??? ControlEvents.cs [150 lines] NEW: Event routing -??? Commands.cs [80 lines] Commands -??? AuctionManagement.cs [200 lines] CRUD -??? EventHandlers.*.cs [600 lines] Events (4 files) -??? Logging.cs [50 lines] Log system -??? UIUpdates.cs [120 lines] UI refresh -??? UrlParsing.cs [80 lines] URL utils -??? UserInfo.cs [140 lines] Session -??? ButtonHandlers.cs [200 lines] Buttons -``` - -## ?? Design Patterns Utilizzati - -### 1. **MVVM (Model-View-ViewModel)** -- `Model`: AuctionInfo, BidHistory, etc. -- `View`: XAML files (MainWindow, UserControls) -- `ViewModel`: AuctionViewModel (INotifyPropertyChanged) - -### 2. **Service Layer** -- `AuctionMonitor`: Orchestrazione monitoring -- `BidooApiClient`: HTTP communication -- `SessionManager`: Persistenza sessione - -### 3. **Repository Pattern** -- `PersistenceManager`: Load/Save aste -- `SettingsManager`: Load/Save settings - -### 4. **Observer Pattern** -- Events: `OnAuctionUpdated`, `OnBidExecuted`, `OnLog` -- Data Binding: `INotifyPropertyChanged` - -### 5. **Command Pattern** -- `RelayCommand`: WPF ICommand implementation -- Grid commands: Start, Pause, Stop, Bid - -### 6. **Composite Pattern** -- UserControls compongono il MainWindow -- Ogni controllo autonomo ma collabora - -### 7. **Strategy Pattern** -- Export formats: CSV, JSON, XML -- Diversi scraper per HTML parsing - -## ?? Sicurezza & Best Practices - -### ? Implementate -- [x] Cookie encryption (future enhancement) -- [x] Input validation (URL, prezzi, etc.) -- [x] Error handling robusto -- [x] Logging strutturato -- [x] Thread safety (lock su collections) - -### ?? Raccomandazioni Future -- [ ] Secure credential storage (Windows Credential Manager) -- [ ] Rate limiting per API calls -- [ ] Retry policy con exponential backoff -- [ ] Circuit breaker pattern per resilienza -- [ ] Telemetry & monitoring - -## ?? Metriche Codebase - -| Metrica | Prima | Dopo | Delta | -|---------|-------|------|-------| -| File XAML | 1 (1000 lines) | 5 (100+4150) | +4 files | -| File C# (MainWindow) | 2 | 14 | +12 files | -| Dimensione media file | 500 lines | 120 lines | -76% | -| Linee per classe | 1000+ | 50-200 | -80% | -| Complessit ciclomatica | Alta | Bassa | ?? | -| Testabilit | 30% | 85% | +55% | -| Riutilizzabilit | 10% | 90% | +80% | - -## ?? Performance - -### Ottimizzazioni -1. **Lazy Loading**: Tab caricati on-demand -2. **Virtual Scrolling**: DataGrid virtualizzato -3. **Async Operations**: Tutte le IO sono async -4. **Caching**: Stati asta cachati in memoria -5. **Debouncing**: TextBox changes debounced - -### Benchmarks Stimati -- Startup time: ~2s (cold), ~0.5s (warm) -- UI responsiveness: <16ms per frame (60fps) -- Memory footprint: ~100MB base + 10MB per 100 aste -- API polling: ~50-200ms latency media - -## ?? Documentazione - -### File Documentazione Creati -1. `REFACTORING_SUMMARY.md` - Code-behind refactoring -2. `XAML_REFACTORING_SUMMARY.md` - XAML refactoring -3. `ARCHITECTURE_OVERVIEW.md` - Questo file - -### XML Comments -Tutte le classi public hanno XML documentation: -```csharp -/// -/// Descrizione classe -/// -/// Descrizione parametro -/// Descrizione return -``` - -## ?? Getting Started - -### Per Sviluppatori - -1. **Clona il repository** - ```bash - git clone https://192.168.30.23/Alby96/Mimante - cd Mimante/Mimante - ``` - -2. **Apri in Visual Studio 2022** - - Apri `AutoBidder.csproj` - - Restore NuGet packages - - Build Solution - -3. **Struttura Progetto** - - `/Controls/` - UserControls modulari - - `/Services/` - Business logic - - `/Models/` - Data models - - `/ViewModels/` - MVVM ViewModels - - `/Utilities/` - Helper utilities - -4. **Workflow Sviluppo** - - Modifica UI ? Edit UserControl XAML - - Modifica logic ? Edit MainWindow partial classes - - Aggiungi feature ? Create new service/model - - Test ? Build & Run - -### Per Utenti Finali - -1. **Primo Avvio** - - Tab "Impostazioni" ? Configura sessione (cookie) - - Tab "Impostazioni" ? Imposta percorso export - -2. **Monitoraggio Aste** - - Tab "Monitor Aste" ? Aggiungi URL/ID asta - - Clicca "Avvia" per iniziare il monitoring - - Configura parametri asta nel pannello dettagli - -3. **Statistiche** - - Tab "Statistiche" ? Carica aste chiuse - - Analizza medie prezzi e click - -## ?? Troubleshooting - -### Problemi Comuni - -**Problema**: Cookie non valido -- **Soluzione**: Vai su bidoo.com, F12 > Application > Cookies > Copia __stattrb - -**Problema**: WebView2 non si carica -- **Soluzione**: Installa WebView2 Runtime da microsoft.com - -**Problema**: Export fallisce -- **Soluzione**: Verifica permessi cartella e spazio disco - -**Problema**: Asta non viene monitorata -- **Soluzione**: Verifica che sia attiva (checkbox) e non in pausa - -## ?? Support - -- **Issues**: GitHub Issues -- **Docs**: `/docs` folder -- **Wiki**: Project Wiki - ---- - -**AutoBidder v4.0** - Architettura modulare e scalabile per il monitoraggio automatizzato delle aste Bidoo.com ?? diff --git a/Mimante/Documentation/CHANGELOG.md b/Mimante/Documentation/CHANGELOG.md deleted file mode 100644 index 1702f29..0000000 --- a/Mimante/Documentation/CHANGELOG.md +++ /dev/null @@ -1,344 +0,0 @@ -# Changelog - -Tutte le modifiche importanti a questo progetto saranno documentate in questo file. - -Il formato è basato su [Keep a Changelog](https://keepachangelog.com/it/1.0.0/), -e questo progetto aderisce a [Semantic Versioning](https://semver.org/lang/it/). - -## [4.0.0] - 2024 - -### 🎉 Maggiori Cambiamenti - -#### Refactoring Architettura -- **Partial Classes**: MainWindow diviso in 13 file partial per responsabilità specifiche -- **UserControls Modulari**: Creati 5 UserControls riutilizzabili (AuctionMonitor, Browser, Settings, Statistics, SimpleToolbar) -- **Struttura a Cartelle**: Riorganizzazione completa del progetto in cartelle logiche - -#### Nuovo Layout UI -- **Dashboard Moderna**: Layout a griglia con panel ridimensionabili -- **GridSplitters**: 4 splitter per personalizzazione completa del workspace -- **Design Dark Theme**: Palette colori consistente (#1E1E1E, #252526, #2D2D30) -- **Card-Style Panels**: Tutti i pannelli con bordi arrotondati e ombre - -### ✨ Nuove Funzionalità - -#### Sistema di Logging Avanzato -- Log colorati per severity (Info, Success, Warn, Error) -- Timestamp automatici -- Auto-scroll intelligente -- Log globale + log per singola asta - -#### Monitoraggio Aste -- Monitoraggio simultaneo di più aste -- Polling HTTP API-based (no Selenium) -- Tracking real-time timer, prezzo, offerenti -- Statistiche dettagliate per asta - -#### Browser Integrato -- WebView2 Microsoft Edge -- Navigazione completa su Bidoo -- Aggiunta rapida aste da URL -- Context menu personalizzato - -#### Export Dati -- Supporto formati: CSV, JSON, XML -- Export massivo o per singola asta -- Opzioni configurabili (logs, bidders, metadata) -- Auto-rimozione dopo export - -### 🔧 Miglioramenti - -#### Performance -- Ridotto uso memoria con lazy loading UserControls -- Ottimizzazione rendering DataGrid con virtualizzazione -- Async/await per tutte le operazioni I/O -- Throttling polling API - -#### UX/UI -- Icone emoji per maggiore leggibilità -- Tooltip informativi su bottoni disabilitati -- Feedback visivo per azioni utente -- Messaggi di errore user-friendly - -#### Code Quality -- Riduzione complessità ciclomatica -- Separazione concerns (SoC) -- Eliminazione codice duplicato -- XML documentation per API pubbliche - -### 📦 Dipendenze - -#### Aggiunte -- `Microsoft.EntityFrameworkCore.Sqlite` v8.0.0 -- `Microsoft.Web.WebView2` v1.0.1343.22 -- `Microsoft.Windows.SDK.BuildTools` v10.0.26100.6584 - -#### Rimosse -- ~~Selenium.WebDriver~~ (sostituito con HTTP API) -- ~~Selenium.WebDriver.ChromeDriver~~ (non più necessario) - -### 🐛 Bug Fix - -#### Critici -- Fix memory leak in AuctionMonitor polling loop -- Fix race condition in bid execution -- Fix crash quando WebView2 non inizializzato -- Fix parsing URL con caratteri speciali - -#### Minori -- Fix auto-scroll log quando raggiunge bottom -- Fix selezione asta dopo rimozione -- Fix salvataggio impostazioni con valori nulli -- Fix export XML con caratteri escape - -### 🔒 Sicurezza - -- Cookie session storage cifrato -- Validazione input URL -- Sanitizzazione dati prima di export -- Protezione contro injection in log - -### 📝 Documentazione - -#### Nuovi File -- `README.md` - Panoramica progetto e setup -- `REFACTORING_SUMMARY.md` - Dettagli refactoring code-behind -- `XAML_REFACTORING_SUMMARY.md` - Dettagli refactoring XAML -- `ARCHITECTURE_OVERVIEW.md` - Overview architettura software -- `XAML_REFACTORING_CHECKLIST.md` - Checklist implementazione -- `CHANGELOG.md` - Questo file - -#### Guide -- Guida importazione cookie da browser -- Best practices per configurazione aste -- FAQ troubleshooting comuni - -### 🗂️ Struttura Progetto - -``` -Prima: -AutoBidder/ -├── MainWindow.xaml/cs (2000+ righe) -├── Models/ -├── Services/ -└── Utilities/ - -Dopo: -AutoBidder/ -├── Core/ -│ ├── MainWindow files (13 partial classes) -│ └── EventHandlers/ -├── Controls/ (5 UserControls) -├── Dialogs/ -├── Models/ -├── Services/ -├── ViewModels/ -├── Utilities/ -├── Data/ -└── Documentation/ -``` - -### 📊 Metriche - -| Metrica | Prima | Dopo | Miglioramento | -|---------|-------|------|---------------| -| LOC MainWindow.xaml | 1000+ | 100 | -90% | -| LOC MainWindow.xaml.cs | 2000+ | 180 | -91% | -| File partial classes | 1 | 13 | +1200% | -| Complessità ciclomatica | 85 | 12 | -86% | -| Test coverage | 0% | 45% | +45% | -| Manutenibilità | 35 | 82 | +134% | - -### ⚠️ Breaking Changes - -- **Namespace Changes**: Alcuni namespace sono stati riorganizzati -- **API Changes**: `AuctionMonitor` ha nuova signature per eventi -- **Config Format**: Formato file `app_settings.json` modificato -- **Database Schema**: Aggiunto campo `PollingLatencyMs` a statistiche - -### 🔄 Migrazioni - -#### Da v3.x a v4.0 - -1. **Cookie Session**: - ```json - // Vecchio formato - { "cookie": "..." } - - // Nuovo formato - { "authCookie": "...", "userId": "...", "expiryDate": "..." } - ``` - -2. **Aste Salvate**: - - Percorso spostato da `auctions.json` → `saved_auctions.json` - - Eseguire script migrazione: `dotnet run --migrate` - -3. **Database SQLite**: - - Nuova tabella `AuctionStatistics` - - Eseguire: `dotnet ef database update` - -### 🎯 Roadmap Futura - -#### v4.1 (Q1 2025) -- [ ] Sistema notifiche desktop -- [ ] Multi-account support -- [ ] Temi personalizzabili -- [ ] Backup cloud automatico - -#### v4.2 (Q2 2025) -- [ ] Machine Learning per bid prediction -- [ ] Analytics dashboard avanzato -- [ ] Plugin system -- [ ] REST API per integrazioni - -#### v5.0 (Q3 2025) -- [ ] Architettura microservizi -- [ ] Web version (Blazor) -- [ ] Mobile app (MAUI) -- [ ] Multi-piattaforma (Linux, macOS) - -### 🙏 Ringraziamenti - -- **Microsoft**: Per .NET 8 e WPF -- **WebView2 Team**: Per il fantastico browser embedded -- **EF Core Team**: Per l'ORM potente e leggero -- **Bidoo**: Per la piattaforma aste (non ufficialmente affiliati) - ---- - -**Legenda Emoji**: -- 🎉 Maggiori cambiamenti -- ✨ Nuove funzionalità -- 🔧 Miglioramenti -- 🐛 Bug fix -- 🔒 Sicurezza -- 📝 Documentazione -- 🗂️ Struttura -- 📊 Metriche -- ⚠️ Breaking changes -- 🔄 Migrazioni -- 🎯 Roadmap -- 🙏 Ringraziamenti - -## v4.1 - UI Modernizzata (2024-01-XX) - -### 🎨 Miglioramenti UI -- ✅ **Header semplificato**: Info utente spostate in basso a sinistra -- ✅ **Pannello utente** elegante con: - - Username + ID utente - - Email - - Design card moderno con bordi arrotondati - - Visibilità automatica (appare solo quando loggato) -- ✅ **Header compatto** con statistiche chiave: - - Puntate residue (verde #00D800) - - Credito Shop (verde #00D800) - - Aste vinte (giallo #FFB700) -- ✅ **Layout pulito** stile moderno con separatori verticali - -### ⚙️ Performance -- ✅ **Aggiornamento ogni 5 minuti** (era 1 minuto) - - Timer HTML principale: 5 minuti - - Timer API fallback: 10 minuti - - Ridotto carico rete del 80% -- ✅ Pannello utente nascosto di default (meno distrazione) - -### 📊 Posizionamento Info -``` -┌─────────────────────────────────────────────┐ -│ Puntate: 199 | Credito: EUR 15.00 | Aste: 0│ [Pulsanti] -├─────────────────────────────────────────────┤ -│ │ -│ GRIGLIA ASTE + LOG │ -│ │ -├─────────────────────────────────────────────┤ -│ IMPOSTAZIONI | UTENTI | LOG │ -│ │ -└─────────────────────────────────────────────┘ - ┌────────────────────┐ - │ sirbietole23 │ ← Pannello utente - │ (ID: 6707664) │ in basso a sx - │ email@email.com │ - └────────────────────┘ -``` - ---- - -## v4.0 - Sistema di Timing Avanzato - -### ⚡ Nuovo Sistema di Timing -- ✅ Sostituito "Timer Click (secondi)" con "Anticipo (ms)" -- ✅ Precisione al millisecondo invece dei secondi -- ✅ Polling adattivo 10-1000ms basato su timer rimanente -- ✅ Cooldown 800ms tra puntate consecutive -- ✅ Rilevamento puntate recenti altri utenti (500ms) -- ✅ Checkbox opzionale "Verifica stato asta prima di puntare" - -### 🐛 Bug Fix -- ✅ Fix persistenza valori modificati per singola asta -- ✅ Fix visualizzazione username e puntate rimanenti -- ✅ Conferma richiesta prima di cancellare asta (pulsante + tasto Canc) -- ✅ Ottimizzazione logging per miglior performance -- ✅ Fix stato pulsanti globali all'avvio -- ✅ **Fix tasto Canc**: Ora elimina correttamente l'asta selezionata - - Cambiato da `KeyDown` a `PreviewKeyDown` (priorità più alta) - - Migliorata gestione focus keyboard sul DataGrid - - Aggiunto messaggio di conferma migliorato - - Aggiunto logging dettagliato per debug - - **Fix messaggio duplicato**: Rimosso secondo messaggio di conferma (ora ne appare solo uno) -- ✅ **Fix avvio singola asta**: Ora il pulsante "Avvia" sulla griglia funziona senza "Avvia Tutti" - - Auto-start del monitoraggio quando si avvia la prima asta - - Auto-stop del monitoraggio quando si ferma l'ultima asta - - Logging dettagliato con `[AUTO-START]` e `[AUTO-STOP]` - - Comportamento più intuitivo e flessibile -- ✅ **Fix persistenza impostazioni predefinite**: Le impostazioni ora vengono applicate e persistono correttamente - - Nuove aste usano valori dalle impostazioni salvate invece di hardcoded - - Impostazioni predefinite vengono caricate all'avvio - - Logging dettagliato quando si salvano/applicano defaults - - File settings.json in %LocalAppData%\AutoBidder -- ✅ **Fix puntata se già vincitore**: Sistema ora evita di puntare quando l'utente è già il vincitore corrente - - Controllo `IsMyBid` in `ShouldBid()` come prima condizione - - Logging chiaro: `[STRATEGIA] SKIP: Sono già il vincitore corrente` - - Elimina errori "Asta chiusa" quando già vincitore - - Risparmia puntate e chiamate API inutili - - Punta solo quando serve riprendersi l'asta -- ✅ **Fix campo URL browser**: URL sempre visibile e campo non editabile - - Campo URL ora `IsReadOnly="True"` (non modificabile) - - URL si aggiorna automaticamente ad ogni navigazione - - Rimosso pulsante "Vai" non funzionale - - Cursore freccia + tooltip esplicativo - - UX più chiara e coerente -- ✅ **Navigazione con frecce direzionali**: Naviga tra le aste con i tasti Su e Giù - - Comportamento nativo WPF della DataGrid - - Aggiornamento automatico pannello dettagli asta - - Scroll automatico per seguire la selezione - - Navigazione rapida senza usare il mouse -- ✅ **Riordinamento manuale aste**: Pulsanti per cambiare l'ordine delle aste nella lista - - Pulsante "↑ Sposta Su" per spostare verso l'alto - - Pulsante "↓ Sposta Giù" per spostare verso il basso - - Ordine salvato automaticamente su disco - - Gestione intelligente casi limite (cima/fondo) - - Logging dettagliato: `[MOVE UP]` / `[MOVE DOWN]` - - Permette di organizzare le aste per priorità o categoria -- ✅ **Navigazione con frecce direzionali**: Naviga tra le aste con i tasti Su e Giù - - Gestione esplicita in PreviewKeyDown con e.Handled = true - - Fix conflitto con GridSplitter (non modifica più altezza pannelli) - - Aggiornamento automatico pannello dettagli asta - - Scroll automatico per seguire la selezione - - Navigazione rapida senza usare il mouse -- ✅ **Riordinamento manuale aste**: Pulsanti per cambiare l'ordine delle aste nella lista - - Pulsanti "Sposta Su" e "Sposta Giù" (senza emoji per migliore compatibilità) - - Ordine salvato automaticamente su disco - - Gestione intelligente casi limite (cima/fondo) - - Logging dettagliato: `[MOVE UP]` / `[MOVE DOWN]` - - Permette di organizzare le aste per priorità o categoria -- ✅ **Validazione robusta campi numerici**: Impedisce inserimento caratteri non validi - - Solo numeri accettati in tutti i campi numerici dell'applicazione - - Campi interi: Anticipo (ms), Max Clicks, limiti log - - Campi decimali: Min/Max EUR con supporto sia punto che virgola - - Campo vuoto → ripristinato automaticamente a 0 (interi) o 0.00 (decimali) - - Blocco paste di testo non valido - - Normalizzazione automatica formato decimali (virgola → punto, 2 decimali) - - Nessun errore di parsing possibile - - 13 campi validati in tutta l'applicazione - - Helper riusabile: `Utilities\NumericTextBoxHelper.cs` - - **Nota**: Cancellare completamente un campo lo imposta a zero (modo rapido per resettare) diff --git a/Mimante/Documentation/DEBUG_COOKIE_DETECTION_LOGGING.md b/Mimante/Documentation/DEBUG_COOKIE_DETECTION_LOGGING.md deleted file mode 100644 index 2a7db7f..0000000 --- a/Mimante/Documentation/DEBUG_COOKIE_DETECTION_LOGGING.md +++ /dev/null @@ -1,261 +0,0 @@ -# ?? Debug: Cookie Detection Non Funziona - -## ?? Problema - -Dopo 60 secondi dall'avvio, rimane "Non connesso" anche se browser ha cookie valido. - -## ? Logging Dettagliato Aggiunto - -Ho aggiunto **logging completo** per diagnosticare il problema. Ora ogni step tracciato. - -### Punti di Log Aggiunti - -#### 1. InitializeWebView2() -```csharp -[DEBUG] Chiamata EnsureCoreWebView2Async... -[DEBUG] EnsureCoreWebView2Async completata -[DEBUG] CoreWebView2 disponibile, navigating... -[DEBUG] Notifica WebView pronta (TrySetResult) -[DEBUG] Inizio CheckAndImportCookieIfAvailable -``` - -#### 2. CheckAndImportCookieIfAvailable() -```csharp -[DEBUG] CheckAndImportCookieIfAvailable - inizio -[DEBUG] Delay 1000ms completato, chiamo GetCookieFromWebView -[DEBUG] GetCookieFromWebView ritornato, cookie presente: True/False -[DEBUG] Cookie gi presente in sessione corrente, skip import -[DEBUG] Nessun cookie trovato nel browser -``` - -#### 3. WaitForWebViewInitAsync() -```csharp -[DEBUG] WaitForWebViewInitAsync - inizio (timeout: 60s) -[DEBUG] WebView gi inizializzata, ritorno true immediato -[DEBUG] Creazione TaskCompletionSource -[DEBUG] WaitForWebViewInitAsync completato, result: true/false -``` - -#### 4. CheckBrowserCookieAfterWebViewReady() -```csharp -[DEBUG] CheckBrowserCookieAfterWebViewReady - avviato Task.Run -[DEBUG] Attesa inizializzazione WebView per verifica cookie... -[DEBUG] WaitForWebViewInitAsync completato, ready: true/false -[DEBUG] WebView pronta, procedo con verifica cookie -[DEBUG] Dispatcher.InvokeAsync - chiamo GetCookieFromWebView -[DEBUG] GetCookieFromWebView ritornato, cookie: PRESENTE/VUOTO -``` - ---- - -## ?? Istruzioni per Test e Debug - -### Step 1: Pulisci e Riavvia - -```powershell -# Pulisci sessione salvata -Remove-Item "$env:LOCALAPPDATA\AutoBidder\session.dat" -ErrorAction SilentlyContinue - -# Riavvia app -``` - -### Step 2: Osserva Log Completo - -Dopo l'avvio, il log dovrebbe mostrare **tutta la sequenza**: - -#### Sequenza Attesa (WebView OK + Cookie Trovato) - -``` -[17:30:53] [SESSION] Nessuna sessione salvata -[17:30:53] [BROWSER] Inizializzazione WebView2 in background... -[17:30:53] [DEBUG] CheckBrowserCookieAfterWebViewReady - avviato Task.Run -[17:30:53] [DEBUG] Attesa inizializzazione WebView per verifica cookie... -[17:30:53] [DEBUG] WaitForWebViewInitAsync - inizio (timeout: 60s) -[17:30:53] [DEBUG] Creazione TaskCompletionSource -[17:30:54] [DEBUG] Chiamata EnsureCoreWebView2Async... - -... [attesa 40-50 secondi] ... - -[17:31:43] [DEBUG] EnsureCoreWebView2Async completata -[17:31:43] [DEBUG] CoreWebView2 disponibile, navigating... -[17:31:43] [BROWSER] WebView2 inizializzato e pre-caricato -[17:31:43] [DEBUG] Notifica WebView pronta (TrySetResult) -[17:31:43] [DEBUG] Inizio CheckAndImportCookieIfAvailable -[17:31:43] [DEBUG] CheckAndImportCookieIfAvailable - inizio -[17:31:43] [DEBUG] WaitForWebViewInitAsync completato, result: true -[17:31:43] [DEBUG] WebView pronta, procedo con verifica cookie -[17:31:43] [DEBUG] Dispatcher.InvokeAsync - chiamo GetCookieFromWebView -[17:31:44] [DEBUG] Delay 1000ms completato, chiamo GetCookieFromWebView -[17:31:45] [DEBUG] GetCookieFromWebView ritornato, cookie presente: True -[17:31:45] [DEBUG] GetCookieFromWebView ritornato, cookie: PRESENTE -[17:31:45] [BROWSER] Cookie rilevato nel browser - importazione automatica... -[17:31:45] [DEBUG] Chiamata AutoImportCookieFromWebView -[17:31:45] [SESSION OK] Validata e attiva: username, XX puntate -[17:31:45] [DEBUG] AutoImportCookieFromWebView completata -``` - ---- - -### Step 3: Identifica Punto di Fallimento - -Confronta il tuo log con la sequenza sopra. **Dove si ferma?** - -#### Scenario A: WebView Non Si Inizializza ? - -**Log**: -``` -[17:30:53] [DEBUG] Chiamata EnsureCoreWebView2Async... -[17:31:53] [WARN] Timeout attesa inizializzazione WebView2 -``` - -**Causa**: `EnsureCoreWebView2Async` si blocca per 60 secondi e va in timeout - -**Soluzione**: -1. Verifica WebView2 Runtime installato: - ```powershell - Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" -Name pv - ``` -2. Se mancante, scarica da: https://developer.microsoft.com/en-us/microsoft-edge/webview2/ - ---- - -#### Scenario B: WebView OK ma Cookie Non Trovato ? - -**Log**: -``` -[17:31:43] [BROWSER] WebView2 inizializzato e pre-caricato -[17:31:45] [DEBUG] GetCookieFromWebView ritornato, cookie presente: False -[17:31:45] [DEBUG] Nessun cookie trovato nel browser -[17:31:45] [INFO] Nessun cookie nel browser -[17:31:45] [INFO] Per accedere: -``` - -**Causa**: WebView pronta ma nessun cookie `__stattrb` trovato - -**Verifica**: -1. Apri app -2. Click tab "Browser" -3. Vai su https://it.bidoo.com -4. Apri DevTools (F12) ? Application ? Cookies -5. Cerca cookie `__stattrb` - -**Soluzioni**: -- Se cookie assente: Fai login su Bidoo manualmente -- Se cookie presente ma non rilevato: Bug in `GetCookieFromWebView()`, devo fixare - ---- - -#### Scenario C: Cookie Trovato ma Importazione Fallisce ? - -**Log**: -``` -[17:31:45] [DEBUG] GetCookieFromWebView ritornato, cookie presente: True -[17:31:45] [BROWSER] Cookie rilevato - importazione automatica... -[17:31:45] [DEBUG] Chiamata AutoImportCookieFromWebView -[17:31:46] [SESSION ERROR] Cookie importato ma non valido: [errore] -``` - -**Causa**: Cookie trovato ma validazione fallita - -**Possibili Cause**: -1. Cookie scaduto -2. API Bidoo cambiata -3. Errore di rete - -**Soluzione**: Controlla log dettagliato errore, potrei dover fixare `ValidateAndActivateSessionAsync` - ---- - -#### Scenario D: Tutto OK ma UI Non Aggiorna ? - -**Log**: -``` -[17:31:45] [SESSION OK] Validata e attiva: username, XX puntate -[17:31:45] [DEBUG] AutoImportCookieFromWebView completata -``` - -**Ma sidebar ancora "Non connesso"** - -**Causa**: `SetUserBanner()` non chiamato o chiamato con parametri sbagliati - -**Soluzione**: Controlla se c' chiamata a `SetUserBanner()` dopo l'import - ---- - -### Step 4: Inviami il Log - -**Copia TUTTO il log** dal momento dell'avvio fino a 60 secondi dopo, e inviamelo. - -Cercher specificamente questi pattern: - -1. ? `[DEBUG] EnsureCoreWebView2Async completata` ? WebView init OK -2. ? `[DEBUG] GetCookieFromWebView ritornato, cookie presente: True` ? Cookie trovato -3. ? `[SESSION OK] Validata e attiva` ? Validazione OK -4. ? Qualsiasi `[ERROR]` o `[WARN]` ? Problema specifico - ---- - -## ?? Quick Fixes Comuni - -### Fix 1: WebView2 Runtime Mancante - -```powershell -# Download installer -$url = "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -Invoke-WebRequest -Uri $url -OutFile "MicrosoftEdgeWebview2Setup.exe" - -# Installa -.\MicrosoftEdgeWebview2Setup.exe /silent /install -``` - -### Fix 2: Cookie Browser Assente - -1. Apri app -2. Tab "Browser" -3. Vai su https://it.bidoo.com -4. Login manuale: - - Username: `sirbietole23` - - Password: [tua password] -5. Verifica login riuscito (homepage Bidoo) -6. Riavvia app - -### Fix 3: Firewall/Antivirus Blocca WebView - -Aggiungi eccezione per: -- `AutoBidder.exe` -- `msedgewebview2.exe` - ---- - -## ?? Checklist Diagnostica - -Prima di inviare log, verifica: - -- [ ] WebView2 Runtime installato? -- [ ] Browser ha cookie `__stattrb`? -- [ ] Sei loggato su Bidoo nel browser integrato? -- [ ] Firewall/antivirus non blocca app? -- [ ] Hai riavviato app dopo aver fatto login? -- [ ] Log mostra "[DEBUG]" lines? (se no, build non aggiornata) - ---- - -## ?? Prossimi Passi - -1. ? Avvia app con logging dettagliato -2. ? Aspetta 60 secondi -3. ? Copia TUTTO il log -4. ? Inviami il log completo -5. ? Identificher il punto esatto di fallimento -6. ? Fornir fix mirato - ---- - -**File Modificati**: -- `Core\MainWindow.WebView.cs` - Logging dettagliato init + cookie check -- `Core\MainWindow.UserInfo.cs` - Logging dettagliato attesa WebView - -**Build**: ? Compilazione riuscita -**Pronto per Debug**: ? S - -**Azione Richiesta**: Riavvia app e inviami log completo dei primi 60 secondi diff --git a/Mimante/Documentation/DIAGNOSTICA_DATI_UTENTE.md b/Mimante/Documentation/DIAGNOSTICA_DATI_UTENTE.md deleted file mode 100644 index 062c0d4..0000000 --- a/Mimante/Documentation/DIAGNOSTICA_DATI_UTENTE.md +++ /dev/null @@ -1,148 +0,0 @@ -# ?? Diagnostica Recupero Dati Utente - -## Cosa cambiato - -**NON ho modificato** la procedura di recupero dati utente nelle ultime modifiche. - -Il codice esistente lo stesso di prima, ma ho aggiunto **logging dettagliato** per capire cosa sta andando storto. - -## Come funziona il recupero dati - -Il sistema usa **2 strategie parallele** (ridondanza per affidabilit): - -### 1?? **METODO PRINCIPALE**: HTML Scraping (Timer 5 minuti) -- **URL**: `https://it.bidoo.com/bids_history.php` -- **Estrae**: Username, Puntate residue -- **Pattern cercati**: - ```regex - ]*>([^<]+) # Username - ]*>(\d+) # Puntate - ``` - -### 2?? **METODO FALLBACK**: API (Timer 10 minuti) -- **URL**: `https://it.bidoo.com/buy_bids.php` -- **Estrae**: Username, Email, ID, Telefono, Puntate, Credito Shop -- **Pattern cercati**: - ```regex - BidooCnf.userObj.username = 'username'; - BidooCnf.userObj.email = 'email@example.com'; - BidooCnf.userObj.id = '123456'; - 206 - 15.00 - ``` - -## ?? Possibili Cause dell'Errore - -### 1. **Cookie Scaduto o Non Valido** -Il cookie `__stattrb` potrebbe essere scaduto o non pi valido. - -**Come verificare**: -1. Apri il browser e vai su `https://it.bidoo.com` -2. Apri DevTools (F12) ? Applicazione ? Cookie -3. Controlla se il cookie `__stattrb` esiste -4. Copia il nuovo valore e inseriscilo nelle Impostazioni - -### 2. **Sito Bidoo ha Cambiato Struttura HTML** -Bidoo potrebbe aver modificato la struttura delle pagine. - -**Come verificare**: -1. Guarda i log dettagliati (ora disponibili dopo le modifiche) -2. Cerca messaggi tipo: - - `[USER HTML ERROR] Username NON trovato nell'HTML` - - `[USER HTML DEBUG] Snippet HTML: ...` -3. Confronta lo snippet con i pattern regex - -### 3. **Problema di Rete o Firewall** -Il server potrebbe bloccare le richieste. - -**Come verificare**: -1. Cerca nei log: - - `[USER HTML ERROR] HTTP 403` ? Bloccato - - `[USER HTML ERROR] HTTP 401` ? Non autorizzato - - `[USER HTML ERROR] HTTP 500` ? Errore server - -### 4. **Redirect o Risposta Non HTML** -Il server potrebbe fare redirect o rispondere con JSON/testo. - -**Come verificare**: -1. Cerca nei log: - - `[USER HTML ERROR] Risposta non contiene HTML valido` - - `Body length: <100` ? Risposta troppo corta - -## ?? Nuovo Logging Disponibile - -Ho aggiunto logging **molto dettagliato** per diagnosticare: - -### Log nel Console Output -``` -[INFO] Tentativo recupero dati utente da HTML... -[USER HTML REQUEST] GET https://it.bidoo.com/bids_history.php -[USER HTML RESPONSE] Status: 200 OK -[USER HTML RESPONSE] Body length: 45233 chars -[USER HTML PARSED] Username trovato: sirbietole23 -[USER HTML PARSED] Puntate residue trovate: 206 -[USER HTML SUCCESS] Dati estratti: sirbietole23, 206 puntate -[OK] Dati utente aggiornati via HTML: sirbietole23, 206 puntate -``` - -### Se Fallisce -``` -[USER HTML RESPONSE] Status: 200 OK -[USER HTML RESPONSE] Body length: 45233 chars -[USER HTML ERROR] Username NON trovato nell'HTML -[USER HTML DEBUG] Snippet HTML: ... -[USER HTML ERROR] Puntate residue NON trovate nell'HTML -[USER HTML FAILED] Impossibile estrarre dati utente dall'HTML -[WARN] HTML scraping non ha restituito dati validi - verifica cookie nelle Impostazioni -``` - -## ?? Come Risolvere - -### Soluzione 1: Aggiorna Cookie -1. Vai su **Impostazioni** -2. Clicca **Configura Sessione** -3. Inserisci il cookie `__stattrb` aggiornato dal browser -4. Clicca **Salva** -5. Controlla i log - -### Soluzione 2: Verifica Log Dettagliati -1. **Riavvia l'applicazione** -2. Aspetta 5-10 secondi (timer automatico parte) -3. Guarda il **Log Principale** in basso -4. Cerca i messaggi `[USER HTML...]` e `[USER INFO...]` -5. Inviami lo snippet HTML se vedi errori - -### Soluzione 3: Test Manuale -1. Apri browser e vai su `https://it.bidoo.com/bids_history.php` -2. Verifica se sei loggato (vedi username in alto) -3. Se non sei loggato ? Cookie scaduto -4. Se sei loggato ? Mandami screenshot della pagina - -## ?? Test di Verifica - -Dopo aver seguito le soluzioni, verifica che nei log appaia: - -? **SUCCESSO**: -``` -[OK] Dati utente aggiornati via HTML: tuousername, X puntate -``` - -? **ANCORA ERRORE**: -``` -[ERROR] Impossibile aggiornare info utente - verifica cookie nelle Impostazioni -``` - -Se ancora non funziona, **inviami i log completi** dal primo avvio fino all'errore. - -## ?? Supporto - -Se il problema persiste: -1. Copia **tutti i log** dal pannello principale -2. Invia screenshot della **scheda Impostazioni** (censura cookie se vuoi) -3. Dimmi se hai aggiornato il cookie recentemente -4. Dimmi se funzionava prima (quando?) - ---- - -**Data**: 2025 -**Versione**: 4.0+ diff --git a/Mimante/Documentation/FEATURE_AUCTION_BUTTONS_REORGANIZED.md b/Mimante/Documentation/FEATURE_AUCTION_BUTTONS_REORGANIZED.md deleted file mode 100644 index 177af2e..0000000 --- a/Mimante/Documentation/FEATURE_AUCTION_BUTTONS_REORGANIZED.md +++ /dev/null @@ -1,437 +0,0 @@ -# ? Feature: Pulsanti Apertura Asta Riorganizzati e Funzionanti - -## ?? Obiettivo - -Riorganizzare i pulsanti per l'asta selezionata e aggiungere funzionalit complete per: -1. **Aprire l'asta nel browser interno** (integrato nell'applicazione) -2. **Aprire l'asta nel browser esterno** (browser predefinito di sistema) -3. **Copiare URL** negli appunti -4. **Esportare asta** (singola) - ---- - -## ?? Problema Prima - -- ? **Un solo pulsante "Apri"** senza funzionalit -- ? **Nessun modo** di aprire nel browser interno -- ? **Nessun modo** di aprire nel browser esterno -- ? **Layout confuso** con pulsanti non ben organizzati - ---- - -## ? Soluzione Implementata - -### 1?? Nuova Organizzazione Pulsanti - -**Layout Precedente**: -``` -[Apri] [Copia] [Esporta] -``` - -**Nuovo Layout (2x2)**: -``` -?????????????????????????????????????????? -? ?? Browser Interno | ?? Browser Esterno ? -?????????????????????????????????????????? -? ?? Copia URL | ?? Esporta ? -?????????????????????????????????????????? -``` - -### 2?? Pulsanti Implementati - -#### ?? Browser Interno -- **Testo**: "?? Browser Interno" -- **Colore**: `#007ACC` (Blu Azure) -- **Tooltip**: "Apri asta nel browser integrato" -- **Funzionalit**: - - Passa alla tab "Browser" - - Carica l'asta nel WebView2 integrato - - Log: `[BROWSER] Apertura asta nel browser interno` - -#### ?? Browser Esterno -- **Testo**: "?? Browser Esterno" -- **Colore**: `#0078D7` (Blu pi chiaro) -- **Tooltip**: "Apri asta nel browser predefinito di sistema" -- **Funzionalit**: - - Apre l'URL nel browser predefinito del sistema - - Utilizza `Process.Start` con `UseShellExecute = true` - - Log: `[BROWSER] Apertura asta nel browser esterno` - -#### ?? Copia URL -- **Testo**: "?? Copia URL" -- **Colore**: `#9B4F96` (Viola) -- **Tooltip**: "Copia URL negli appunti" -- **Funzionalit**: (gi esistente, riorganizzato) - - Copia l'URL negli appunti - - Log: `URL copiato negli appunti` - -#### ?? Esporta -- **Testo**: "?? Esporta" -- **Colore**: `#106EBE` (Blu scuro) -- **Tooltip**: "Esporta dati asta" -- **Funzionalit**: - - Mostra messaggio "Funzionalit in sviluppo" - - Log: `[INFO] Richiesto export singolo` - ---- - -## ?? File Modificati - -### 1. `Controls/AuctionMonitorControl.xaml` - -**Modifiche**: -- Rimosso layout a 3 colonne `UniformGrid Columns="3"` -- Aggiunto `Grid 2x2` per layout organizzato -- Creati 4 pulsanti ben definiti con emoji e tooltip - -**Prima**: -```xaml - - - - - - -``` - ---- - -#### 2. `MainWindow.xaml` -Sidebar sempre visibile, mostra "Non connesso" quando disconnesso: - -```xaml - - ? Nascosta - ... - - - - ? Sempre visibile - - - - - - - - - - - -``` - ---- - -#### 3. `Core\MainWindow.UserInfo.cs` -Aggiornato `SetUserBanner()` per gestire sidebar: - -```csharp -private void SetUserBanner(string username, int? remainingBids) -{ - if (!string.IsNullOrEmpty(username)) - { - // === CONNESSO === - - // Banner: Puntate + Credito - RemainingBidsText.Text = remainingBids?.ToString() ?? "0"; - AuctionMonitor.ShopCreditText.Text = $"EUR {session.ShopCredit:F2}"; - - // Sidebar: Username Verde - SidebarUsernameText.Text = username; - SidebarUsernameText.Foreground = Verde; - SidebarUsernameText.FontWeight = Bold; - - // Sidebar: Mostra dettagli (ID + Email) - SidebarUserDetailsPanel.Visibility = Visible; - SidebarUserIdText.Text = $"ID: {session.UserId}"; - SidebarUserEmailText.Text = session.Email; - } - else - { - // === NON CONNESSO === - - // Banner: Reset - RemainingBidsText.Text = "0"; - AuctionMonitor.ShopCreditText.Text = "EUR 0.00"; - - // Sidebar: "Non connesso" Rosso - SidebarUsernameText.Text = "Non connesso"; - SidebarUsernameText.Foreground = RossoChiaro; - SidebarUsernameText.FontWeight = Bold; - - // Sidebar: Nascondi dettagli - SidebarUserDetailsPanel.Visibility = Collapsed; - } -} -``` - -**Rimosso**: Metodo `UpdateConnectionStatus()` obsoleto - ---- - -#### 4. `Core\MainWindow.ConnectionHandlers.cs` -Aggiunto handler click per username sidebar: - -```csharp -/// -/// Handler per il click sul nome utente nella sidebar -/// -private void SidebarUsername_Click(object sender, MouseButtonEventArgs e) -{ - // Riusa la logica del pulsante connessione - ConnectionStatusButton_Click(sender, new RoutedEventArgs()); -} -``` - -**Comportamento**: -- Click su "Non connesso" ? Apre tab Browser per login -- Click su Username ? Mostra opzioni disconnetti - ---- - -#### 5. `Core\MainWindow.WebView.cs` -WebView2 inizializzata subito all'avvio: - -```csharp -/// -/// Inizializza WebView2 in background all'avvio -/// -private async void InitializeWebView2() -{ - Log("[BROWSER] Inizializzazione WebView2 in background...", LogLevel.Info); - - // ? FIX: Aspetta che CoreWebView2 sia inizializzato SINCRONAMENTE - await EmbeddedWebView.EnsureCoreWebView2Async(null); - - if (EmbeddedWebView.CoreWebView2 != null) - { - _isWebViewInitialized = true; - - // Pre-carica Bidoo in background - EmbeddedWebView.CoreWebView2.Navigate("https://it.bidoo.com"); - - Log("[BROWSER] ? WebView2 inizializzato e pre-caricato", LogLevel.Success); - - // Registra evento per auto-login - EmbeddedWebView.CoreWebView2.NavigationCompleted += OnWebViewNavigationCompleted; - } -} -``` - -**Chiamato da**: `MainWindow()` constructor - -**Effetto**: -- Browser pre-caricato in background -- Pronto immediatamente quando utente apre tab -- Cookie extraction funziona subito al login - ---- - -## ?? Comportamento Finale - -### Scenario 1: Primo Avvio (Non Connesso) - -**Sidebar**: -``` -??????????????????????? -? Non connesso ? ? Rosso chiaro, clickable -??????????????????????? -``` - -**Banner**: -``` -Puntate: 0 Credito: EUR 0.00 -``` - -**Log**: -``` -[SESSION] Nessuna sessione salvata -[INFO] Per accedere: -[INFO] 1. Click su 'Non connesso' nella sidebar -[INFO] 2. Si aprir la scheda Browser -[INFO] 3. Fai login su Bidoo -[INFO] 4. La connessione sar automatica -[BROWSER] Inizializzazione WebView2 in background... -[BROWSER] ? WebView2 inizializzato e pre-caricato -``` - ---- - -### Scenario 2: Dopo Login Automatico - -**Sidebar**: -``` -??????????????????????? -? sirbietole23 ? ? Verde, grassetto, clickable -? ID: 6707664 ? -? email@email.com ? -??????????????????????? -``` - -**Banner**: -``` -Puntate: 50 (20) Credito: EUR 15.00 -``` - -**Log**: -``` -[BROWSER] Login rilevato - importazione automatica cookie... -[BROWSER] ? Connessione automatica completata -[SESSION] ? Sessione valida - sirbietole23 (50 puntate) -``` - ---- - -### Scenario 3: Click su Username quando Connesso - -**MessageBox**: -``` -???????????????????????????????????? -? Gestione Connessione ? -???????????????????????????????????? -? Connesso come: sirbietole23 ? -? Puntate residue: 50 ? -? Credito Shop: EUR 15.00 ? -? ? -? Vuoi disconnettere e accedere ? -? con un altro account? ? -? ? -? [ S ] [ No ] ? -???????????????????????????????????? -``` - -**Se "S"**: -- SessionService.ClearSession() -- Sidebar mostra "Non connesso" rosso -- Banner reset a 0 - ---- - -### Scenario 4: Click su "Non connesso" - -**MessageBox**: -``` -???????????????????????????????????? -? Accedi a Bidoo ? -???????????????????????????????????? -? Per accedere: ? -? ? -? 1. Fai login su Bidoo nella ? -? scheda Browser ? -? 2. La connessione sar automatica? -? ? -? Apertura scheda Browser... ? -? ? -? [ OK ] ? -???????????????????????????????????? -``` - -**Effetto**: -- Tab Browser selezionato automaticamente -- Browser gi caricato (pre-init background) -- Pronto per login immediato - ---- - -## ?? File Modificati - -| File | Modifiche | -|------|-----------| -| `Controls\AuctionMonitorControl.xaml` | Rimosso pulsante ConnectionStatus | -| `MainWindow.xaml` | Sidebar sempre visibile + handler click | -| `MainWindow.xaml.cs` | Rimossi properties ConnectionStatus obsoleti | -| `Core\MainWindow.UserInfo.cs` | `SetUserBanner()` gestisce sidebar, rimosso `UpdateConnectionStatus()` | -| `Core\MainWindow.ConnectionHandlers.cs` | Aggiunto `SidebarUsername_Click()`, rimosso `UpdateConnectionStatus()` | -| `Core\MainWindow.WebView.cs` | Init sincrona WebView2 in background | - -**Totale**: 6 file modificati - ---- - -## ? Test di Verifica - -### Test 1: Sidebar Sempre Visibile ? - -**Steps**: -1. Avvia app (prima volta, senza cookie) -2. Verifica sidebar mostra "Non connesso" in rosso -3. Fai login tramite browser -4. Verifica sidebar mostra username in verde -5. Disconnetti -6. Verifica sidebar torna a "Non connesso" rosso - -**Risultato**: ? Sidebar sempre visibile, cambia solo testo/colore - ---- - -### Test 2: WebView Init Background ? - -**Steps**: -1. Avvia app -2. Controlla log per "[BROWSER] Inizializzazione WebView2..." -3. Aspetta 2-3 secondi -4. Controlla log per "[BROWSER] ? WebView2 inizializzato" -5. Click su tab Browser -6. Verifica Bidoo gi caricato (non loader bianco) - -**Risultato**: ? Browser pre-caricato in background - ---- - -### Test 3: Click Sidebar ? - -**Steps**: -1. Avvia app senza cookie -2. Click su "Non connesso" in sidebar -3. Verifica tab Browser si apre -4. Fai login su Bidoo -5. Verifica auto-login funziona -6. Click su username in sidebar -7. Verifica MessageBox con opzioni - -**Risultato**: ? Click sidebar funziona come previsto - ---- - -## ?? Confronto Prima/Dopo - -### Indicatore Connessione - -| Aspetto | Prima | Dopo | -|---------|-------|------| -| **Posizione** | Banner + Sidebar | Solo Sidebar ? | -| **Visibilit Non Connesso** | Nascosto | Sempre visibile ? | -| **Colore Non Connesso** | - | Rosso chiaro (#FF5252) ? | -| **Colore Connesso** | Verde | Verde (#00D800) ? | -| **Clickable** | Solo banner | Sidebar username ? | -| **Dettagli (ID/Email)** | Sempre visibili | Nascosti se disconnesso ? | - -### WebView Init - -| Aspetto | Prima | Dopo | -|---------|-------|------| -| **Quando Init** | Click tab Browser | Avvio app ? | -| **Tempo init** | 2-3 sec dopo click | Background asincrono ? | -| **Pronta quando aperta** | No (loader bianco) | S (gi caricata) ? | -| **Auto-login** | Non funzionava subito | Funziona subito ? | -| **Log visible** | No | S con progress ? | - -### User Experience - -| Scenario | Prima | Dopo | -|----------|-------|------| -| **Capire se connesso** | Ambiguo | Chiaro (sidebar) ? | -| **Accedere** | Non intuitivo | Click su "Non connesso" ? | -| **Disconnettere** | Nascosto in impostazioni | Click su username ? | -| **Browser pronto** | Attesa 2-3 sec | Immediato ? | - ---- - -## ?? Risultati - -### ? UI Pulita -- Username mostrato una sola volta (sidebar) -- Banner compatto con solo dati essenziali -- Sidebar sempre visibile = stato sempre chiaro - -### ? UX Migliorata -- Stato connessione immediatamente visibile -- Click su sidebar per azioni rapide -- Browser pre-caricato = esperienza fluida - -### ? Codice Pulito -- Rimosso codice duplicato (UpdateConnectionStatus) -- Logica connessione centralizzata in SetUserBanner -- WebView init ben separata - ---- - -**Data Fix**: 2025 -**Versione**: 5.9+ -**Issue 1**: Username duplicato in banner e sidebar -**Issue 2**: Sidebar nascosta quando disconnesso -**Issue 3**: WebView init solo al click tab -**Status**: ? TUTTI RISOLTI - -## ?? Riferimenti - -- `Controls\AuctionMonitorControl.xaml` - Banner header -- `MainWindow.xaml` - Sidebar layout -- `Core\MainWindow.UserInfo.cs` - SetUserBanner() -- `Core\MainWindow.ConnectionHandlers.cs` - Click handlers -- `Core\MainWindow.WebView.cs` - WebView init diff --git a/Mimante/Documentation/FIX_SINGLE_AUCTION_START.md b/Mimante/Documentation/FIX_SINGLE_AUCTION_START.md deleted file mode 100644 index e2c0a0c..0000000 --- a/Mimante/Documentation/FIX_SINGLE_AUCTION_START.md +++ /dev/null @@ -1,234 +0,0 @@ -# ?? Fix Avvio Singola Asta dalla Griglia - -## Problema Rilevato - -Quando si cliccava il pulsante **"Avvia"** su una singola asta nella griglia, l'asta **non veniva monitorata** a meno che prima non si fosse cliccato **"Avvia Tutti"**. - -## Causa del Problema - -Il sistema di monitoraggio aveva una **dipendenza rigida** sul flag `_isAutomationActive`: - -1. ? Clic su "Avvia Tutti" ? Avvia `AuctionMonitor.Start()` + imposta `IsActive = true` su tutte le aste -2. ? Clic su "Avvia" (singola asta) ? Imposta solo `IsActive = true` MA **non avvia** `AuctionMonitor.Start()` -3. ? Risultato: L'asta era marcata come attiva, ma il loop di monitoraggio **non era in esecuzione** - -### Codice Problematico (Prima) - -```csharp -private void ExecuteGridStart(AuctionViewModel? vm) -{ - if (vm == null) return; - vm.IsActive = true; - vm.IsPaused = false; - Log($"[START] Asta avviata: {vm.Name}"); - UpdateGlobalControlButtons(); -} -``` - -**Mancava**: Avvio del `AuctionMonitor` se non gi attivo. - -## Soluzione Implementata - -### ? 1. Auto-Start del Monitoraggio - -Ora, quando si avvia una singola asta, **il monitoraggio viene avviato automaticamente** se non gi attivo: - -```csharp -private void ExecuteGridStart(AuctionViewModel? vm) -{ - if (vm == null) return; - - // Attiva l'asta - vm.IsActive = true; - vm.IsPaused = false; - - // Se il monitoraggio globale non attivo, avvialo automaticamente - if (!_isAutomationActive) - { - _auctionMonitor.Start(); - _isAutomationActive = true; - Log($"[AUTO-START] Monitoraggio avviato automaticamente per asta: {vm.Name}", LogLevel.Info); - } - else - { - Log($"[START] Asta avviata: {vm.Name}", LogLevel.Info); - } - - UpdateGlobalControlButtons(); -} -``` - -### ? 2. Auto-Stop del Monitoraggio - -Quando si ferma l'ultima asta attiva, **il monitoraggio viene fermato automaticamente**: - -```csharp -private void ExecuteGridStop(AuctionViewModel? vm) -{ - if (vm == null) return; - vm.IsActive = false; - - // Se tutte le aste sono fermate, ferma anche il monitoraggio globale - bool hasActiveAuctions = _auctionViewModels.Any(a => a.IsActive); - if (!hasActiveAuctions && _isAutomationActive) - { - _auctionMonitor.Stop(); - _isAutomationActive = false; - Log($"[AUTO-STOP] Monitoraggio fermato: nessuna asta attiva", LogLevel.Info); - } - else - { - Log($"[STOP] Asta fermata: {vm.Name}", LogLevel.Info); - } - - UpdateGlobalControlButtons(); -} -``` - -### ? 3. Migliorato Logging - -Aggiunto logging dettagliato per capire quando il monitoraggio viene avviato/fermato automaticamente: - -- `[AUTO-START] Monitoraggio avviato automaticamente per asta: Nome` -- `[AUTO-STOP] Monitoraggio fermato: nessuna asta attiva` -- `[START] Asta avviata: Nome` (se monitoraggio gi attivo) -- `[STOP] Asta fermata: Nome` (se ci sono altre aste attive) - -### ? 4. Coerenza con Pulsanti Globali - -I pulsanti globali ora sono coerenti con il nuovo comportamento: - -- **"Avvia Tutti"**: Avvia monitoraggio + attiva tutte le aste -- **"Ferma Tutti"**: Ferma monitoraggio + disattiva tutte le aste -- **"Pausa Tutti"**: Mette in pausa tutte le aste attive (monitoraggio rimane attivo) - -## Comportamento Atteso - -### ? Scenario 1: Avvio Singola Asta (Monitoraggio Fermo) - -1. Nessuna asta attiva -2. Clic su "Avvia" su Asta A -3. ? Monitoraggio si avvia automaticamente -4. ? Asta A inizia ad essere monitorata -5. ? Log: `[AUTO-START] Monitoraggio avviato automaticamente per asta: Asta A` - -### ? Scenario 2: Avvio Singola Asta (Monitoraggio Gi Attivo) - -1. Asta A gi attiva -2. Clic su "Avvia" su Asta B -3. ? Monitoraggio gi attivo (non viene riavviato) -4. ? Asta B inizia ad essere monitorata -5. ? Log: `[START] Asta avviata: Asta B` - -### ? Scenario 3: Stop Ultima Asta - -1. Solo Asta A attiva -2. Clic su "Ferma" su Asta A -3. ? Asta A viene fermata -4. ? Monitoraggio si ferma automaticamente (nessuna asta attiva) -5. ? Log: `[AUTO-STOP] Monitoraggio fermato: nessuna asta attiva` - -### ? Scenario 4: Stop Asta (Altre Attive) - -1. Asta A e Asta B attive -2. Clic su "Ferma" su Asta A -3. ? Asta A viene fermata -4. ? Monitoraggio rimane attivo (Asta B ancora attiva) -5. ? Log: `[STOP] Asta fermata: Asta A` - -### ? Scenario 5: Avvia Tutti - -1. Asta A e Asta B ferme -2. Clic su "Avvia Tutti" -3. ? Monitoraggio si avvia -4. ? Tutte le aste vengono attivate -5. ? Log: `[START] Monitoraggio avviato!` + `[START ALL] Tutte le aste avviate/riprese` - -### ? Scenario 6: Ferma Tutti - -1. Alcune aste attive -2. Clic su "Ferma Tutti" -3. ? Tutte le aste vengono fermate -4. ? Monitoraggio si ferma -5. ? Log: `[STOP ALL] Monitoraggio fermato e tutte le aste arrestate` - -## Vantaggi della Soluzione - -### ?? 1. Maggiore Flessibilit -- Puoi avviare solo le aste che ti interessano -- Non serve pi avviare tutte le aste per monitorarne una - -### ?? 2. Risparmio Risorse -- Il monitoraggio si ferma automaticamente quando non serve -- Polling solo sulle aste effettivamente attive - -### ?? 3. UX Migliorata -- Comportamento pi intuitivo -- Non serve capire la differenza tra "Avvia Tutti" e "Avvia" singolo - -### ?? 4. Logging Chiaro -- Si vede esattamente quando il monitoraggio parte/si ferma -- Distingue tra start manuale e automatico - -## File Modificati - -1. ? `Core\MainWindow.Commands.cs` - - Aggiunto auto-start in `ExecuteGridStart` - - Aggiunto auto-stop in `ExecuteGridStop` - - Aggiunta importazione `System.Linq` e `AutoBidder.Utilities` - - Migliorato logging con `LogLevel` - -2. ? `Core\MainWindow.ButtonHandlers.cs` - - Migliorato logging in `StartButton_Click` - - Migliorato logging in `StopButton_Click` - - Migliorato logging in `PauseAllButton_Click` - -## Note Tecniche - -### Perch Auto-Start Sicuro? - -1. **Idempotente**: `AuctionMonitor.Start()` controlla se gi attivo -2. **Thread-safe**: Il lock interno previene race conditions -3. **Logging**: Si vede esattamente cosa succede - -```csharp -public void Start() -{ - if (_monitoringTask != null && !_monitoringTask.IsCompleted) - { - OnLog?.Invoke("[WARN] Monitoraggio gia' attivo"); - return; // Non fa nulla se gi attivo - } - // ... -} -``` - -### Perch Auto-Stop Sicuro? - -1. **Controlla tutte le aste**: Verifica se ci sono altre aste attive prima di fermare -2. **Non forza**: Se ci sono altre aste attive, non ferma il monitoraggio -3. **Graceful**: Usa `Stop()` che fa cleanup corretto - -## Test di Verifica - -- [x] Avviare singola asta da griglia (monitoraggio fermo) -- [x] Avviare seconda asta (monitoraggio gi attivo) -- [x] Fermare asta (altre attive) ? Monitoraggio continua -- [x] Fermare ultima asta ? Monitoraggio si ferma -- [x] "Avvia Tutti" continua a funzionare -- [x] "Ferma Tutti" continua a funzionare -- [x] "Pausa Tutti" continua a funzionare -- [x] Pulsanti di griglia abilitati/disabilitati correttamente -- [x] Log mostra AUTO-START/AUTO-STOP - ---- - -**Data Fix**: 2025 -**Versione**: 4.0+ -**Issue**: Pulsante "Avvia" singolo non funzionava senza "Avvia Tutti" -**Status**: ? RISOLTO - -## Riepilogo - -Prima: **Dovevi cliccare "Avvia Tutti" per monitorare anche una sola asta** -Dopo: **Clicchi "Avvia" su un'asta e parte automaticamente il monitoraggio** ?? diff --git a/Mimante/Documentation/FIX_SKIP_BID_IF_WINNER.md b/Mimante/Documentation/FIX_SKIP_BID_IF_WINNER.md deleted file mode 100644 index c0d0d1e..0000000 --- a/Mimante/Documentation/FIX_SKIP_BID_IF_WINNER.md +++ /dev/null @@ -1,341 +0,0 @@ -# ?? Fix Puntata su Asta Gi Vinta - -## Problema Rilevato - -Il sistema tentava di **puntare anche quando l'utente era gi il vincitore corrente** dell'asta, causando: - -1. ? **Errori inutili** - La puntata falliva con messaggio "Asta chiusa" o simile -2. ? **Spreco risorse** - Chiamate API non necessarie -3. ? **Logging confuso** - Messaggi di errore quando tutto andava bene -4. ? **Puntate perse** - Tentativo di puntata quando non aveva senso - -## Causa del Problema - -Il metodo `ShouldBid()` non controllava se l'utente era gi il vincitore corrente prima di decidere di puntare. - -La logica era: -```csharp -// ? PRIMA - Non controllava IsMyBid -private bool ShouldBid(AuctionInfo auction, AuctionState state) -{ - // Controlli prezzo, reset count, max clicks, cooldown... - // MA mancava: controllo se sono gi vincitore! - - return true; -} -``` - -Scenario problematico: -1. ? Utente punta alle 10:00:00 e vince -2. ? Timer riparte da 20 secondi -3. ? Timer scende a 0.3 secondi (dentro finestra anticipo) -4. ? Sistema cerca di puntare di nuovo -5. ? Server risponde: "Asta chiusa" o errore simile -6. ? Log mostra errore anche se l'utente ha gi vinto! - -## Soluzione Implementata - -### ? 1. Controllo `IsMyBid` in `ShouldBid()` - -Aggiunto controllo come **prima condizione**: - -```csharp -private bool ShouldBid(AuctionInfo auction, AuctionState state) -{ - // ? NUOVO: Non puntare se sono gi il vincitore corrente - if (state.IsMyBid) - { - // Sono gi io l'ultimo ad aver puntato, non serve puntare di nuovo - return false; - } - - // ... altri controlli ... - - return true; -} -``` - -### ? 2. Logging Chiaro in `ExecuteBidStrategy()` - -Aggiunto messaggio informativo quando si evita la puntata: - -```csharp -private async Task ExecuteBidStrategy(...) -{ - if (timerMs <= auction.BidBeforeDeadlineMs) - { - auction.AddLog($"[STRATEGIA] Finestra di puntata raggiunta: {timerMs:F0}ms <= {auction.BidBeforeDeadlineMs}ms"); - - // ? NUOVO: Log quando skippo perch sono gi vincitore - if (state.IsMyBid) - { - auction.AddLog($"[STRATEGIA] SKIP: Sono gi il vincitore corrente (ultimo bidder: {state.LastBidder})"); - return; - } - - // ... continua con puntata ... - } -} -``` - -### ? 3. Come Funziona `IsMyBid` - -Il flag `state.IsMyBid` viene calcolato in `BidooApiClient.ParsePollingResponse()`: - -```csharp -state.IsMyBid = !string.IsNullOrEmpty(_session.Username) && - state.LastBidder.Equals(_session.Username, StringComparison.OrdinalIgnoreCase); -``` - -Confronta il `LastBidder` dall'API con lo `Username` della sessione (case-insensitive). - -## Comportamento Atteso - -### ? Scenario 1: Utente NON Vincitore (Deve Puntare) - -``` -Timer: 0.3s (dentro finestra 0.5s) -Ultimo bidder: "altroUtente123" -IsMyBid: false - -[STRATEGIA] Finestra di puntata raggiunta: 300ms <= 500ms -[STRATEGIA] Eseguo puntata... -[BID OK] Latenza: 45ms -> EUR 1.50 -``` - -**Risultato**: ? Punta correttamente - -### ? Scenario 2: Utente GI Vincitore (SKIP Puntata) - -``` -Timer: 0.3s (dentro finestra 0.5s) -Ultimo bidder: "miousername" -IsMyBid: true - -[STRATEGIA] Finestra di puntata raggiunta: 300ms <= 500ms -[STRATEGIA] SKIP: Sono gi il vincitore corrente (ultimo bidder: miousername) -``` - -**Risultato**: ? NON punta (evita errore) - -### ? Scenario 3: Altro Utente Supera - -``` -t=10s: Io puntp -> IsMyBid = true -t=8s: [STRATEGIA] SKIP: Sono gi vincitore -t=6s: [STRATEGIA] SKIP: Sono gi vincitore -t=4s: altroUtente punta -> IsMyBid = false -t=0.3s: [STRATEGIA] Finestra raggiunta -t=0.3s: [BID OK] Riprendo il controllo! -``` - -**Risultato**: ? Punta solo quando necessario - -## Vantaggi della Soluzione - -### ?? 1. Nessun Errore Inutile -- ? **Prima**: "Asta chiusa" quando eri gi vincitore -- ? **Dopo**: Nessun errore, log chiaro - -### ?? 2. Risparmio Risorse -- ? **Prima**: Chiamata API inutile quando gi vincitore -- ? **Dopo**: Skip immediato, nessuna chiamata - -### ?? 3. Logging Trasparente -``` -? [STRATEGIA] SKIP: Sono gi il vincitore corrente -``` -Invece di: -``` -? [BID FAIL] Asta chiusa -``` - -### ?? 4. Strategia Ottimizzata -- Punta **solo** quando serve riprendersi l'asta -- Non spreca puntate quando sei gi vincitore - -## Test Scenario - -### Test 1: Vincitore Corrente (Non Deve Puntare) - -**Setup**: -- Imposta Anticipo = 500ms -- Aggiungi asta X -- Punta manualmente -- Sei il vincitore (LastBidder = "tuousername") - -**Verifica**: -1. ? Timer scende da 20s a 0.4s -2. ? Log: `[STRATEGIA] Finestra di puntata raggiunta: 400ms <= 500ms` -3. ? Log: `[STRATEGIA] SKIP: Sono gi il vincitore corrente` -4. ? **Nessuna puntata** effettuata -5. ? **Nessun errore** mostrato - -### Test 2: Altro Utente Supera (Deve Puntare) - -**Setup**: -- Sei il vincitore -- Altro utente punta e diventa vincitore -- Timer scende a 0.3s - -**Verifica**: -1. ? Log: `[STRATEGIA] Finestra di puntata raggiunta: 300ms <= 500ms` -2. ? **Nessun SKIP** (non sei pi vincitore) -3. ? Log: `[BID OK] Latenza: XXms` -4. ? Puntata **effettuata correttamente** - -### Test 3: Alternanza Vincitori - -**Setup**: -- Tu: punta -- Altro: punta -- Tu: riprende controllo -- Altro: riprende controllo - -**Verifica**: -- ? SKIP solo quando sei vincitore -- ? Punta solo quando NON sei vincitore -- ? Log chiaro per ogni decisione - -## File Modificati - -### 1. ? `Services\AuctionMonitor.cs` - -**Modifiche**: -- `ShouldBid()`: Aggiunto controllo `state.IsMyBid` come prima condizione -- `ExecuteBidStrategy()`: Aggiunto logging quando si skippa per vincitore corrente - -**Prima**: -```csharp -private bool ShouldBid(AuctionInfo auction, AuctionState state) -{ - // ? Mancava controllo IsMyBid - - // Controlli prezzo... - // Controlli reset... - // Controlli clicks... - - return true; -} -``` - -**Dopo**: -```csharp -private bool ShouldBid(AuctionInfo auction, AuctionState state) -{ - // ? NUOVO: Prima controlla se sei gi vincitore - if (state.IsMyBid) - { - return false; - } - - // ... altri controlli ... - - return true; -} -``` - -## Ordine di Controllo in `ShouldBid()` - -``` -1. ? IsMyBid? ? false (skip, sei gi vincitore) -2. ? Price OK? ? false (skip, prezzo fuori range) -3. ? Reset Count OK? ? false (skip, troppi/pochi reset) -4. ? Max Clicks OK? ? false (skip, raggiunto limite click) -5. ? Cooldown OK? ? false (skip, troppo presto dall'ultimo click) -6. ? Tutti OK? ? true (PUNTA!) -``` - -**Importante**: `IsMyBid` il **primo** controllo perch la condizione pi comune e pi veloce da verificare. - -## Note Tecniche - -### Perch Prima Condizione? - -1. **Performance**: Controllo pi veloce (confronto string) -2. **Frequenza**: Caso pi comune quando monitori un'asta che gi vinci -3. **Logica**: Non ha senso controllare prezzo/reset se sei gi vincitore - -### Quando `IsMyBid` `true`? - -```csharp -// In BidooApiClient.cs -state.IsMyBid = !string.IsNullOrEmpty(_session.Username) && - state.LastBidder.Equals(_session.Username, StringComparison.OrdinalIgnoreCase); -``` - -Condizioni: -- ? Sessione ha username valido -- ? LastBidder dall'API = Username sessione (case-insensitive) - -### Possibili Edge Case - -#### Caso 1: Username Non Impostato -``` -_session.Username = null o "" -? IsMyBid = false sempre -? Sistema continua a puntare -``` -**Soluzione**: Richiedi sempre configurazione sessione all'avvio - -#### Caso 2: Username Diverso (Typo) -``` -Username sessione: "MioUsername" -LastBidder API: "miousername" -? IsMyBid = false (StringComparison.OrdinalIgnoreCase gestisce) -``` -**Soluzione**: Confronto case-insensitive gi implementato - -## Log Esempi - -### Log Normale (Non Vincitore) -``` -[STRATEGIA] Finestra di puntata raggiunta: 450ms <= 500ms -[BID OK] Latenza: 42ms -> EUR 1.25 -``` - -### Log con SKIP (Gi Vincitore) -``` -[STRATEGIA] Finestra di puntata raggiunta: 380ms <= 500ms -[STRATEGIA] SKIP: Sono gi il vincitore corrente (ultimo bidder: miousername) -``` - -### Log Alternanza -``` -[STRATEGIA] Finestra di puntata raggiunta: 450ms <= 500ms -[STRATEGIA] SKIP: Sono gi il vincitore corrente (ultimo bidder: miousername) -[RESET] Puntata: EUR 1.30 da altroUtente -[STRATEGIA] Finestra di puntata raggiunta: 420ms <= 500ms -[BID OK] Latenza: 38ms -> EUR 1.31 -``` - ---- - -## ? Test di Verifica - -- [x] Non punta quando gi vincitore -- [x] Log mostra SKIP con motivo chiaro -- [x] Punta quando altro utente supera -- [x] Nessun errore "Asta chiusa" quando vincitore -- [x] Risparmia chiamate API inutili -- [x] Logging chiaro in tutti gli scenari - ---- - -**Data Fix**: 2025 -**Versione**: 4.0+ -**Issue**: Puntata inutile quando gi vincitore -**Status**: ? RISOLTO - -## Riepilogo - -**Prima**: -- ? Puntava anche quando gi vincitore -- ? Errori "Asta chiusa" senza motivo -- ? Spreco risorse e puntate - -**Dopo**: -- ? SKIP automatico se gi vincitore -- ? Log chiaro: `[STRATEGIA] SKIP: Sono gi il vincitore corrente` -- ? Punta solo quando serve riprendersi l'asta -- ? Nessun errore inutile diff --git a/Mimante/Documentation/FIX_TAB_SETTINGS_WEBVIEW_INIT.md b/Mimante/Documentation/FIX_TAB_SETTINGS_WEBVIEW_INIT.md deleted file mode 100644 index 82729d6..0000000 --- a/Mimante/Documentation/FIX_TAB_SETTINGS_WEBVIEW_INIT.md +++ /dev/null @@ -1,380 +0,0 @@ -# ?? Fix Critici - Tab Impostazioni + WebView Init - -## ?? Problemi Rilevati - -### 1?? Tab Impostazioni Non Si Visualizza -**Sintomo**: Click sulla tab "Impostazioni" ? tab selezionata ma contenuto non mostrato - -**Causa**: -```csharp -// ? PROBLEMA -private void TabImpostazioni_Checked(object sender, RoutedEventArgs e) -{ - LoadDefaultSettings(); // Carica impostazioni - // MANCA: ShowPanel(Settings); ? Non chiamato! -} -``` - -### 2?? WebView Non Inizializzata Correttamente -**Sintomo**: Cookie extraction non funziona, browser non pre-caricato - -**Causa**: -- `InitializeWebView2()` chiamato troppo presto (nel constructor) -- UI non ancora completamente renderizzata -- `EnsureCoreWebView2Async()` fallisce silenziosamente - ---- - -## ? Soluzioni Implementate - -### 1?? Fix Tab Impostazioni - -**File**: `Core\MainWindow.ControlEvents.cs` - -**Prima** ?: -```csharp -private void TabImpostazioni_Checked(object sender, RoutedEventArgs e) -{ - try - { - // Carica impostazioni quando si apre la tab - LoadDefaultSettings(); - - // NOTA: Caricamento cookie RIMOSSO - ora automatico tramite browser - } - catch { } -} -``` - -**Dopo** ?: -```csharp -private void TabImpostazioni_Checked(object sender, RoutedEventArgs e) -{ - try - { - // ? FIX: Mostra il pannello Impostazioni - ShowPanel(Settings); - - // Carica impostazioni quando si apre la tab - LoadDefaultSettings(); - - // NOTA: Caricamento cookie RIMOSSO - ora automatico tramite browser - } - catch { } -} -``` - -**Effetto**: -- ? Click su tab "Impostazioni" ? pannello Settings visualizzato -- ? Impostazioni caricate correttamente -- ? Coerente con altre tab (tutte chiamano ShowPanel) - ---- - -### 2?? Fix WebView Init Background - -**File**: `Core\MainWindow.WebView.cs` - -**Prima** ?: -```csharp -private async void InitializeWebView2() -{ - if (EmbeddedWebView == null) - { - Log("[WARN] WebView2 non disponibile", LogLevel.Warn); - return; - } - - Log("[BROWSER] Inizializzazione WebView2 in background...", LogLevel.Info); - - // ? PROBLEMA: UI non ancora completamente caricata - await EmbeddedWebView.EnsureCoreWebView2Async(null); - - // ... -} -``` - -**Dopo** ?: -```csharp -private async void InitializeWebView2() -{ - try - { - if (EmbeddedWebView == null) - { - Log("[WARN] WebView2 non disponibile", LogLevel.Warn); - return; - } - - Log("[BROWSER] Inizializzazione WebView2 in background...", LogLevel.Info); - - // ? FIX: Aspetta 500ms che UI sia completamente caricata - await System.Threading.Tasks.Task.Delay(500); - - // ? Ora l'init funziona correttamente - await EmbeddedWebView.EnsureCoreWebView2Async(null); - - if (EmbeddedWebView.CoreWebView2 != null) - { - _isWebViewInitialized = true; - - // Pre-carica Bidoo - EmbeddedWebView.CoreWebView2.Navigate("https://it.bidoo.com"); - - Log("[BROWSER] ? WebView2 inizializzato e pre-caricato", LogLevel.Success); - - // Registra evento auto-login - EmbeddedWebView.CoreWebView2.NavigationCompleted += OnWebViewNavigationCompleted; - } - } - catch (Exception ex) - { - Log($"[WARN] Inizializzazione WebView2 fallita: {ex.Message}", LogLevel.Warn); - Log("[INFO] WebView2 sar inizializzata al primo utilizzo del browser", LogLevel.Info); - } -} -``` - -**Miglioramenti**: -- ? `Task.Delay(500)` - Aspetta che UI sia renderizzata -- ? `try-catch` completo - Gestisce errori gracefully -- ? Log fallback - Informa utente se init fallisce -- ? Fallback automatico - WebView init al primo uso se background fallisce - ---- - -## ?? Confronto Prima/Dopo - -### Tab Impostazioni - -| Aspetto | Prima ? | Dopo ? | -|---------|----------|---------| -| **Click tab** | Tab selezionata | Tab selezionata | -| **Pannello mostrato** | Niente (rimane tab precedente) | Settings visualizzato | -| **Impostazioni caricate** | S (ma invisibili) | S (e visibili) | -| **Coerenza con altre tab** | No | S | - -### WebView Init - -| Aspetto | Prima ? | Dopo ? | -|---------|----------|---------| -| **Timing init** | Troppo presto | Dopo 500ms (UI pronta) | -| **Successo init** | Spesso fallisce | Quasi sempre successo | -| **Gestione errori** | Silenzioso | Log + fallback | -| **Cookie extraction** | Non funziona | Funziona | -| **Pre-load Bidoo** | Non eseguito | Eseguito | - ---- - -## ?? Test di Verifica - -### Test 1: Tab Impostazioni ? - -**Steps**: -1. Avvia app -2. App si apre su tab "Aste Attive" (default) -3. Click su tab "Impostazioni" -4. Verifica pannello Settings mostrato -5. Verifica campi impostazioni visibili -6. Modifica un'impostazione -7. Salva -8. Cambia tab -9. Torna su "Impostazioni" -10. Verifica impostazione salvata - -**Risultato Atteso**: ? Settings sempre visibile quando tab selezionata - ---- - -### Test 2: WebView Init Background ? - -**Steps**: -1. Avvia app (primo avvio) -2. Aspetta 5 secondi (non aprire tab Browser) -3. Controlla log per: - ``` - [BROWSER] Inizializzazione WebView2 in background... - [BROWSER] ? WebView2 inizializzato e pre-caricato - ``` -4. Click su tab "Browser" -5. Verifica Bidoo gi caricato (non loader bianco) -6. Fai login su Bidoo -7. Controlla log per: - ``` - [BROWSER] Login rilevato - importazione automatica cookie... - [BROWSER] ? Connessione automatica completata - ``` - -**Risultato Atteso**: ? WebView pre-caricata, auto-login funzionante - ---- - -### Test 3: Fallback WebView (Se Init Fallisce) ? - -**Scenario**: WebView2 Runtime non installato o problema temporaneo - -**Steps**: -1. Simula errore init (disconnetti rete) -2. Avvia app -3. Controlla log per: - ``` - [WARN] Inizializzazione WebView2 fallita: [errore] - [INFO] WebView2 sar inizializzata al primo utilizzo del browser - ``` -4. Click su tab "Browser" -5. Verifica WebView inizializzata al primo uso - -**Risultato Atteso**: ? App non crasha, fallback funziona - ---- - -## ?? Flusso Completo Corretto - -### Avvio Applicazione - -``` -1. MainWindow() Constructor - ? -2. InitializeComponent() ? XAML caricato - ? -3. InitializeCommands() -4. LoadSavedAuctions() -5. LoadExportSettings() -6. LoadDefaultSettings() -7. UpdateGlobalControlButtons() - ? -8. InitializeUserInfoTimers() -9. LoadSavedSession() - ? -10. InitializeWebView2() ? Async, non blocca - ? (in background) - - Task.Delay(500ms) ? Aspetta UI - - EnsureCoreWebView2Async() - - Navigate("bidoo.com") - - Log success ? - ? -11. App pronta ? -``` - -### Click Tab Impostazioni - -``` -1. User click tab "Impostazioni" - ? -2. TabImpostazioni_Checked() - ? -3. ShowPanel(Settings) ? - ? - - AuctionMonitor.Visibility = Collapsed - - Browser.Visibility = Collapsed - - PuntateGratisPanel.Visibility = Collapsed - - StatisticsPanel.Visibility = Collapsed - - Settings.Visibility = Visible ? - ? -4. LoadDefaultSettings() - ? -5. Settings visualizzato ? -``` - ---- - -## ?? File Modificati - -| File | Modifiche | Linee | -|------|-----------|-------| -| `Core\MainWindow.ControlEvents.cs` | Aggiunto `ShowPanel(Settings)` | +1 | -| `Core\MainWindow.WebView.cs` | Delay 500ms + try-catch completo | +5 | - -**Totale**: 2 file, 6 righe modificate - ---- - -## ?? Note Importanti - -### Timing WebView Init - -**Perch 500ms?** -- 100ms ? Troppo poco, UI non pronta -- 500ms ? Giusto compromesso -- 1000ms ? Troppo, utente aspetta troppo - -**Alternative considerate**: -1. ? `Loaded` event ? Troppo presto -2. ? `ContentRendered` event ? Non affidabile con WPF moderno -3. ? `Task.Delay(500)` ? Semplice e funziona - -### Gestione Errori WebView - -**Scenari coperti**: -1. ? WebView2 Runtime non installato -2. ? Problema temporaneo di rete -3. ? Permessi insufficienti -4. ? Altro controllo attivo su WebView - -**Fallback**: -- WebView inizializzata al primo utilizzo del browser -- App continua a funzionare normalmente -- Solo funzionalit browser ritardata - ---- - -## ?? Risultati Finali - -### ? Tab Impostazioni -- Click su tab ? Pannello visualizzato immediatamente -- Impostazioni caricate e mostrate -- Modifiche salvate correttamente -- Coerente con tutte le altre tab - -### ? WebView Background Init -- Inizializzata automaticamente dopo 500ms -- Bidoo pre-caricato in background -- Pronta all'uso quando utente apre tab Browser -- Auto-login funzionante -- Fallback graceful se init fallisce - -### ? User Experience -- App si avvia velocemente -- Tutte le tab funzionano correttamente -- Browser immediatamente disponibile -- Nessun crash o errore visibile - ---- - -**Data Fix**: 2025 -**Versione**: 6.0+ -**Issue 1**: Tab Impostazioni non visualizzata -**Issue 2**: WebView init falliva silenziosamente -**Status**: ? ENTRAMBI RISOLTI - -## ?? Riferimenti - -- `Core\MainWindow.ControlEvents.cs` - Tab navigation handlers -- `Core\MainWindow.WebView.cs` - WebView initialization -- `MainWindow.xaml.cs` - Constructor e inizializzazione - ---- - -## ?? Debug Tips - -### Se Tab Impostazioni Non Si Vede - -1. Controlla log per errori durante `LoadDefaultSettings()` -2. Verifica `Settings.Visibility` in debugger -3. Controlla che `ShowPanel()` sia chiamato - -### Se WebView Non Si Inizializza - -1. Controlla log per: - - `[BROWSER] Inizializzazione WebView2...` - - `[BROWSER] ? WebView2 inizializzato` oppure - - `[WARN] Inizializzazione WebView2 fallita` -2. Verifica WebView2 Runtime installato -3. Prova ad aprire manualmente tab Browser - -**Comando check WebView2 Runtime**: -```powershell -Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" -Name pv -``` - -Se non presente, scarica da: https://developer.microsoft.com/en-us/microsoft-edge/webview2/ diff --git a/Mimante/Documentation/FIX_UI_UPDATE_AFTER_BID.md b/Mimante/Documentation/FIX_UI_UPDATE_AFTER_BID.md deleted file mode 100644 index 57ab1cf..0000000 --- a/Mimante/Documentation/FIX_UI_UPDATE_AFTER_BID.md +++ /dev/null @@ -1,425 +0,0 @@ -# ?? Fix Aggiornamento UI Contatori Puntate - -## ?? Problema Rilevato - -Dopo una puntata riuscita: -- ? La colonna "Clicks" nella griglia mostra **0** invece del numero corretto -- ? Il banner "Puntate residue" in alto non si aggiorna immediatamente -- ? L'aggiornamento avviene solo dopo 5-10 minuti (timer automatico) - -### Screenshot del Problema -- **Clicks**: mostra `0` anche dopo puntata -- **Puntate**: mostra `48` (non aggiornato dopo puntata) - ---- - -## ?? Analisi del Problema - -### Problema 1: `RefreshCounters()` non sul Thread UI -`RefreshCounters()` veniva chiamato dal thread worker invece che dal thread UI, quindi la UI non si aggiornava. - -```csharp -// ? PRIMA - thread worker -vm.RefreshCounters(); -``` - -### Problema 2: Banner Aggiornato Solo dai Timer -Il banner delle puntate residue veniva aggiornato solo dai timer (ogni 5-10 minuti), non immediatamente dopo la puntata. - -### Problema 3: Parsing Risposta Server Poco Chiaro -Il parsing della risposta non aveva logging dettagliato, quindi era impossibile capire se i dati arrivavano correttamente. - ---- - -## ? Soluzioni Implementate - -### 1?? Aggiunto Logging Dettagliato per Debugging - -**File**: `Services/BidooApiClient.cs` - -Ora quando punti, il log mostra **esattamente** cosa restituisce il server: - -```csharp -if (responseText.StartsWith("ok", StringComparison.OrdinalIgnoreCase)) -{ - result.Success = true; - var parts = responseText.Split('|'); - - // Log della risposta completa per debugging - Log($"[BID PARSE] Risposta completa: {responseText}", auctionId); - Log($"[BID PARSE] Numero totale campi: {parts.Length}", auctionId); - - // ? FORMATO RISPOSTA BIDOO: 9 campi - // Campo 1 (indice 0): "ok" - // Campo 2 (indice 1): Puntate residue totali - // Campo 5 (indice 4): Puntate usate su questa asta - - // Campo 2 (indice 1): Puntate residue totali - if (parts.Length > 1) - { - Log($"[BID PARSE] Campo 2 (indice 1) - Remaining bids: '{parts[1]}'", auctionId); - if (int.TryParse(parts[1], out var remaining)) - { - result.RemainingBids = remaining; - _session.RemainingBids = remaining; - Log($"[BID SUCCESS] ? Puntate residue totali: {remaining}", auctionId); - } - else - { - Log($"[BID PARSE WARN] ?? Impossibile parsare campo 2", auctionId); - } - } - - // Campo 5 (indice 4): Puntate usate su questa asta - if (parts.Length > 4) - { - Log($"[BID PARSE] Campo 5 (indice 4) - Bids used: '{parts[4]}'", auctionId); - if (int.TryParse(parts[4], out var usedOnAuction)) - { - result.BidsUsedOnThisAuction = usedOnAuction; - Log($"[BID SUCCESS] ? Puntate usate su questa asta: {usedOnAuction}", auctionId); - } - else - { - Log($"[BID PARSE WARN] ?? Impossibile parsare campo 5", auctionId); - } - } - - // Log tutti i campi per debugging completo - Log($"[BID PARSE DEBUG] Tutti i campi della risposta:", auctionId); - for (int i = 0; i < parts.Length; i++) - { - Log($" Campo {i+1} (indice {i}): '{parts[i]}'", auctionId); - } -} -``` - -### 2?? Aggiunto Metodo per Aggiornare Banner Immediatamente - -**File**: `Core/MainWindow.UserInfo.cs` - -Nuovo metodo `UpdateRemainingBidsDisplay()` per aggiornare il banner senza aspettare i timer: - -```csharp -/// -/// Aggiorna immediatamente il banner delle puntate residue (chiamato dopo ogni puntata) -/// -public void UpdateRemainingBidsDisplay() -{ - try - { - var session = _auctionMonitor.GetSession(); - if (session != null && session.RemainingBids > 0) - { - RemainingBidsText.Text = session.RemainingBids.ToString(); - Log($"[BANNER UPDATE] Puntate residue aggiornate: {session.RemainingBids}", LogLevel.Info); - } - } - catch (Exception ex) - { - Log($"[ERROR] Errore aggiornamento banner: {ex.Message}", LogLevel.Error); - } -} -``` - -### 3?? Aggiornamento Banner dopo Puntata Manuale - -**File**: `Core/MainWindow.Commands.cs` - -Ora `ExecuteGridBidAsync` chiama `UpdateRemainingBidsDisplay()` e `RefreshCounters()` sul thread UI: - -```csharp -private async Task ExecuteGridBidAsync(AuctionViewModel? vm) -{ - if (vm == null) return; - try - { - Log($"[BID] Puntata manuale richiesta su: {vm.Name}", LogLevel.Info); - var result = await _auctionMonitor.PlaceManualBidAsync(vm.AuctionInfo); - - // Aggiorna dati puntate da risposta server per puntata manuale - if (result.Success) - { - if (result.RemainingBids.HasValue) - { - vm.AuctionInfo.RemainingBids = result.RemainingBids.Value; - - // ? NUOVO: Aggiorna immediatamente il banner in alto - SUL THREAD UI - Dispatcher.Invoke(() => UpdateRemainingBidsDisplay()); - } - if (result.BidsUsedOnThisAuction.HasValue) - { - vm.AuctionInfo.BidsUsedOnThisAuction = result.BidsUsedOnThisAuction.Value; - } - - // ? NUOVO: Notifica aggiornamento contatori - SUL THREAD UI - Dispatcher.Invoke(() => vm.RefreshCounters()); - - Log($"[OK] Puntata manuale su {vm.Name}: {result.LatencyMs}ms", LogLevel.Success); - } - else - { - Log($"[FAIL] Puntata manuale su {vm.Name}: {result.Error}", LogLevel.Error); - } - } - catch (System.Exception ex) - { - Log($"[ERRORE] Puntata manuale: {ex.Message}", LogLevel.Error); - } -} -``` - -### 4?? Aggiornamento Banner dopo Puntata Automatica - -**File**: `MainWindow.xaml.cs` - -Modificato `AuctionMonitor_OnBidExecuted` per aggiornare anche il banner: - -```csharp -private void AuctionMonitor_OnBidExecuted(AuctionInfo auction, BidResult result) -{ - Dispatcher.BeginInvoke(() => - { - var vm = _auctionViewModels.FirstOrDefault(a => a.AuctionId == auction.AuctionId); - if (vm != null) - { - vm.RefreshCounters(); - - if (result.Success) - { - // ? NUOVO: Aggiorna il banner delle puntate residue dopo puntata automatica - if (result.RemainingBids.HasValue) - { - UpdateRemainingBidsDisplay(); - } - - Log($"[OK] Click su {auction.Name}: {result.LatencyMs}ms {result.Response}", LogLevel.Success); - } - else - { - Log($"[FAIL] Click fallito su {auction.Name}: {result.Error}", LogLevel.Error); - } - } - }); -} -``` - ---- - -## ?? Comportamento Corretto - -### ? Scenario: Puntata Manuale - -**Azioni**: -1. Clicchi "Punta" nella griglia -2. Server risponde: `ok|47|xxx|xxx|1|xxx|xxx|xxx|xxx` (9 campi) - -**Risultato Atteso**: -- ?? **Colonna "Clicks"**: aggiornata immediatamente da `0` ? `1` -- ?? **Banner "Puntate"**: aggiornato immediatamente da `48` ? `47` -- ?? **Log dettagliato**: - ``` - [BID PARSE] Risposta completa: ok|47|xxx|xxx|1|xxx|xxx|xxx|xxx - [BID PARSE] Numero totale campi: 9 - [BID PARSE] Campo 2 (indice 1) - Remaining bids: '47' - [BID SUCCESS] ? Puntate residue totali: 47 - [BID PARSE] Campo 5 (indice 4) - Bids used: '1' - [BID SUCCESS] ? Puntate usate su questa asta: 1 - [BID PARSE DEBUG] Tutti i campi della risposta: - Campo 1 (indice 0): 'ok' - Campo 2 (indice 1): '47' - Campo 3 (indice 2): 'xxx' - Campo 4 (indice 3): 'xxx' - Campo 5 (indice 4): '1' - Campo 6 (indice 5): 'xxx' - Campo 7 (indice 6): 'xxx' - Campo 8 (indice 7): 'xxx' - Campo 9 (indice 8): 'xxx' - [BANNER UPDATE] Puntate residue aggiornate: 47 - [OK] Puntata manuale su Balenciaga Collana: 45ms - ``` - -### ? Scenario: Puntata Automatica - -**Azioni**: -1. Strategia punta automaticamente -2. Server risponde: `ok|46|xxx|xxx|2|xxx|xxx|xxx|xxx` (9 campi) - -**Risultato Atteso**: -- ?? **Colonna "Clicks"**: aggiornata automaticamente `1` ? `2` -- ?? **Banner "Puntate"**: aggiornato automaticamente `47` ? `46` -- ?? **Log dettagliato** (come sopra) - ---- - -## ?? Log di Debugging - -### Cosa Cercare nei Log - -Dopo una puntata, cerca nel log questi messaggi: - -``` -[BID PARSE] Risposta completa: ok|XX|xxx|xxx|X|xxx|xxx|xxx|xxx -[BID PARSE] Numero totale campi: 9 -[BID PARSE] Campo 2 (indice 1) - Remaining bids: 'XX' -[BID SUCCESS] ? Puntate residue totali: XX -[BID PARSE] Campo 5 (indice 4) - Bids used: 'X' -[BID SUCCESS] ? Puntate usate su questa asta: X -[BID PARSE DEBUG] Tutti i campi della risposta: - Campo 1 (indice 0): 'ok' - Campo 2 (indice 1): 'XX' - Campo 3 (indice 2): 'xxx' - Campo 4 (indice 3): 'xxx' - Campo 5 (indice 4): 'X' - ... -[BANNER UPDATE] Puntate residue aggiornate: XX -``` - -### Se Vedi Questi Messaggi = Problema Risolto ? - -Se vedi: -- `[BID PARSE] Numero totale campi: 9` ? -- `[BID PARSE] Campo 2 (indice 1) - Remaining bids: 'XX'` ? -- `[BID SUCCESS] ? Puntate residue totali: XX` ? -- `[BID PARSE] Campo 5 (indice 4) - Bids used: 'X'` ? -- `[BID SUCCESS] ? Puntate usate su questa asta: X` ? -- `[BANNER UPDATE] Puntate residue aggiornate: XX` ? - -Significa che: -- ? Il server restituisce i dati correttamente -- ? Il parsing legge i campi giusti (campo 2 e campo 5) -- ? Il banner viene aggiornato -- ? La colonna "Clicks" si aggiorna - -### Se Vedi Questi Warning = Problema con Risposta Server ?? - -Se vedi: -- `[BID PARSE] Numero totale campi: X` (dove X ? 9) ?? -- `[BID PARSE ERROR] ? Risposta non ha campo 2` ?? -- `[BID PARSE ERROR] ? Risposta non ha campo 5` ?? -- `[BID PARSE WARN] ?? Impossibile parsare campo X` ?? - -Significa che: -- ?? Il server **non restituisce** 9 campi come previsto -- ?? I campi sono in posizioni diverse -- ?? Il formato risposta cambiato - ---- - -## ?? Come Testare - -### Test 1: Puntata Manuale con Log Abilitati - -1. Apri l'applicazione -2. Aggiungi un'asta -3. **Guarda il banner in alto** - nota le puntate residue (es. 48) -4. Clicca "Punta" nella griglia -5. **Controlla il log** - devi vedere i messaggi `[BID PARSE]` -6. **Verifica**: - - ? Colonna "Clicks" aggiornata immediatamente - - ? Banner "Puntate" decrementato (es. 48 ? 47) - - ? Log mostra parsing dettagliato - -### Test 2: Puntata Automatica - -1. Configura strategia (Anticipo = 200ms) -2. Avvia l'asta -3. Aspetta che punti automaticamente -4. **Verifica** (come sopra) - -### Test 3: Puntate Multiple - -1. Punta 3 volte manualmente -2. **Verifica** che ad ogni puntata: - - Clicks: `0` ? `1` ? `2` ? `3` - - Puntate: `48` ? `47` ? `46` ? `45` - ---- - -## ?? Troubleshooting - -### Problema: Clicks Rimane a 0 - -**Possibili cause**: -1. Il server non restituisce il campo "bids used" nella risposta -2. Il campo in una posizione diversa - -**Soluzione**: -Guarda il log `[BID PARSE]` e verifica: -- Quanti campi ha la risposta? -- Quale campo contiene il contatore? -- Potrebbe servire modificare gli indici del parsing - -### Problema: Banner Non Si Aggiorna - -**Possibili cause**: -1. Il server non restituisce "remaining bids" -2. `UpdateRemainingBidsDisplay()` non viene chiamato - -**Soluzione**: -Cerca nel log: -- `[BANNER UPDATE] Puntate residue aggiornate` ? -- Se non c', il metodo non viene chiamato -- Se c' ma il banner non cambia, problema UI binding - -### Problema: Log Non Mostra `[BID PARSE]` - -**Possibile causa**: -La puntata fallisce prima del parsing - -**Soluzione**: -Cerca errori prima di `[BID PARSE]`: -- `[BID ERROR]` - puntata fallita -- `[BID EXCEPTION]` - errore durante chiamata - ---- - -## ?? File Modificati - -| File | Modifiche | -|------|-----------| -| `Services/BidooApiClient.cs` | ?? Aggiunto logging dettagliato parsing risposta | -| `Core/MainWindow.UserInfo.cs` | ? Aggiunto metodo `UpdateRemainingBidsDisplay()` | -| `Core/MainWindow.Commands.cs` | ?? Chiamata `UpdateRemainingBidsDisplay()` e `RefreshCounters()` su UI thread | -| `MainWindow.xaml.cs` | ?? Aggiornamento banner in `AuctionMonitor_OnBidExecuted` | - ---- - -## ? Checklist Test - -### Prima di Chiudere Issue - -- [ ] Puntata manuale aggiorna colonna "Clicks" immediatamente -- [ ] Puntata manuale aggiorna banner "Puntate" immediatamente -- [ ] Puntata automatica aggiorna colonna "Clicks" -- [ ] Puntata automatica aggiorna banner "Puntate" -- [ ] Log mostra `[BID PARSE]` con tutti i campi -- [ ] Log mostra `[BID SUCCESS] Puntate residue totali: XX` -- [ ] Log mostra `[BID SUCCESS] Puntate usate su questa asta: X` -- [ ] Log mostra `[BANNER UPDATE] Puntate residue aggiornate: XX` -- [ ] Nessun errore/warning nel parsing -- [ ] Build compila senza errori - ---- - -**Data Fix**: 2025 -**Versione**: 4.1+ -**Issue**: UI non aggiorna contatori dopo puntata -**Status**: ? RISOLTO - ---- - -## ?? Riepilogo - -### Prima: -- ? Colonna "Clicks" mostra sempre 0 -- ? Banner aggiornato solo dopo 5-10 minuti -- ? Nessun logging dettagliato -- ? `RefreshCounters()` su thread sbagliato - -### Dopo: -- ? Colonna "Clicks" aggiornata **immediatamente** -- ? Banner aggiornato **immediatamente** -- ? Log **dettagliato** per debugging -- ? `RefreshCounters()` sul **thread UI** corretto -- ? `UpdateRemainingBidsDisplay()` chiamato dopo ogni puntata diff --git a/Mimante/Documentation/FIX_WEBVIEW_ALREADY_INITIALIZED.md b/Mimante/Documentation/FIX_WEBVIEW_ALREADY_INITIALIZED.md deleted file mode 100644 index b5c54ee..0000000 --- a/Mimante/Documentation/FIX_WEBVIEW_ALREADY_INITIALIZED.md +++ /dev/null @@ -1,296 +0,0 @@ -# ?? Fix: WebView2 Already Initialized Error - -## ?? Problema - -### Log Errore - -``` -[18:47:29] [ERROR] Inizializzazione WebView2 fallita: -WebView2 was already initialized with a different CoreWebView2Environment. -Check to see if the Source property was already set or -EnsureCoreWebView2Async was previously called with different values. - -[18:47:29] [DEBUG] Exception type: ArgumentException -``` - -### Root Cause - -**XAML** stava inizializzando automaticamente WebView2: - -```xaml - - -``` - -**Sequenza Eventi** (PRIMA ?): - -``` -1. XAML carica ? WebView2 vede Source="https://..." -2. WebView2 auto-init con CoreWebView2Environment.Default -3. InitializeWebView2() chiama EnsureCoreWebView2Async(customEnv) -4. ? ArgumentException: Already initialized with different environment! -``` - ---- - -## ? Soluzione - -**Rimuovere `Source` da XAML** e gestire init completamente via codice. - -### File: `Controls\BrowserControl.xaml` - -#### BEFORE ? - -```xaml - -``` - -#### AFTER ? - -```xaml - ? ? Nessuna init automatica -``` - ---- - -## ?? Flusso Corretto - -### Dopo il Fix ? - -``` -1. XAML carica ? WebView2 NON inizializzata (nessun Source) -2. MainWindow() constructor ? InitializeWebView2() -3. CreateAsync(userDataFolder) ? Crea environment personalizzato -4. EnsureCoreWebView2Async(env) ? Init con environment custom ? -5. Navigate("https://it.bidoo.com") ? Carica pagina via codice -``` - ---- - -## ?? Benefici - -| Aspetto | Prima ? | Dopo ? | -|---------|----------|---------| -| **Init Source** | XAML (automatico) | Codice (controllato) | -| **Environment** | Default (auto) | Custom (esplicito) | -| **UserDataFolder** | Auto-detect (problematico) | Esplicito (sicuro) | -| **Timing** | Immediato (prima del codice) | Controllato (quando vogliamo) | -| **Errore** | ArgumentException | Nessuno | - ---- - -## ?? Test Richiesto - -### Step 1: Pulisci Cache - -```powershell -# Rimuovi vecchia cache WebView -Remove-Item "$env:LOCALAPPDATA\AutoBidder\WebView2" -Recurse -Force -ErrorAction SilentlyContinue -``` - -### Step 2: Riavvia App - -1. Chiudi completamente l'app -2. Ricompila (gi fatto) -3. Avvia app -4. Aspetta 30 secondi -5. Osserva log - -### Step 3: Verifica Log - -**Log Atteso** ?: - -``` -[18:47:28] [BROWSER] Inizializzazione WebView2 in background... -[18:47:29] [DEBUG] Chiamata EnsureCoreWebView2Async... -[18:47:29] [DEBUG] UserDataFolder: C:\Users\...\AutoBidder\WebView2 -[18:47:29] [DEBUG] CoreWebView2Environment creato -[18:47:29] [DEBUG] EnsureCoreWebView2Async completata ? ? NESSUN ERRORE! -[18:47:29] [DEBUG] CoreWebView2 disponibile, navigating... -[18:47:29] [BROWSER] WebView2 inizializzato e pre-caricato -[18:47:29] [DEBUG] Notifica WebView pronta (TrySetResult) -[18:47:29] [DEBUG] Inizio CheckAndImportCookieIfAvailable -[18:47:30] [DEBUG] CheckAndImportCookieIfAvailable - inizio -[18:47:31] [DEBUG] Delay 1000ms completato, chiamo GetCookieFromWebView -[18:47:32] [DEBUG] GetCookieFromWebView ritornato, cookie presente: True -[18:47:32] [BROWSER] Cookie rilevato - importazione automatica... -[18:47:33] [SESSION OK] Validata e attiva: sirbietole23, XX puntate -``` - -**NON Deve Comparire** ?: -``` -[ERROR] Inizializzazione WebView2 fallita: WebView2 was already initialized... -``` - ---- - -## ?? Checklist - -- [x] Rimosso `Source="https://it.bidoo.com"` da XAML -- [x] WebView2 init gestita completamente via codice -- [x] Environment custom con UserDataFolder esplicito -- [x] Navigate chiamato via codice dopo init -- [ ] Test con cache pulita (da fare) -- [ ] Verifica auto-login funzionante (da fare) - ---- - -## ?? Perch Succedeva - -### XAML Source Property - -In WPF, quando imposti `Source` su un controllo WebView2 in XAML: - -```xaml - -``` - -**Dietro le quinte**: - -```csharp -// WPF chiama automaticamente (internamente) -await webView.EnsureCoreWebView2Async(null); // null = environment default -webView.CoreWebView2.Navigate(Source); -``` - -**Problema**: Quando poi noi chiamiamo: - -```csharp -var env = await CoreWebView2Environment.CreateAsync(...); // Environment custom -await webView.EnsureCoreWebView2Async(env); // ? Already initialized! -``` - -**Soluzione**: Rimuovi `Source` da XAML, gestisci tutto via codice: - -```csharp -// Prima init con environment custom -var env = await CoreWebView2Environment.CreateAsync(...); -await webView.EnsureCoreWebView2Async(env); // ? Prima chiamata - -// Poi navigate -webView.CoreWebView2.Navigate("https://..."); -``` - ---- - -## ?? Pattern Corretto - -### ? Anti-Pattern (Causa Errore) - -```xaml - - ? Init automatica - - -var env = CreateAsync(...); // Troppo tardi! -await webView.EnsureCoreWebView2Async(env); // ? Exception -``` - -### ? Pattern Corretto - -```xaml - - ? Nessuna init - - -var env = await CreateAsync(...); -await WebView.EnsureCoreWebView2Async(env); // ? Prima chiamata -WebView.CoreWebView2.Navigate("https://site.com"); // ? Navigate via codice -``` - ---- - -## ?? Risultato Atteso - -### Ora il Flow : - -``` -Avvio App - ? -XAML carica (WebView2 NON inizializzata) - ? -MainWindow() constructor - ? -InitializeWebView2() (async background) - ? -await CoreWebView2Environment.CreateAsync(customUserDataFolder) - ? [2-3 secondi] - ? -await EnsureCoreWebView2Async(env) ? ? Prima e unica chiamata! - ? -CoreWebView2.Navigate("https://it.bidoo.com") - ? -CheckAndImportCookieIfAvailable() - ? -GetCookieFromWebView() ? Cookie trovato - ? -ValidateAndActivateSessionAsync() - ? -[SESSION OK] Connesso! -``` - ---- - -## ?? Prossimi Passi - -1. ? **Pulisci cache**: `Remove-Item "$env:LOCALAPPDATA\AutoBidder\WebView2" -Recurse -Force` -2. ? **Riavvia app** (gi compilata) -3. ? **Aspetta 30 secondi** senza cliccare -4. ? **Copia log completo** e inviami - -**Cerco specificamente**: -- ? `[DEBUG] EnsureCoreWebView2Async completata` senza errori -- ? `[DEBUG] GetCookieFromWebView ritornato, cookie presente: True` -- ? `[SESSION OK] Validata e attiva` - -**NON deve esserci**: -- ? `[ERROR] ... already initialized ...` -- ? `[WARN] Timeout attesa inizializzazione` - ---- - -**Data Fix**: 2025 -**Versione**: 7.2+ -**Issue**: ArgumentException - WebView already initialized -**Root Cause**: XAML Source property inizializza WebView prima del codice -**Soluzione**: Rimosso Source da XAML, init completamente gestita via codice -**Status**: ? Fix applicato, test richiesto - -## ?? Riferimenti - -- `Controls\BrowserControl.xaml` - Rimosso Source property -- `Core\MainWindow.WebView.cs` - Init con environment custom -- [WebView2 Source Property](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.wpf.webview2.source) -- [EnsureCoreWebView2Async](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.wpf.webview2.ensurecorewebview2async) - ---- - -## ?? Note Importanti - -### Se ancora non funziona dopo questo fix: - -1. **Verifica nessun altro `Source=` in XAML**: - ```powershell - Select-String -Path "*.xaml" -Pattern 'Source="' -Recurse - ``` - -2. **Verifica nessuna altra init in codice**: - ```powershell - Select-String -Path "*.cs" -Pattern 'EnsureCoreWebView2Async' -Recurse - ``` - -3. **Pulisci bin/obj**: - ```powershell - Remove-Item bin, obj -Recurse -Force - ``` - -4. **Rebuild completo**: - ``` - Build ? Clean Solution - Build ? Rebuild Solution - ``` diff --git a/Mimante/Documentation/FIX_WEBVIEW_THREADING_ERROR.md b/Mimante/Documentation/FIX_WEBVIEW_THREADING_ERROR.md deleted file mode 100644 index 5d919c8..0000000 --- a/Mimante/Documentation/FIX_WEBVIEW_THREADING_ERROR.md +++ /dev/null @@ -1,653 +0,0 @@ -# ?? Fix: Threading Error - Accesso WebView da Thread Background - -## ?? Problema - -**Errore Runtime**: -``` -[17:09:42] [WARN] Impossibile estrarre cookie da WebView: -Il thread chiamante non riesce ad accedere a questo oggetto -perch tale oggetto di propriet di un altro thread. -``` - -**Causa**: Tentativo di accesso a **controllo UI (WebView2)** da **thread background (Task.Run)** - -**Impatto**: -- ? Cookie extraction fallisce all'avvio -- ? Auto-login non funziona fino al click tab Browser -- ? Verifica presenza cookie fallisce - ---- - -## ?? Analisi Dettagliata - -### Thread Model WPF - -In WPF, **tutti i controlli UI** possono essere accessibili **SOLO dal thread UI**: - -```csharp -// ? SBAGLIATO - Crash garantito -Task.Run(() => -{ - var value = myTextBox.Text; // ? InvalidOperationException! -}); - -// ? CORRETTO - Usa Dispatcher -Task.Run(() => -{ - Dispatcher.Invoke(() => - { - var value = myTextBox.Text; // ? OK, thread UI - }); -}); -``` - -### WebView2 un Controllo UI - -```csharp -public Microsoft.Web.WebView2.Wpf.WebView2 EmbeddedWebView -``` - -- ? Deriva da `System.Windows.UIElement` -- ? Appartiene al **thread UI (Dispatcher)** -- ? **NON** thread-safe -- ? **NON** accessibile da background threads - ---- - -## ?? Codice Problematico - -### File: `Core\MainWindow.UserInfo.cs` - -**Scenario 1: Nessuna Sessione Salvata** - -**Prima** ?: -```csharp -else -{ - Log("[SESSION] Nessuna sessione salvata", LogLevel.Info); - - // Aspetta che WebView sia inizializzata (in background) - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(2000); - - // ? PROBLEMA: GetCookieFromWebView accede a EmbeddedWebView - // ma siamo su un thread BACKGROUND (Task.Run)! - var browserCookie = await GetCookieFromWebView(); - // ? - // Questo chiama: - // EmbeddedWebView.CoreWebView2.CookieManager.GetCookiesAsync(...) - // ? - // EmbeddedWebView un controllo UI! - // InvalidOperationException! - - Dispatcher.Invoke(() => - { - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per accedere:", LogLevel.Info); - // ... - } - }); - }); -} -``` - -**Dopo** ?: -```csharp -else -{ - Log("[SESSION] Nessuna sessione salvata", LogLevel.Info); - - // Aspetta che WebView sia inizializzata (in background) - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(2000); - - // ? FIX: Accesso WebView DEVE essere sul thread UI - await Dispatcher.InvokeAsync(async () => - { - // ? ORA siamo sul thread UI! - var browserCookie = await GetCookieFromWebView(); - // ? - // Questo chiama: - // EmbeddedWebView.CoreWebView2.CookieManager.GetCookiesAsync(...) - // ? - // EmbeddedWebView accessibile perch siamo sul thread UI! - // ? Nessun errore! - - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per accedere:", LogLevel.Info); - // ... - } - }); - }); -} -``` - ---- - -### Scenario 2: Sessione Scaduta - -**Prima** ?: -```csharp -else -{ - SetUserBanner(string.Empty, 0); - Log("[SESSION] Sessione scaduta", LogLevel.Warn); - - // ? PROBLEMA: Dispatcher.Invoke NON aspetta task async! - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(500); - - // ? Siamo ancora su thread background! - var browserCookie = await GetCookieFromWebView(); - - Dispatcher.Invoke(() => - { - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per riconnetterti:", LogLevel.Info); - } - }); - }); -} -``` - -**Dopo** ?: -```csharp -else -{ - SetUserBanner(string.Empty, 0); - Log("[SESSION] Sessione scaduta", LogLevel.Warn); - - // ? FIX: Dispatcher.InvokeAsync supporta async/await - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(500); - - // ? Switcha al thread UI E aspetta il task async - await Dispatcher.InvokeAsync(async () => - { - var browserCookie = await GetCookieFromWebView(); - - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per riconnetterti:", LogLevel.Info); - } - }); - }); -} -``` - ---- - -### Scenario 3: Errore Verifica Sessione - -**Prima** ?: -```csharp -catch (Exception ex) -{ - Dispatcher.Invoke(() => - { - SetUserBanner(string.Empty, 0); - Log($"[SESSION] Errore verifica sessione: {ex.Message}", LogLevel.Warn); - - // ? PROBLEMA: Task.Run dentro Dispatcher.Invoke - // Poi accesso WebView da background thread! - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(500); - var browserCookie = await GetCookieFromWebView(); - - Dispatcher.Invoke(() => - { - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per connetterti:", LogLevel.Info); - } - }); - }); - }); -} -``` - -**Dopo** ?: -```csharp -catch (Exception ex) -{ - Dispatcher.Invoke(() => - { - SetUserBanner(string.Empty, 0); - Log($"[SESSION] Errore verifica sessione: {ex.Message}", LogLevel.Warn); - - // ? FIX: Dispatcher.InvokeAsync per accesso WebView - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(500); - - await Dispatcher.InvokeAsync(async () => - { - var browserCookie = await GetCookieFromWebView(); - - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per connetterti:", LogLevel.Info); - } - }); - }); - }); -} -``` - ---- - -### Scenario 4: Exception Handler Finale - -**Prima** ?: -```csharp -catch (Exception ex) -{ - Log($"[ERRORE] Caricamento sessione: {ex.Message}", LogLevel.Error); - - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(2000); - - // ? Accesso WebView da background thread! - var browserCookie = await GetCookieFromWebView(); - - Dispatcher.Invoke(() => - { - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per accedere:", LogLevel.Info); - } - }); - }); - - SetUserBanner(string.Empty, 0); -} -``` - -**Dopo** ?: -```csharp -catch (Exception ex) -{ - Log($"[ERRORE] Caricamento sessione: {ex.Message}", LogLevel.Error); - - System.Threading.Tasks.Task.Run(async () => - { - await System.Threading.Tasks.Task.Delay(2000); - - // ? Switcha al thread UI per accedere a WebView - await Dispatcher.InvokeAsync(async () => - { - var browserCookie = await GetCookieFromWebView(); - - if (string.IsNullOrEmpty(browserCookie)) - { - Log("[INFO] Per accedere:", LogLevel.Info); - } - }); - }); - - SetUserBanner(string.Empty, 0); -} -``` - ---- - -## ?? Pattern Corretto - -### ? Anti-Pattern (Causa l'errore) - -```csharp -// Background thread -Task.Run(async () => -{ - // ? Accesso diretto a controllo UI da background thread - var cookie = await GetCookieFromWebView(); - // ? - // Accede a EmbeddedWebView (UI control) - // InvalidOperationException! - - Dispatcher.Invoke(() => - { - // Log... - }); -}); -``` - -### ? Pattern Corretto - -```csharp -// Background thread -Task.Run(async () => -{ - // Attesa che NON blocca thread UI - await Task.Delay(2000); - - // ? Switcha al thread UI per accedere a controlli UI - await Dispatcher.InvokeAsync(async () => - { - // ? ORA siamo sul thread UI, possiamo accedere a WebView - var cookie = await GetCookieFromWebView(); - - // Tutto il codice qui sul thread UI - if (string.IsNullOrEmpty(cookie)) - { - Log("[INFO] ..."); - } - }); -}); -``` - ---- - -## ?? Chiavi del Fix - -### 1. `Dispatcher.Invoke` vs `Dispatcher.InvokeAsync` - -| Metodo | Supporta Async | Usa Per | -|--------|----------------|---------| -| `Dispatcher.Invoke(() => { })` | ? No | Codice sincrono | -| `Dispatcher.InvokeAsync(async () => { })` | ? S | Codice async (await) | - -**Esempio**: -```csharp -// ? SBAGLIATO - Invoke non aspetta task async -Dispatcher.Invoke(() => -{ - var result = await GetSomethingAsync(); // ? Errore compilazione! -}); - -// ? CORRETTO - InvokeAsync supporta await -await Dispatcher.InvokeAsync(async () => -{ - var result = await GetSomethingAsync(); // ? OK -}); -``` - -### 2. Nesting Task.Run e Dispatcher - -```csharp -// ? Pattern corretto -Task.Run(async () => // Thread background -{ - await Task.Delay(2000); // Attesa non bloccante - - await Dispatcher.InvokeAsync(async () => // Switch a thread UI - { - var data = await GetUIDataAsync(); // Accesso UI (async) - ProcessData(data); // Elaborazione - }); -}); -``` - -### 3. Perch Non Fare Tutto su Thread UI? - -```csharp -// ? BAD - Blocca thread UI per 2 secondi! -Dispatcher.Invoke(() => -{ - Thread.Sleep(2000); // ? UI freezata! - var cookie = GetCookieFromWebView(); -}); - -// ? GOOD - Attesa su background, poi switch a UI -Task.Run(async () => -{ - await Task.Delay(2000); // ? UI responsive - - await Dispatcher.InvokeAsync(async () => - { - var cookie = await GetCookieFromWebView(); // ? Breve op su UI - }); -}); -``` - ---- - -## ?? Test di Verifica - -### Test 1: Avvio con Browser Pulito ? - -**Steps**: -1. Cancella cookie browser -2. Cancella sessione salvata -3. Avvia app -4. Controlla log - -**Log Atteso** (PRIMA ?): -``` -[17:09:42] [SESSION] Nessuna sessione salvata -[17:09:42] [BROWSER] Inizializzazione WebView2 in background... -[17:09:42] [WARN] Impossibile estrarre cookie da WebView: - Il thread chiamante non riesce ad accedere... -[17:09:50] [BROWSER] WebView2 inizializzato e pre-caricato -``` - -**Log Atteso** (DOPO ?): -``` -[17:09:42] [SESSION] Nessuna sessione salvata -[17:09:42] [BROWSER] Inizializzazione WebView2 in background... -[17:09:50] [BROWSER] WebView2 inizializzato e pre-caricato -[17:09:52] [INFO] Per accedere: -[17:09:52] [INFO] 1. Click su 'Non connesso' nella sidebar -... -``` - -**Risultato**: ? Nessun errore, istruzioni mostrate correttamente - ---- - -### Test 2: Avvio con Browser Loggato ? - -**Steps**: -1. Fai login su Bidoo nel browser -2. Riavvia app -3. Controlla log - -**Log Atteso** (PRIMA ?): -``` -[17:09:42] [SESSION] Nessuna sessione salvata -[17:09:42] [BROWSER] Inizializzazione WebView2 in background... -[17:09:42] [WARN] Impossibile estrarre cookie da WebView: - Il thread chiamante non riesce ad accedere... -[17:09:50] [BROWSER] WebView2 inizializzato e pre-caricato -``` - -**Log Atteso** (DOPO ?): -``` -[17:09:42] [SESSION] Nessuna sessione salvata -[17:09:42] [BROWSER] Inizializzazione WebView2 in background... -[17:09:50] [BROWSER] WebView2 inizializzato e pre-caricato -[17:09:52] [INFO] Cookie rilevato nel browser - in attesa di importazione automatica... -[17:09:56] [BROWSER] Login rilevato - importazione automatica cookie... -[17:09:56] [SESSION OK] Validata e attiva: username, XX puntate -[17:09:56] [BROWSER] Connessione automatica completata -``` - -**Risultato**: ? Auto-login funziona SENZA click tab Browser - ---- - -### Test 3: Sessione Scaduta ? - -**Steps**: -1. Crea sessione salvata con cookie vecchio -2. Avvia app -3. Controlla log - -**Log Atteso** (PRIMA ?): -``` -[17:09:42] [SESSION] Ripristino sessione per: username -[17:09:42] [SESSION] Verifica validit sessione... -[17:09:45] [SESSION] Sessione scaduta -[17:09:45] [WARN] Impossibile estrarre cookie da WebView: - Il thread chiamante non riesce ad accedere... -``` - -**Log Atteso** (DOPO ?): -``` -[17:09:42] [SESSION] Ripristino sessione per: username -[17:09:42] [SESSION] Verifica validit sessione... -[17:09:45] [SESSION] Sessione scaduta -[17:09:46] [INFO] Per riconnetterti: -[17:09:46] [INFO] 1. Click su 'Non connesso' nella sidebar -... -``` - -**Risultato**: ? Verifica cookie funziona, istruzioni mostrate correttamente - ---- - -## ?? File Modificati - -| File | Modifiche | Scenario | -|------|-----------|----------| -| `Core\MainWindow.UserInfo.cs` | 4 fix | Nessuna sessione, Sessione scaduta, Exception handlers | - -**Totale**: 1 file, 4 punti di fix - ---- - -## ?? Impatto del Fix - -### Prima ? - -``` -Avvio App - ? -LoadSavedSession() - ? -Task.Run(() => { - await Task.Delay(2000); - var cookie = await GetCookieFromWebView(); ? ? Crash! - ? - [WARN] Impossibile estrarre cookie... -}) - ? -Cookie extraction fallita - ? -Istruzioni login NON mostrate - ? -Auto-login NON funziona fino a click tab Browser -``` - -### Dopo ? - -``` -Avvio App - ? -LoadSavedSession() - ? -Task.Run(() => { - await Task.Delay(2000); - await Dispatcher.InvokeAsync(async () => { - var cookie = await GetCookieFromWebView(); ? ? OK! - ? - [INFO] Cookie rilevato... / Per accedere... - }); -}) - ? -Cookie extraction funzionante - ? -Se cookie presente ? Auto-login IMMEDIATO -Se cookie assente ? Istruzioni chiare -``` - ---- - -## ?? Lezioni Apprese - -### 1. Controlli UI = Thread UI Only - -**Regola d'oro**: -> Qualsiasi accesso a controlli UI (TextBox, Button, WebView, ecc.) DEVE avvenire sul thread UI (Dispatcher). - -### 2. Task.Run per Attese, Dispatcher per UI - -**Pattern corretto**: -```csharp -Task.Run(async () => // Background: attese lunghe -{ - await Task.Delay(5000); - - await Dispatcher.InvokeAsync(async () => // UI: accesso controlli - { - var data = await GetUIDataAsync(); - }); -}); -``` - -### 3. InvokeAsync per Codice Async - -**Ricorda**: -- `Dispatcher.Invoke()` ? Codice sincrono -- `Dispatcher.InvokeAsync()` ? Codice async (await) - -### 4. Errori Threading Comuni WPF - -| Errore | Causa | Fix | -|--------|-------|-----| -| "Il thread chiamante non riesce ad accedere..." | Accesso UI da background | `Dispatcher.InvokeAsync` | -| "This type of CollectionView does not support..." | Modifica collection da background | `Dispatcher.BeginInvoke` | -| "The calling thread cannot access this object..." | Stesso problema, messaggio diverso | `Dispatcher.InvokeAsync` | - ---- - -## ? Risultato Finale - -### Funzionalit Ripristinate - -1. ? **Cookie extraction all'avvio** funziona -2. ? **Auto-login** funziona senza click tab Browser -3. ? **Verifica presenza cookie** funziona -4. ? **Istruzioni login intelligenti** funzionano -5. ? **Nessun errore threading** nei log - -### Performance - -- ? UI rimane responsive (attese su background thread) -- ? Accesso WebView rapido (solo quando necessario, su UI thread) -- ? Nessun freeze o delay percepibile - -### User Experience - -**Prima** ?: -``` -1. Avvio app con browser loggato -2. [WARN] Errore threading -3. Nessun auto-login -4. Utente deve cliccare tab Browser -5. Poi auto-login funziona -``` - -**Dopo** ?: -``` -1. Avvio app con browser loggato -2. Nessun errore -3. Auto-login automatico entro 2-3 secondi -4. Utente vede subito username e puntate -5. Tutto funziona come previsto -``` - ---- - -**Data Fix**: 2025 -**Versione**: 6.2+ -**Issue**: Threading error - accesso WebView da background thread -**Causa**: `GetCookieFromWebView()` chiamato fuori dal Dispatcher -**Soluzione**: `Dispatcher.InvokeAsync` per accesso UI controls -**Status**: ? RISOLTO - -## ?? Riferimenti - -- `Core\MainWindow.UserInfo.cs` - LoadSavedSession threading fix -- `Core\MainWindow.WebView.cs` - GetCookieFromWebView implementation -- [Microsoft Docs - Threading Model](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/threading-model) -- [Dispatcher Class](https://learn.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher) diff --git a/Mimante/Documentation/FIX_WEBVIEW_TIMEOUT_USERDATAFOLDER.md b/Mimante/Documentation/FIX_WEBVIEW_TIMEOUT_USERDATAFOLDER.md deleted file mode 100644 index 02a2f67..0000000 --- a/Mimante/Documentation/FIX_WEBVIEW_TIMEOUT_USERDATAFOLDER.md +++ /dev/null @@ -1,352 +0,0 @@ -# ?? Fix Critico: WebView2 Timeout (60 secondi) - -## ?? Problema Identificato - -### Log Diagnostico - -``` -[17:50:14] [BROWSER] Inizializzazione WebView2 in background... -[17:50:16] [DEBUG] Chiamata EnsureCoreWebView2Async... -[17:51:14] [WARN] Timeout attesa inizializzazione WebView2 ? 60 secondi dopo! -[17:51:14] [WARN] WebView non inizializzata dopo 60 secondi -``` - -**Causa**: `EnsureCoreWebView2Async()` si blocca per 60 secondi e **non completa mai**. - ---- - -## ? Soluzione Implementata - -### Fix: UserDataFolder Esplicito - -**Problema**: WebView2 tentava di creare UserDataFolder in posizione non accessibile o con permessi insufficienti. - -**Soluzione**: Specifica **esplicitamente** UserDataFolder in `%LOCALAPPDATA%\AutoBidder\WebView2`. - ---- - -## ?? Modifiche - -### File: `Core\MainWindow.WebView.cs` - -#### BEFORE ? - -```csharp -private async void InitializeWebView2() -{ - await EmbeddedWebView.EnsureCoreWebView2Async(null); - // ? - // null = auto-detect folder - // ? Pu fallire con permessi/path problematici -} -``` - -#### AFTER ? - -```csharp -private async void InitializeWebView2() -{ - // ? Specifica UserDataFolder esplicito - var userDataFolder = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "AutoBidder", - "WebView2" - ); - - Log($"[DEBUG] UserDataFolder: {userDataFolder}", LogLevel.Info); - - // Crea directory se non esiste - Directory.CreateDirectory(userDataFolder); - - // Crea environment con UserDataFolder esplicito - var env = await CoreWebView2Environment.CreateAsync( - browserExecutableFolder: null, - userDataFolder: userDataFolder // ? Path esplicito - ); - - Log("[DEBUG] CoreWebView2Environment creato", LogLevel.Info); - - // Inizializza WebView con environment - await EmbeddedWebView.EnsureCoreWebView2Async(env); -} -``` - ---- - -## ?? UserDataFolder Path - -### Prima ? (Auto-detect) - -``` -C:\Users\\AppData\Local\\EBWebView\ -``` - -**Problemi**: -- Potrebbe essere inaccessibile -- Permessi insufficienti -- Path troppo lungo -- Caratteri speciali nel path - -### Dopo ? (Esplicito) - -``` -C:\Users\\AppData\Local\AutoBidder\WebView2\ -``` - -**Benefici**: -- Path controllato e prevedibile -- Directory creata esplicitamente -- Permessi garantiti (%LOCALAPPDATA%) -- Path corto e senza caratteri speciali - ---- - -## ?? Logging Dettagliato Aggiunto - -### Prima Init - -``` -[17:50:14] [BROWSER] Inizializzazione WebView2 in background... -[17:50:16] [DEBUG] Chiamata EnsureCoreWebView2Async... -[17:50:16] [DEBUG] UserDataFolder: C:\Users\...\AutoBidder\WebView2 ? Nuovo -[17:50:16] [DEBUG] CoreWebView2Environment creato ? Nuovo -[17:50:18] [DEBUG] EnsureCoreWebView2Async completata ? Nuovo -[17:50:18] [DEBUG] CoreWebView2 disponibile, navigating... ? Nuovo -[17:50:18] [BROWSER] WebView2 inizializzato e pre-caricato -``` - -### In Caso di Errore - -``` -[17:50:14] [ERROR] Inizializzazione WebView2 fallita: [messaggio] -[17:50:14] [DEBUG] Exception type: InvalidOperationException -[17:50:14] [DEBUG] Stack trace: ... -[17:50:14] [DEBUG] Inner exception: Access denied -``` - ---- - -## ?? Test Richiesto - -### Step 1: Cancella WebView Cache Esistente - -```powershell -# Rimuovi vecchia cache (se esiste) -Remove-Item "$env:LOCALAPPDATA\\EBWebView" -Recurse -Force -ErrorAction SilentlyContinue - -# Oppure pulisci tutto -Remove-Item "$env:LOCALAPPDATA\AutoBidder" -Recurse -Force -ErrorAction SilentlyContinue -``` - -### Step 2: Riavvia App - -1. Chiudi completamente l'app -2. Ricompila (Build ? Rebuild Solution) -3. Avvia app -4. Osserva log - -### Step 3: Verifica Log - -**Log atteso (Successo)** ?: - -``` -[17:50:14] [BROWSER] Inizializzazione WebView2 in background... -[17:50:16] [DEBUG] Chiamata EnsureCoreWebView2Async... -[17:50:16] [DEBUG] UserDataFolder: C:\Users\...\AutoBidder\WebView2 -[17:50:16] [DEBUG] CoreWebView2Environment creato -[17:50:18] [DEBUG] EnsureCoreWebView2Async completata ? Deve comparire entro 5 secondi! -[17:50:18] [DEBUG] CoreWebView2 disponibile, navigating... -[17:50:18] [BROWSER] WebView2 inizializzato e pre-caricato -[17:50:18] [DEBUG] Notifica WebView pronta (TrySetResult) -[17:50:18] [DEBUG] Inizio CheckAndImportCookieIfAvailable -[17:50:19] [DEBUG] CheckAndImportCookieIfAvailable - inizio -[17:50:20] [DEBUG] Delay 1000ms completato, chiamo GetCookieFromWebView -[17:50:21] [DEBUG] GetCookieFromWebView ritornato, cookie presente: True -[17:50:21] [BROWSER] Cookie rilevato - importazione automatica... -[17:50:22] [SESSION OK] Validata e attiva: sirbietole23, XX puntate -``` - -**Log atteso (Fallimento)** ?: - -``` -[17:50:14] [BROWSER] Inizializzazione WebView2 in background... -[17:50:16] [DEBUG] Chiamata EnsureCoreWebView2Async... -[17:50:16] [DEBUG] UserDataFolder: C:\Users\...\AutoBidder\WebView2 -[17:50:16] [ERROR] Inizializzazione WebView2 fallita: [messaggio specifico] -[17:50:16] [DEBUG] Exception type: ... -[17:50:16] [DEBUG] Stack trace: ... -``` - ---- - -## ?? Checklist Diagnostica - -Se ancora non funziona, verifica: - -### 1. Permessi Directory - -```powershell -# Verifica esistenza e permessi -$path = "$env:LOCALAPPDATA\AutoBidder\WebView2" -Test-Path $path -Get-Acl $path | Format-List -``` - -**Atteso**: Directory creata, permessi Full Control per utente corrente - ---- - -### 2. WebView2 Runtime Versione - -```powershell -Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" -Name pv -``` - -**Atteso**: Versione >= 100.0.0.0 - ---- - -### 3. Antivirus/Firewall - -**Verifica**: -- Windows Defender non blocca `msedgewebview2.exe` -- Firewall non blocca connessioni WebView2 - -**Soluzione**: -```powershell -# Aggiungi eccezione Windows Defender (admin) -Add-MpPreference -ExclusionPath "$env:LOCALAPPDATA\AutoBidder\WebView2" -``` - ---- - -### 4. Spazio Disco - -```powershell -Get-PSDrive C | Select-Object Free, Used -``` - -**Atteso**: Almeno 500 MB liberi - ---- - -### 5. Path Troppo Lungo - -```powershell -# Verifica lunghezza path -$path = "$env:LOCALAPPDATA\AutoBidder\WebView2" -$path.Length -``` - -**Atteso**: < 200 caratteri - ---- - -## ?? Fix Alternativi (Se Ancora Fallisce) - -### Opzione 1: Usa Temp Folder - -```csharp -var userDataFolder = Path.Combine( - Path.GetTempPath(), // C:\Users\...\AppData\Local\Temp - "AutoBidder_WebView2" -); -``` - -### Opzione 2: Usa Desktop (Sempre Accessibile) - -```csharp -var userDataFolder = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.Desktop), - ".autobidder_webview" -); -``` - -### Opzione 3: Disabilita Cache - -```csharp -var options = new CoreWebView2EnvironmentOptions(); -options.AdditionalBrowserArguments = "--disable-web-security --disable-cache"; - -var env = await CoreWebView2Environment.CreateAsync( - null, - userDataFolder, - options -); -``` - ---- - -## ?? Tempistiche Attese - -| Fase | Tempo Normale | Timeout Se... | -|------|---------------|---------------| -| CreateAsync | 1-2 sec | Path inaccessibile | -| EnsureCoreWebView2Async | 2-3 sec | Permessi insufficienti | -| Navigate | 1-2 sec | Rete offline | -| GetCookiesAsync | < 1 sec | WebView non pronta | - -**Totale normale**: ~5-8 secondi -**Totale attuale**: 60 secondi (timeout) - ---- - -## ?? Prossimi Passi - -1. ? **Pulisci cache vecchia**: `Remove-Item "$env:LOCALAPPDATA\AutoBidder" -Recurse -Force` -2. ? **Ricompila app**: Build ? Rebuild Solution -3. ? **Riavvia app** e osserva log -4. ? **Inviami nuovo log** completo (primi 30 secondi) - -### Log da Cercare - -**Successo** ?: -``` -[DEBUG] CoreWebView2Environment creato -[DEBUG] EnsureCoreWebView2Async completata ? Entro 5 secondi! -``` - -**Fallimento** ?: -``` -[ERROR] Inizializzazione WebView2 fallita: [messaggio] -[DEBUG] Exception type: ... ? Inviami questo! -``` - ---- - -## ?? Cause Comuni Timeout - -| Causa | Sintomo | Fix | -|-------|---------|-----| -| **Permessi** | Access Denied | Esegui come Admin | -| **Antivirus** | Blocked by AV | Aggiungi eccezione | -| **Path Lungo** | PathTooLongException | Usa path pi corto | -| **Spazio Disco** | Disk Full | Libera spazio | -| **WebView Corrotto** | Init Timeout | Reinstalla WebView2 Runtime | - ---- - -**Data Fix**: 2025 -**Versione**: 7.1+ -**Issue**: WebView2 timeout 60 secondi all'init -**Root Cause**: UserDataFolder auto-detect falliva -**Soluzione**: UserDataFolder esplicito + logging dettagliato -**Status**: ? Fix applicato, test richiesto - -## ?? Riferimenti - -- `Core\MainWindow.WebView.cs` - InitializeWebView2() refactored -- [CoreWebView2Environment.CreateAsync](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2environment.createasync) -- [WebView2 Troubleshooting](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/troubleshooting) - ---- - -## ?? IMPORTANTE - -**Se ancora va in timeout dopo questo fix**, il problema pi profondo: -- Reinstalla WebView2 Runtime -- Controlla Windows Event Viewer per errori -- Esegui app come Administrator -- Verifica integrit file system - -**Inviami sempre il log completo con i nuovi messaggi [DEBUG]!** diff --git a/Mimante/Documentation/FIX_WEBVIEW_VISIBILITY_REQUIREMENT.md b/Mimante/Documentation/FIX_WEBVIEW_VISIBILITY_REQUIREMENT.md deleted file mode 100644 index af61fc3..0000000 --- a/Mimante/Documentation/FIX_WEBVIEW_VISIBILITY_REQUIREMENT.md +++ /dev/null @@ -1,378 +0,0 @@ -# ?? Fix Finale: WebView2 Richiede Visibilit per Inizializzarsi - -## ?? Problema Root Cause - -### Log Diagnostico - -``` -[09:38:14] [DEBUG] CoreWebView2Environment creato -[09:39:13] [WARN] Timeout attesa inizializzazione WebView2 ? 59 secondi di blocco! - -[Dopo click tab Browser] -[09:39:32] [DEBUG] EnsureCoreWebView2Async completata ? Completata immediatamente! -``` - -**Root Cause**: `EnsureCoreWebView2Async()` **si blocca** finch WebView2 non diventa **visibile**. Questo un comportamento **by-design di WPF WebView2**. - ---- - -## ?? Perch Succede - -### WPF WebView2 Visibility Requirement - -In WPF, **WebView2 si inizializza solo quando visibile** (rendered). Questo documentato: - -> "The WebView2 control will not initialize until it is visible in the visual tree and has been measured and arranged." - -**Sequenza Prima del Fix** ?: - -``` -Avvio App - ? -Tab "Aste Attive" selezionata (Browser.Visibility = Collapsed) - ? -InitializeWebView2() - ? -CoreWebView2Environment.CreateAsync() ? OK (2 secondi) - ? -EnsureCoreWebView2Async(env) ? BLOCCA (aspetta visibilit) - ? [Attesa infinita...] - ? -Utente click tab "Browser" - ? -Browser.Visibility = Visible - ? -EnsureCoreWebView2Async completa immediatamente ? -``` - ---- - -## ? Soluzione: Forza Visibilit Temporanea - -**Pattern**: Rendi Browser visibile durante l'init, poi ripristina tab originale. - -### Sequenza Dopo il Fix ?: - -``` -Avvio App - ? -Tab "Aste Attive" selezionata (Browser.Visibility = Collapsed) - ? -InitializeWebView2() - ? -Salva tab corrente: "AsteAttive" - ? -Forza Browser.Visibility = Visible (temporaneo) - ? -await Task.Delay(100) // Aspetta render - ? -CoreWebView2Environment.CreateAsync() ? (2 secondi) - ? -EnsureCoreWebView2Async(env) ? Completa immediatamente (visibile!) - ? -Ripristina Browser.Visibility = Collapsed - ? -Ripristina tab originale: "AsteAttive" - ? -WebView2 inizializzata e pronta ? - ? -CheckAndImportCookieIfAvailable() ? - ? -Auto-login funziona ? -``` - ---- - -## ?? Modifiche Implementate - -### File: `Core\MainWindow.WebView.cs` - -#### Nuovo Codice (Visibilit Temporanea) - -```csharp -private async void InitializeWebView2() -{ - // ... - - // ? FIX CRITICO: WebView2 si inizializza SOLO se visibile - // Salva tab corrente - var wasVisible = Browser.Visibility == Visibility.Visible; - var currentTab = TabAsteAttive.IsChecked == true ? "AsteAttive" : - TabBrowser.IsChecked == true ? "Browser" : - // ... altri tab - - if (!wasVisible) - { - Log("[DEBUG] WebView non visibile, forzo visibilit temporanea..."); - - // Rendi visibile - await Dispatcher.InvokeAsync(() => - { - Browser.Visibility = Visibility.Visible; - }); - - // Aspetta render completo - await Task.Delay(100); - } - - // Ora WebView visibile, pu inizializzarsi - var env = await CoreWebView2Environment.CreateAsync(...); - await EmbeddedWebView.EnsureCoreWebView2Async(env); // ? Completa velocemente! - - // ? Ripristina stato originale - if (!wasVisible) - { - await Dispatcher.InvokeAsync(() => - { - Browser.Visibility = Visibility.Collapsed; - - // Ripristina tab originale - switch (currentTab) - { - case "AsteAttive": - TabAsteAttive.IsChecked = true; - AuctionMonitor.Visibility = Visibility.Visible; - break; - // ... altri casi - } - }); - - Log("[DEBUG] Tab originale ripristinata"); - } - - // ... -} -``` - ---- - -## ?? Tempistiche - -### Prima ? - -| Fase | Tempo | -|------|-------| -| CreateAsync | 2 sec | -| EnsureCoreWebView2Async | **60 sec (timeout!)** | -| **Totale** | **62 sec** | - -### Dopo ? - -| Fase | Tempo | -|------|-------| -| Forza visibilit | 0.1 sec | -| CreateAsync | 2 sec | -| EnsureCoreWebView2Async | **0.5 sec** | -| Ripristina visibilit | 0.1 sec | -| **Totale** | **~3 sec** ? | - -**Miglioramento**: Da 62 secondi a 3 secondi = **20x pi veloce**! - ---- - -## ?? Test Atteso - -### Log Corretto ? - -``` -[09:38:13] [BROWSER] Inizializzazione WebView2 in background... -[09:38:14] [DEBUG] Chiamata EnsureCoreWebView2Async... -[09:38:14] [DEBUG] WebView non visibile, forzo visibilit temporanea... ? Nuovo -[09:38:14] [DEBUG] UserDataFolder: C:\Users\...\AutoBidder\WebView2 -[09:38:14] [DEBUG] CoreWebView2Environment creato -[09:38:16] [DEBUG] EnsureCoreWebView2Async completata ? 2 secondi dopo! ? -[09:38:16] [DEBUG] Tab originale ripristinata ? Nuovo -[09:38:16] [DEBUG] CoreWebView2 disponibile, navigating... -[09:38:16] [BROWSER] WebView2 inizializzato e pre-caricato -[09:38:17] [DEBUG] GetCookieFromWebView ritornato, cookie presente: True -[09:38:17] [BROWSER] Cookie rilevato - importazione automatica... -[09:38:18] [SESSION OK] Validata e attiva: sirbietole23, 59 puntate -``` - -**Verifiche**: -- ? `EnsureCoreWebView2Async completata` dopo **~2 secondi** (non 60!) -- ? `Tab originale ripristinata` presente nei log -- ? Auto-login completo entro **5 secondi** dall'avvio -- ? Nessun flash visibile della tab Browser (troppo veloce) - ---- - -## ?? UX Impatto - -### Comportamento Visibile - -**Utente NON vede nulla di diverso**: -- App si apre su tab "Aste Attive" (default) -- Browser **non** lampeggia (cambio troppo veloce, ~100ms) -- Dopo 3-5 secondi: Username appare in sidebar (auto-login) - -**Solo nei log**: -``` -[DEBUG] WebView non visibile, forzo visibilit temporanea... -[DEBUG] Tab originale ripristinata -``` - ---- - -## ?? Alternativa: Inizializzazione Lazy - -Se preferisci **non** forzare la visibilit, alternativa : - -```csharp -// Init WebView SOLO quando utente apre tab Browser per la prima volta -private async void TabBrowser_Checked(object sender, RoutedEventArgs e) -{ - ShowPanel(Browser); - - if (!_isWebViewInitialized) - { - await InitializeWebView2(); - } -} -``` - -**Pro**: -- Nessuna manipolazione visibilit -- Pi "pulito" - -**Contro**: -- ? Auto-login NON funziona all'avvio -- ? Utente deve cliccare tab Browser manualmente -- ? Cookie detection ritardata - -**Conclusione**: Forzare visibilit temporanea la scelta migliore per auto-login. - ---- - -## ?? Dettagli Tecnici - -### Perch 100ms Delay? - -```csharp -Browser.Visibility = Visibility.Visible; -await Task.Delay(100); // ? Perch serve? -``` - -**Motivo**: WPF ha bisogno di **render** il controllo. La sequenza : - -1. `Visibility = Visible` ? Aggiorna layout tree -2. WPF dispatcher ? Schedule render pass -3. Render pass ? Effettivo rendering su schermo -4. WebView2 ? Rileva visibilit e si inizializza - -**100ms** garantisce che il render pass sia completato prima di chiamare `EnsureCoreWebView2Async`. - ---- - -### Perch Ripristinare Visibilit? - -```csharp -Browser.Visibility = Visibility.Collapsed; -``` - -**Motivo**: Se lasciamo `Browser.Visibility = Visible` ma con un'altra tab selezionata: - -- ? Browser rendered in background (spreco memoria) -- ? JavaScript eseguito in background (spreco CPU) -- ? Animazioni/timer attivi inutilmente - -**Collapsed** = WebView2 rimane inizializzata ma **non consume risorse**. - ---- - -## ?? Pattern Riusabile - -Questo pattern funziona per **qualsiasi controllo WPF** che richiede visibilit: - -```csharp -// Template generico -private async Task InitializeControlRequiringVisibility(T control) - where T : FrameworkElement -{ - var wasVisible = control.Visibility == Visibility.Visible; - - if (!wasVisible) - { - control.Visibility = Visibility.Visible; - await Task.Delay(100); // Render time - } - - // Inizializza controllo - await control.Initialize(); - - if (!wasVisible) - { - control.Visibility = Visibility.Collapsed; - } -} -``` - -**Applicabile a**: -- WebView2 -- Media player che richiede HwndHost -- DirectX/OpenGL controls -- Qualsiasi controllo con HWND nativo - ---- - -## ?? Risultato Finale - -### Ora il Flow : - -``` -Avvio App (tab "Aste Attive") - ? (500ms) - ? -InitializeWebView2() - ? -Salva tab corrente - ? (100ms) -Forza Browser visibile - ? (2 sec) -Crea environment + Init WebView - ? (100ms) -Ripristina tab originale - ? (1 sec) -Navigate Bidoo - ? (2 sec) -Carica pagina + Estrai cookie - ? (1 sec) -Valida cookie - ? -[SESSION OK] ? -``` - -**Totale**: ~7 secondi dall'avvio a sessione attiva -**Utente percepito**: Nessun cambio tab visibile -**Auto-login**: ? Funziona perfettamente - ---- - -**Data Fix**: 2025 -**Versione**: 7.3 FINALE -**Issue**: WebView2 timeout perch non visibile -**Root Cause**: WPF WebView2 richiede visibilit per inizializzarsi -**Soluzione**: Forza visibilit temporanea (100ms) durante init -**Status**: ? RISOLTO DEFINITIVAMENTE - -## ?? Riferimenti - -- `Core\MainWindow.WebView.cs` - InitializeWebView2() con visibilit forzata -- [WebView2 Visibility Requirement](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.wpf.webview2) -- [WPF Visibility Property](https://learn.microsoft.com/en-us/dotnet/api/system.windows.uielement.visibility) - -## ?? Note Finali - -**Questo il fix DEFINITIVO**. Se ancora non funziona: - -1. Verifica log mostra: - ``` - [DEBUG] WebView non visibile, forzo visibilit temporanea... - [DEBUG] EnsureCoreWebView2Async completata ? Entro 5 secondi! - ``` - -2. Se non vedi questi log: build non aggiornata, ricompila - -3. Se vedi timeout ancora: problema pi grave (WebView2 Runtime corrotto) - -**Test richiesto**: Riavvia app e inviami log completo (primi 30 secondi) diff --git a/Mimante/Documentation/LOG_CLEANUP_FINAL.md b/Mimante/Documentation/LOG_CLEANUP_FINAL.md deleted file mode 100644 index 8c1eac3..0000000 --- a/Mimante/Documentation/LOG_CLEANUP_FINAL.md +++ /dev/null @@ -1,334 +0,0 @@ -# ? Log Cleanup - Versione Finale Pulita - -## ?? Obiettivo - -Rimuovere tutti i log di debug aggiunti durante la fase di troubleshooting, mantenendo solo i messaggi essenziali per l'utente finale. - ---- - -## ?? Log Rimossi - -### MainWindow.WebView.cs - -**Rimossi** ?: -```csharp -Log("[DEBUG] Chiamata EnsureCoreWebView2Async..."); -Log($"[DEBUG] UserDataFolder: {userDataFolder}"); -Log("[DEBUG] CoreWebView2Environment creato"); -Log("[DEBUG] EnsureCoreWebView2Async completata"); -Log("[DEBUG] CoreWebView2 disponibile, navigating..."); -Log("[DEBUG] Notifica WebView pronta (TrySetResult)"); -Log("[DEBUG] Inizio CheckAndImportCookieIfAvailable"); -Log("[DEBUG] CheckAndImportCookieIfAvailable - inizio"); -Log("[DEBUG] Delay 1000ms completato, chiamo GetCookieFromWebView"); -Log($"[DEBUG] GetCookieFromWebView ritornato, cookie presente: {!string.IsNullOrEmpty(cookie)}"); -Log("[DEBUG] Chiamata AutoImportCookieFromWebView"); -Log("[DEBUG] AutoImportCookieFromWebView completata"); -Log("[DEBUG] Cookie gi presente in sessione corrente, skip import"); -Log("[DEBUG] Nessun cookie trovato nel browser"); -Log("[DEBUG] WebView non visibile, forzo visibilit temporanea..."); -Log("[DEBUG] Tab originale ripristinata"); -Log($"[DEBUG] Exception type: {ex.GetType().Name}"); -Log($"[DEBUG] Stack trace: {ex.StackTrace}"); -Log($"[DEBUG] Inner exception: {ex.InnerException.Message}"); -``` - -**Mantenuti** ?: -```csharp -Log("[BROWSER] Inizializzazione WebView2 in background..."); -Log("[BROWSER] WebView2 inizializzato e pre-caricato"); -Log("[BROWSER] Cookie rilevato - importazione automatica..."); -Log("[ERROR] Inizializzazione WebView2 fallita: {ex.Message}"); -Log("[WARN] Verifica cookie fallita: {ex.Message}"); -``` - ---- - -### MainWindow.UserInfo.cs - -**Rimossi** ?: -```csharp -Log("[DEBUG] CheckBrowserCookieAfterWebViewReady - avviato Task.Run"); -Log("[DEBUG] Attesa inizializzazione WebView per verifica cookie..."); -Log("[DEBUG] WaitForWebViewInitAsync completato, ready: {webViewReady}"); -Log("[DEBUG] WebView pronta, procedo con verifica cookie"); -Log("[DEBUG] Dispatcher.InvokeAsync - chiamo GetCookieFromWebView"); -Log($"[DEBUG] GetCookieFromWebView ritornato, cookie: {(string.IsNullOrEmpty(browserCookie) ? "VUOTO" : "PRESENTE")}"); -Log("[DEBUG] CheckBrowserCookieAfterWebViewReady exception: {ex.Message}"); -Log($"[DEBUG] Stack trace: {ex.StackTrace}"); -Log($"[DEBUG] WaitForWebViewInitAsync - inizio (timeout: {timeoutSeconds}s)"); -Log("[DEBUG] WebView gi inizializzata, ritorno true immediato"); -Log("[DEBUG] Creazione TaskCompletionSource"); -Log($"[DEBUG] WaitForWebViewInitAsync completato, result: {result}"); -``` - -**Mantenuti** ?: -```csharp -Log($"[SESSION] Ripristino sessione per: {session.Username}"); -Log("[SESSION] Verifica validit sessione..."); -Log($"[SESSION] Sessione valida - {username} ({bids} puntate)"); -Log("[SESSION] Sessione scaduta"); -Log($"[SESSION] Errore verifica sessione: {ex.Message}"); -Log("[SESSION] Nessuna sessione salvata"); -Log("[WARN] WebView non inizializzata dopo 60 secondi"); -Log("[INFO] Per accedere:"); -Log("[INFO] 1. Click su 'Non connesso'..."); -Log("[WARN] Timeout attesa inizializzazione WebView2"); -Log($"[WARN] Errore verifica cookie: {ex.Message}"); -Log($"[ERRORE] Caricamento sessione: {ex.Message}"); -``` - ---- - -## ?? Log Finale dell'Utente - -### Scenario 1: Primo Avvio (No Cookie) - -``` -[09:38:13] [LOAD] 6 aste caricate con stato iniziale: Stopped -[09:38:13] [OK] Impostazioni caricate: Anticipo=200ms, LogAsta=500, LogGlobale=1000, MinBids=0 -[09:38:13] [OK] AutoBidder v4.0 avviato -[09:38:13] [SESSION] Nessuna sessione salvata -[09:38:13] [BROWSER] Inizializzazione WebView2 in background... -[09:38:16] [BROWSER] WebView2 inizializzato e pre-caricato -[09:38:18] [INFO] Nessun cookie nel browser -[09:38:18] [INFO] Per accedere: -[09:38:18] [INFO] 1. Click su 'Non connesso' nella sidebar -[09:38:18] [INFO] 2. Si aprir la scheda Browser -[09:38:18] [INFO] 3. Fai login su Bidoo -[09:38:18] [INFO] 4. La connessione sar automatica -``` - -**Risultato**: Chiaro e conciso ? - ---- - -### Scenario 2: Primo Avvio (Con Cookie) - -``` -[09:38:13] [LOAD] 6 aste caricate con stato iniziale: Stopped -[09:38:13] [OK] Impostazioni caricate: Anticipo=200ms, LogAsta=500, LogGlobale=1000, MinBids=0 -[09:38:13] [OK] AutoBidder v4.0 avviato -[09:38:13] [SESSION] Nessuna sessione salvata -[09:38:13] [BROWSER] Inizializzazione WebView2 in background... -[09:38:16] [BROWSER] WebView2 inizializzato e pre-caricato -[09:38:18] [INFO] Cookie rilevato nel browser - importazione in corso... -[09:38:18] [BROWSER] Cookie rilevato nel browser - importazione automatica... -[09:38:19] [SESSION OK] Validata e attiva: sirbietole23, 59 puntate -[09:38:19] [BROWSER] Connessione automatica completata -``` - -**Risultato**: Feedback chiaro dell'auto-login ? - ---- - -### Scenario 3: Sessione Salvata Valida - -``` -[09:38:13] [LOAD] 6 aste caricate con stato iniziale: Stopped -[09:38:13] [OK] Impostazioni caricate: Anticipo=200ms, LogAsta=500, LogGlobale=1000, MinBids=0 -[09:38:13] [OK] AutoBidder v4.0 avviato -[09:38:13] [SESSION] Ripristino sessione per: sirbietole23 -[09:38:13] [SESSION] Verifica validit sessione... -[09:38:13] [BROWSER] Inizializzazione WebView2 in background... -[09:38:16] [BROWSER] WebView2 inizializzato e pre-caricato -[09:38:16] [SESSION] Sessione valida - sirbietole23 (59 puntate) -``` - -**Risultato**: Ripristino rapido e chiaro ? - ---- - -## ?? Vantaggi Log Puliti - -### Per l'Utente Finale - -| Aspetto | Prima (Debug) | Dopo (Pulito) | -|---------|---------------|---------------| -| **Righe Log** | ~30 righe | ~10 righe | -| **Leggibilit** | Confuso | Chiaro ? | -| **Informazioni Utili** | Mescolate | Solo essenziali ? | -| **Tempo Lettura** | ~30 sec | ~5 sec ? | - -### Messaggi Chiave Mantenuti - -? **Info Utente**: -- Stato caricamento aste -- Stato sessione (salvata/nuova) -- Risultato validazione -- Istruzioni login (se necessarie) - -? **Errori Importanti**: -- Errori init WebView -- Timeout WebView -- Errori validazione cookie - -? **Successi**: -- WebView inizializzata -- Cookie importato -- Sessione valida - -? **Rimossi**: -- Step interni di init -- Dettagli tecnici -- Stack traces completi -- Debug markers (`[DEBUG]`) - ---- - -## ?? Confronto Prima/Dopo - -### Prima (Con Debug) ? - -``` -[09:38:13] [SESSION] Nessuna sessione salvata -[09:38:13] [DEBUG] CheckBrowserCookieAfterWebViewReady - avviato Task.Run -[09:38:13] [DEBUG] Attesa inizializzazione WebView... -[09:38:13] [DEBUG] WaitForWebViewInitAsync - inizio (timeout: 60s) -[09:38:13] [DEBUG] Creazione TaskCompletionSource -[09:38:13] [BROWSER] Inizializzazione WebView2 in background... -[09:38:14] [DEBUG] Chiamata EnsureCoreWebView2Async... -[09:38:14] [DEBUG] UserDataFolder: C:\Users\...\AutoBidder\WebView2 -[09:38:14] [DEBUG] CoreWebView2Environment creato -[09:38:16] [DEBUG] EnsureCoreWebView2Async completata -[09:38:16] [DEBUG] CoreWebView2 disponibile, navigating... -[09:38:16] [BROWSER] WebView2 inizializzato e pre-caricato -[09:38:16] [DEBUG] Notifica WebView pronta (TrySetResult) -[09:38:16] [DEBUG] Inizio CheckAndImportCookieIfAvailable -[09:38:16] [DEBUG] CheckAndImportCookieIfAvailable - inizio -[09:38:17] [DEBUG] Delay 1000ms completato -[09:38:18] [DEBUG] GetCookieFromWebView ritornato, cookie presente: True -[09:38:18] [BROWSER] Cookie rilevato - importazione automatica... -[09:38:18] [DEBUG] Chiamata AutoImportCookieFromWebView -[09:38:19] [SESSION OK] Validata e attiva: sirbietole23, 59 puntate -[09:38:19] [DEBUG] AutoImportCookieFromWebView completata -``` - -**Totale**: 22 righe (10 debug + 12 info) - ---- - -### Dopo (Pulito) ? - -``` -[09:38:13] [SESSION] Nessuna sessione salvata -[09:38:13] [BROWSER] Inizializzazione WebView2 in background... -[09:38:16] [BROWSER] WebView2 inizializzato e pre-caricato -[09:38:18] [INFO] Cookie rilevato nel browser - importazione in corso... -[09:38:18] [BROWSER] Cookie rilevato nel browser - importazione automatica... -[09:38:19] [SESSION OK] Validata e attiva: sirbietole23, 59 puntate -``` - -**Totale**: 6 righe (tutte essenziali) - -**Riduzione**: -73% di righe, +300% leggibilit - ---- - -## ?? Risultato Finale - -### Vantaggi - -1. ? **Log Conciso**: Solo info essenziali -2. ? **Facile Lettura**: Niente tecnicismi inutili -3. ? **Chiaro Feedback**: Utente capisce stato app -4. ? **Debug Possibile**: Errori ancora loggati -5. ? **Performance**: Meno overhead I/O - -### File Modificati - -| File | Righe Rimosse | Status | -|------|---------------|--------| -| `Core\MainWindow.WebView.cs` | ~15 log debug | ? Pulito | -| `Core\MainWindow.UserInfo.cs` | ~10 log debug | ? Pulito | - -**Totale**: ~25 righe di debug rimosse - ---- - -## ?? Linee Guida Log Future - -### ? DA LOGGARE - -**Azioni Utente**: -```csharp -Log("[BROWSER] Inizializzazione..."); -Log("[SESSION] Ripristino sessione..."); -Log("[LOAD] N aste caricate..."); -``` - -**Risultati Importanti**: -```csharp -Log("[SESSION OK] Validata e attiva: {username}"); -Log("[BROWSER] WebView2 inizializzato"); -``` - -**Errori**: -```csharp -Log($"[ERROR] Inizializzazione fallita: {ex.Message}"); -Log("[WARN] Timeout attesa WebView2"); -``` - -**Istruzioni**: -```csharp -Log("[INFO] Per accedere:"); -Log("[INFO] 1. Click su..."); -``` - ---- - -### ? NON LOGGARE - -**Step Interni**: -```csharp -// ? Log("[DEBUG] Chiamata metodo X..."); -// ? Log("[DEBUG] Creazione oggetto Y..."); -``` - -**Dettagli Tecnici**: -```csharp -// ? Log($"[DEBUG] UserDataFolder: {path}"); -// ? Log($"[DEBUG] Cookie presente: {bool}"); -``` - -**Stack Traces Completi**: -```csharp -// ? Log($"[DEBUG] Stack trace: {ex.StackTrace}"); -// ? Log($"[DEBUG] Inner exception: {...}"); -``` - -**Marker Debug**: -```csharp -// ? Log("[DEBUG] Inizio metodo..."); -// ? Log("[DEBUG] Fine metodo..."); -``` - ---- - -**Data Cleanup**: 2025 -**Versione**: 7.4 FINAL -**Righe Debug Rimosse**: ~25 -**Leggibilit**: +300% -**Status**: ? PRODUZIONE READY - -## ?? Riferimenti - -- `Core\MainWindow.WebView.cs` - Log essenziali WebView init -- `Core\MainWindow.UserInfo.cs` - Log essenziali session management - -**Build**: ? Compilazione riuscita -**Test**: ? Funzionalit invariata -**Log**: ? Puliti e professionali - ---- - -## ?? Conclusione - -Il sistema ora **production-ready**: -- ? WebView2 si inizializza correttamente -- ? Auto-login funziona perfettamente -- ? Log puliti e informativi -- ? Nessun debug noise -- ? UX professionale - -**L'applicazione pronta per essere distribuita agli utenti!** ?? diff --git a/Mimante/Documentation/PROJECT_REORGANIZATION.md b/Mimante/Documentation/PROJECT_REORGANIZATION.md deleted file mode 100644 index db4b1ff..0000000 --- a/Mimante/Documentation/PROJECT_REORGANIZATION.md +++ /dev/null @@ -1,363 +0,0 @@ -# 📁 Riorganizzazione Progetto - Riepilogo Finale - -## ✅ Operazioni Completate - -### 1. Creazione Struttura a Cartelle - -#### 📂 Nuove Cartelle Create -``` -✅ Core/ # File principali MainWindow -✅ Core/EventHandlers/ # Event handlers separati -✅ Documentation/ # File markdown documentazione -``` - -#### 📂 Cartelle Già Esistenti (Mantenute) -``` -✅ Controls/ # UserControls WPF -✅ Dialogs/ # Finestre di dialogo -✅ Models/ # Data models -✅ Services/ # Business logic services -✅ ViewModels/ # MVVM ViewModels -✅ Utilities/ # Helper utilities -✅ Data/ # Database contexts -✅ Icon/ # Risorse grafiche -``` - -### 2. Spostamento File - -#### Core/ (8 file spostati) -- ✅ `MainWindow.Commands.cs` -- ✅ `MainWindow.AuctionManagement.cs` -- ✅ `MainWindow.Logging.cs` -- ✅ `MainWindow.UIUpdates.cs` -- ✅ `MainWindow.UrlParsing.cs` -- ✅ `MainWindow.UserInfo.cs` -- ✅ `MainWindow.ButtonHandlers.cs` -- ✅ `MainWindow.ControlEvents.cs` - -#### Core/EventHandlers/ (5 file spostati) -- ✅ `MainWindow.EventHandlers.cs` -- ✅ `MainWindow.EventHandlers.Browser.cs` -- ✅ `MainWindow.EventHandlers.Export.cs` -- ✅ `MainWindow.EventHandlers.Settings.cs` -- ✅ `MainWindow.EventHandlers.Stats.cs` - -#### Documentation/ (6 file spostati) -- ✅ `REFACTORING_SUMMARY.md` -- ✅ `XAML_REFACTORING_SUMMARY.md` -- ✅ `ARCHITECTURE_OVERVIEW.md` -- ✅ `XAML_REFACTORING_CHECKLIST.md` -- ✅ `CHANGELOG.md` -- ✅ `PROJECT_REORGANIZATION.md` (questo file) - -### 3. File Creati - -#### Root Directory -- ✅ `README.md` - Overview completo progetto -- ✅ `.gitignore` - File da ignorare nel VCS (ESSENZIALE per Git) - -### 4. File Eliminati (Non Necessari) - -#### ❌ Rimossi -- ~~`.editorconfig`~~ - Non necessario (Visual Studio ha già le sue impostazioni) -- ~~`.vscode/extensions.json`~~ - Non necessario (si usa Visual Studio, non VS Code) -- ~~`.vscode/` folder~~ - Cartella vuota rimossa - -**Motivo**: Semplificazione del progetto, mantenendo solo i file essenziali per il workflow di sviluppo. - -### 5. File Rimasti nella Root (Essenziali) - -#### File Principali -- ✅ `MainWindow.xaml` - UI principale (deve stare in root) -- ✅ `MainWindow.xaml.cs` - Code-behind principale (deve stare in root) -- ✅ `App.xaml` - Application entry point -- ✅ `App.xaml.cs` - Application code-behind -- ✅ `AssemblyInfo.cs` - Assembly metadata -- ✅ `AutoBidder.csproj` - File progetto -- ✅ `README.md` - Documentazione overview -- ✅ `.gitignore` - **ESSENZIALE** per Git (protegge da commit indesiderati) - -## 📊 Statistiche Riorganizzazione - -### Prima della Riorganizzazione -``` -Root Directory: 18 file C#/XAML + 5 file MD -├── File difficili da trovare -├── Nessuna categorizzazione -└── Documentazione mista con codice -``` - -### Dopo la Riorganizzazione -``` -Root Directory: 8 file essenziali -├── Core/: 8 file partial classes -├── Core/EventHandlers/: 5 file event handlers -├── Controls/: 5 UserControls -├── Dialogs/: 3 dialog windows -├── Models/: 12 data models -├── Services/: 5 servizi -├── ViewModels/: 1 ViewModel -├── Utilities/: 6 utilities -├── Data/: 1 context -├── Documentation/: 6 file markdown -└── Icon/: 1 risorsa grafica -``` - -### Metriche -| Metrica | Prima | Dopo | Miglioramento | -|---------|-------|------|---------------| -| File root directory | 23 | 8 | **-65%** | -| Cartelle logiche | 6 | 10 | +67% | -| File configurazione | 3 | 1 | **-67%** | -| File per cartella media | 8 | 4 | -50% | - -## 🎯 Benefici della Riorganizzazione - -### ✅ Navigabilità -- **Prima**: Cercare file tra 20+ nella root -- **Dopo**: Struttura logica per categoria - -### ✅ Manutenibilità -- **Prima**: Difficile capire dipendenze -- **Dopo**: Separazione chiara delle responsabilità - -### ✅ Semplicità -- **Prima**: File di configurazione inutili (.editorconfig, .vscode) -- **Dopo**: Solo file essenziali per il progetto - -### ✅ Scalabilità -- **Prima**: Aggiungere file complica la root -- **Dopo**: Struttura estendibile con nuove cartelle - -### ✅ Onboarding -- **Prima**: Developer deve esplorare tutti i file -- **Dopo**: README + struttura guidano l'esplorazione - -## 📐 Struttura Finale - -``` -AutoBidder/ -│ -├── 📁 Core/ # 🔵 PRINCIPALE -│ ├── MainWindow.Commands.cs # Comandi WPF -│ ├── MainWindow.AuctionManagement.cs # Gestione aste -│ ├── MainWindow.Logging.cs # Sistema logging -│ ├── MainWindow.UIUpdates.cs # Aggiornamenti UI -│ ├── MainWindow.UrlParsing.cs # Parsing URL -│ ├── MainWindow.UserInfo.cs # Info utente -│ ├── MainWindow.ButtonHandlers.cs # Click handlers -│ ├── MainWindow.ControlEvents.cs # Event routing -│ └── 📁 EventHandlers/ -│ ├── MainWindow.EventHandlers.cs -│ ├── MainWindow.EventHandlers.Browser.cs -│ ├── MainWindow.EventHandlers.Export.cs -│ ├── MainWindow.EventHandlers.Settings.cs -│ └── MainWindow.EventHandlers.Stats.cs -│ -├── 📁 Controls/ # 🟢 UI COMPONENTS -├── 📁 Dialogs/ # 🟡 DIALOGS -├── 📁 Models/ # 🟣 DATA MODELS -├── 📁 Services/ # 🔴 BUSINESS LOGIC -├── 📁 ViewModels/ # 🟠 MVVM -├── 📁 Utilities/ # ⚫ HELPERS -├── 📁 Data/ # 🟤 DATABASE -├── 📁 Documentation/ # 📘 DOCS -├── 📁 Icon/ # 🎨 RESOURCES -│ -├── MainWindow.xaml # 🏠 MAIN UI -├── MainWindow.xaml.cs # 🏠 MAIN CODE -├── App.xaml # 🚀 APP ENTRY -├── App.xaml.cs # 🚀 APP CODE -├── AssemblyInfo.cs # ℹ️ METADATA -├── AutoBidder.csproj # 📦 PROJECT -├── README.md # 📖 OVERVIEW -└── .gitignore # 🚫 VCS IGNORE (ESSENZIALE) -``` - -## 🔧 Modifiche al Build System - -### File .csproj -- ✅ Nessuna modifica necessaria (SDK-style usa glob pattern impliciti) -- ✅ I file nelle sottocartelle sono automaticamente inclusi -- ✅ Namespace corretti generati automaticamente - -### Compilazione -```bash -# Test compilazione -dotnet build -# ✅ Compilazione riuscita -# ✅ 0 Errori -# ✅ 0 Warning -``` - -## 📚 Documentazione Aggiornata - -### File nella Cartella Documentation/ -1. **REFACTORING_SUMMARY.md** - - Dettagli refactoring code-behind - - Partial classes organization - -2. **XAML_REFACTORING_SUMMARY.md** - - Dettagli refactoring XAML - - UserControls modulari - -3. **ARCHITECTURE_OVERVIEW.md** - - Overview architettura software - - Pattern utilizzati - -4. **XAML_REFACTORING_CHECKLIST.md** - - Checklist implementazione - - Testing guide - -5. **CHANGELOG.md** - - Storico versioni - - Breaking changes - - Roadmap futura - -6. **PROJECT_REORGANIZATION.md** (questo file) - - Guida alla riorganizzazione - - Decisioni architetturali - -### File nella Root -1. **README.md** - - Overview progetto - - Setup instructions - - Struttura completa - -2. **.gitignore** - - Pattern Visual Studio - - File build artifacts - - File sensibili (DB, config, logs) - - **ESSENZIALE** per mantenere repository pulito - -## ✅ Checklist Verifica - -### Build & Runtime -- ✅ Compilazione riuscita -- ✅ Nessun warning -- ✅ Tutti i namespace corretti -- ✅ Partial classes funzionanti -- ✅ UserControls caricati -- ✅ Event routing funzionante - -### Struttura Progetto -- ✅ Cartelle logiche create -- ✅ File spostati correttamente -- ✅ Root directory pulita (solo 8 file essenziali) -- ✅ Documentazione organizzata -- ✅ File non necessari rimossi - -### Documentazione -- ✅ README completo e aggiornato -- ✅ CHANGELOG dettagliato -- ✅ .gitignore essenziale mantenuto -- ✅ File di configurazione IDE rimossi - -## 🎉 Risultato Finale - -### Prima -``` -📁 AutoBidder/ - ├── 📄 MainWindow.xaml - ├── 📄 MainWindow.xaml.cs - ├── 📄 MainWindow.Commands.cs - ├── 📄 MainWindow.AuctionManagement.cs - ├── 📄 MainWindow.EventHandlers.cs - ├── ... (18+ file nella root) ... - ├── 📄 README.md - ├── 📄 .editorconfig (inutile) - ├── 📄 .vscode/ (inutile) - └── ... (difficile navigare) ... -``` - -### Dopo -``` -📁 AutoBidder/ - ├── 📁 Core/ (13 file organizzati) - ├── 📁 Controls/ (5 UserControls) - ├── 📁 Models/ (12 modelli) - ├── 📁 Services/ (5 servizi) - ├── 📁 Documentation/ (6 markdown) - ├── 📄 MainWindow.xaml - ├── 📄 MainWindow.xaml.cs - ├── 📄 App.xaml - ├── 📄 README.md - ├── 📄 .gitignore (ESSENZIALE) - └── ... (8 file essenziali) ✨ -``` - -## 💡 Filosofia "Less is More" - -### Decisioni Architetturali - -#### ✅ MANTENUTO: `.gitignore` -**Motivo**: -- Protegge il repository da commit indesiderati -- Ignora file temporanei: `bin/`, `obj/`, `.vs/` -- Protegge dati sensibili: `app_settings.json`, `stats.db` -- Previene bloat nel repo con file utente -- **ESSENZIALE per workflow Git pulito** - -#### ❌ RIMOSSO: `.editorconfig` -**Motivo**: -- Visual Studio ha già impostazioni di formattazione integrate -- Non lavori in team con IDE diversi -- Aggiunge complessità senza benefici reali -- Le convenzioni sono già definite nel README - -#### ❌ RIMOSSO: `.vscode/extensions.json` -**Motivo**: -- Usi Visual Studio 2022, non VS Code -- File specifico per un IDE che non usi -- Nessun valore aggiunto al progetto - -### Principio Guida -> **"Un progetto dovrebbe contenere solo ciò che serve, niente di più"** - -## 🚀 Prossimi Passi - -1. **Git Commit** - ```bash - git add . - git commit -m "refactor: Riorganizzazione finale + Pulizia file non necessari - - - Struttura cartelle logiche (Core, Documentation) - - 13 partial classes MainWindow organizzate - - 5 UserControls modulari - - Layout dashboard con GridSplitters - - Documentazione completa (6 file MD) - - Rimossi .editorconfig e .vscode/ (non necessari) - - Mantenuto solo .gitignore (essenziale)" - - git push origin main - ``` - -2. **Testing Completo** - - ✅ Avvio applicazione - - ✅ Navigazione tra tab - - ✅ Funzionalità core - -3. **Deployment** - - Publish per produzione - - Installer creation - ---- - -## 🎊 **PROGETTO FINALIZZATO!** - -L'applicazione AutoBidder v4.0 ora ha: -- ✅ **Architettura pulita e scalabile** -- ✅ **UI moderna con dashboard professionale** -- ✅ **Documentazione completa e organizzata** -- ✅ **Solo file essenziali (no bloat)** -- ✅ **Build ottimizzato** -- ✅ **Repository Git pulito** - -**Pronto per produzione!** 🚀✨ - ---- - -**Data**: 2024 -**Stato**: ✅ **COMPLETATO E OTTIMIZZATO** -**Compilazione**: ✅ **SUCCESSO** -**File Root**: 📊 **8 ESSENZIALI** (-65% rispetto a prima) diff --git a/Mimante/Documentation/REFACTORING_BROWSER_ADDRESS_BAR.md b/Mimante/Documentation/REFACTORING_BROWSER_ADDRESS_BAR.md deleted file mode 100644 index 61cb162..0000000 --- a/Mimante/Documentation/REFACTORING_BROWSER_ADDRESS_BAR.md +++ /dev/null @@ -1,563 +0,0 @@ -# ?? Refactoring: Browser Address Bar Fix - -## ?? Problema Identificato - -**Sintomo**: L'indirizzo URL nella address bar del browser non si aggiorna quando navigo nelle pagine. - -### Causa Radice - -Il problema era un'architettura frammentata della gestione eventi WebView2: - -``` -WebView2 (XAML) - ?? NavigationStarting/Completed eventi nel XAML - ?? Handler nel BrowserControl.xaml.cs - ?? Propagano eventi custom al MainWindow - ?? MainWindow.EventHandlers.Browser.cs - ?? Aggiorna BrowserAddress.Text -``` - -**Problemi architetturali**: -1. ? Eventi WebView2 nel XAML che chiamano stub nel code-behind -2. ? Stub che ripropaano eventi custom -3. ? MainWindow che deve ascoltare eventi custom -4. ? Troppi livelli di indirezione -5. ? Address bar aggiornato solo dal MainWindow (non dal Control) - ---- - -## ? Soluzione: Gestione Locale Diretta - -### Nuovo Flusso Semplificato - -``` -WebView2 (CONTROLLO) - ?? NavigationStarting/Completed eventi collegati nel constructor - ?? WebView_NavigationStarting() - ?? Aggiorna BrowserAddress.Text ? (LOCALE, IMMEDIATO) - ?? Propaga evento al MainWindow (opzionale) - ?? WebView_NavigationCompleted() - ?? Aggiorna BrowserAddress.Text ? (LOCALE, IMMEDIATO) - ?? Propaga evento al MainWindow (opzionale) -``` - -**Vantaggi**: -- ? **Address bar aggiornato localmente** dal control stesso -- ? **Immediato**: Nessuna attesa propagazione eventi -- ? **Indipendente**: Funziona anche se MainWindow non ascolta -- ? **Semplice**: Un solo posto dove aggiornare l'address bar -- ? **Robusto**: Meno livelli = meno punti di fallimento - ---- - -## ?? Implementazione - -### File: `Controls\BrowserControl.xaml.cs` - -#### Constructor: Collega Eventi Direttamente - -```csharp -public BrowserControl() -{ - InitializeComponent(); - - // ? NUOVO: Collega eventi NavigationStarting e NavigationCompleted direttamente qui - EmbeddedWebView.NavigationStarting += WebView_NavigationStarting; - EmbeddedWebView.NavigationCompleted += WebView_NavigationCompleted; -} -``` - -**Prima** ?: -- Eventi collegati nel XAML -- Handler che solo ri-propagavano l'evento -- Address bar NON aggiornato localmente - -**Dopo** ?: -- Eventi collegati nel constructor -- Handler che AGGIORNA l'address bar + propaga evento -- Address bar sempre aggiornato - ---- - -#### Handler: WebView_NavigationStarting - -```csharp -/// -/// ? NUOVO: Aggiorna address bar quando inizia la navigazione -/// -private void WebView_NavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs e) -{ - try - { - // ? CHIAVE: Aggiorna immediatamente l'address bar con l'URL di destinazione - if (!string.IsNullOrEmpty(e.Uri)) - { - BrowserAddress.Text = e.Uri; - } - - // Propaga l'evento al MainWindow (per altre logiche) - var args = new BrowserNavigationEventArgs(BrowserNavigationStartingEvent, this) - { - Uri = e.Uri - }; - RaiseEvent(args); - } - catch { } -} -``` - -**Ordine delle operazioni**: -1. ? **PRIMA**: Aggiorna address bar (locale, immediato) -2. ? **POI**: Propaga evento al MainWindow (se serve) - -**Prima** ?: -- Solo propagava evento -- MainWindow doveva aggiornare l'address bar -- Se MainWindow non ascoltava ? nessun aggiornamento - -**Dopo** ?: -- Aggiorna address bar subito -- Propaga evento (opzionale) -- Funziona sempre, indipendentemente da MainWindow - ---- - -#### Handler: WebView_NavigationCompleted - -```csharp -/// -/// ? NUOVO: Aggiorna address bar quando la navigazione completata -/// -private void WebView_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e) -{ - try - { - // ? CHIAVE: Aggiorna l'address bar con l'URL finale (dopo eventuali redirect) - var finalUrl = EmbeddedWebView?.Source?.ToString(); - if (!string.IsNullOrEmpty(finalUrl)) - { - BrowserAddress.Text = finalUrl; - } - - // Propaga l'evento al MainWindow (per altre logiche) - RaiseEvent(new RoutedEventArgs(BrowserNavigationCompletedEvent, this)); - } - catch { } -} -``` - -**Perch aggiornare in entrambi gli eventi?** - -1. **`NavigationStarting`**: - - Mostra subito dove stai andando - - Feedback immediato all'utente - - Es: Click link ? URL appare subito - -2. **`NavigationCompleted`**: - - Mostra URL finale dopo redirect - - Gestisce URL dinamici - - Es: Redirect da short URL ? URL finale - ---- - -### File: `Controls\BrowserControl.xaml` - -#### XAML: Rimozione Binding Eventi - -```xaml - - - - - -``` - -**Perch rimuovere dal XAML?** - -| Evento | Dove collegare | Motivo | -|--------|----------------|--------| -| NavigationStarting | Constructor C# | Serve access a BrowserAddress (campo privato) | -| NavigationCompleted | Constructor C# | Serve access a BrowserAddress (campo privato) | -| PreviewMouseRightButtonUp | XAML | Semplice handler, non serve stato | - -**Regola generale**: -- XAML: Eventi semplici senza accesso a stato interno -- Constructor: Eventi che manipolano campi del control - ---- - -## ?? Confronto Prima/Dopo - -### Scenario 1: Navigazione Link - -**Prima** ?: -``` -1. Click su link -2. WebView2.NavigationStarting -3. EmbeddedWebView_NavigationStarting() [XAML handler] -4. Propaga BrowserNavigationStartingEvent -5. MainWindow riceve evento? -6. MainWindow aggiorna BrowserAddress? ? FALLISCE -7. Address bar NON aggiornato ? -``` - -**Dopo** ?: -``` -1. Click su link -2. WebView2.NavigationStarting -3. WebView_NavigationStarting() -4. BrowserAddress.Text = e.Uri ? AGGIORNATO SUBITO -5. Propaga BrowserNavigationStartingEvent (opzionale) -6. Address bar mostra nuovo URL ? -``` - ---- - -### Scenario 2: Redirect - -**Prima** ?: -``` -1. Vai su https://short.url/abc -2. NavigationStarting: short.url - ?? Address bar non aggiornato ? -3. Server redirect ? https://it.bidoo.com/auction.php?a=asta_12345 -4. NavigationCompleted: it.bidoo.com/... - ?? Address bar non aggiornato ? -5. Risultato: Address bar vuoto o vecchio ? -``` - -**Dopo** ?: -``` -1. Vai su https://short.url/abc -2. NavigationStarting: short.url - ?? BrowserAddress.Text = "https://short.url/abc" ? -3. Server redirect ? https://it.bidoo.com/auction.php?a=asta_12345 -4. NavigationCompleted: it.bidoo.com/... - ?? BrowserAddress.Text = "https://it.bidoo.com/auction.php?a=asta_12345" ? -5. Risultato: Address bar mostra URL finale ? -``` - ---- - -### Scenario 3: Pulsanti Navigazione - -**Prima** ?: -``` -1. Click "Indietro" -2. MainWindow.BrowserBackButton_Click() -3. EmbeddedWebView.GoBack() -4. NavigationStarting ? NavigationCompleted -5. Address bar non aggiornato ? -``` - -**Dopo** ?: -``` -1. Click "Indietro" -2. MainWindow.BrowserBackButton_Click() -3. EmbeddedWebView.GoBack() -4. NavigationStarting ? BrowserAddress.Text aggiornato ? -5. NavigationCompleted ? BrowserAddress.Text confermato ? -6. Address bar mostra pagina precedente ? -``` - ---- - -## ?? Architettura Prima/Dopo - -### Prima ?: Frammentata - -``` -??????????????????????????????????????????????????? -? BrowserControl.xaml ? -? ? -? ? -? ? -? ? -??????????????????????????????????????????????????? - ? (eventi XAML) -??????????????????????????????????????????????????? -? BrowserControl.xaml.cs ? -? ? -? EmbeddedWebView_NavigationStarting() ? -? { ? -? RaiseEvent(BrowserNavigationStartingEvent); ? -? } ? -? ? NON aggiorna BrowserAddress ? -??????????????????????????????????????????????????? - ? (custom event) -??????????????????????????????????????????????????? -? MainWindow.EventHandlers.Browser.cs ? -? ? -? EmbeddedWebView_NavigationStarting(...) ? -? { ? -? BrowserAddress.Text = e.Uri; ? -? } ? -? ? MA non viene chiamato! ? -??????????????????????????????????????????????????? -``` - -**Problemi**: -- 3 livelli di indirezione -- Address bar aggiornato solo se tutto funziona -- Facile che qualcosa si rompa - ---- - -### Dopo ?: Semplificata - -``` -??????????????????????????????????????????????????? -? BrowserControl.xaml.cs ? -? ? -? Constructor() ? -? { ? -? EmbeddedWebView.NavigationStarting += ? -? WebView_NavigationStarting; ? -? } ? -? ? -? WebView_NavigationStarting(...) ? -? { ? -? BrowserAddress.Text = e.Uri; ? LOCALE ? -? RaiseEvent(...); // opzionale ? -? } ? -??????????????????????????????????????????????????? -``` - -**Vantaggi**: -- 1 livello: diretto -- Address bar sempre aggiornato -- Indipendente da MainWindow - ---- - -## ?? Pattern Architetturale - -### Principio: Self-Contained Controls - -**Regola**: Un UserControl dovrebbe gestire il suo stato interno autonomamente. - -```csharp -// ? SBAGLIATO: Control dipende da parent per funzionare -public class BrowserControl : UserControl -{ - // Address bar aggiornato dal parent - // Se parent non ascolta ? address bar non funziona -} - -// ? CORRETTO: Control autonomo -public class BrowserControl : UserControl -{ - // Address bar aggiornato localmente - // Funziona indipendentemente dal parent - - private void WebView_NavigationStarting(...) - { - // 1. Gestisci stato interno - BrowserAddress.Text = e.Uri; - - // 2. Notifica parent (opzionale) - RaiseEvent(...); - } -} -``` - -**Ordine priorit**: -1. **Prima**: Aggiorna stato interno del control -2. **Poi**: Notifica parent se necessario -3. **Mai**: Dipendere dal parent per funzionare - ---- - -## ? Benefici del Refactoring - -### 1. Semplicit -- **Prima**: 3 classi coinvolte, 5 metodi -- **Dopo**: 1 classe, 2 metodi - -### 2. Affidabilit -- **Prima**: Funziona solo se MainWindow ascolta eventi -- **Dopo**: Funziona sempre - -### 3. Manutenibilit -- **Prima**: Modifiche richiedono aggiornamento in 3 posti -- **Dopo**: Modifiche centralizzate in BrowserControl - -### 4. Testabilit -- **Prima**: Difficile testare (dipendenze nascoste) -- **Dopo**: Facile testare (control autonomo) - -### 5. Performance -- **Prima**: 3 chiamate per aggiornare address bar -- **Dopo**: 1 chiamata diretta - ---- - -## ?? Test di Verifica - -### Test 1: Navigazione Iniziale ? - -**Steps**: -1. Apri scheda Browser -2. Attendi caricamento -3. **Verifica**: Address bar mostra "https://it.bidoo.com/" - -**Risultato atteso**: ? URL visibile - ---- - -### Test 2: Click Link ? - -**Steps**: -1. Scheda Browser aperta -2. Click su link asta -3. **Verifica**: Address bar si aggiorna immediatamente - -**Risultato atteso**: ? Nuovo URL appare subito - ---- - -### Test 3: Pulsante Indietro ? - -**Steps**: -1. Naviga su 2-3 pagine -2. Click "Indietro" -3. **Verifica**: Address bar mostra pagina precedente - -**Risultato atteso**: ? URL aggiornato correttamente - ---- - -### Test 4: Redirect ? - -**Steps**: -1. Vai su URL con redirect -2. **Verifica**: Address bar mostra prima URL temporaneo, poi URL finale - -**Risultato atteso**: ? Due aggiornamenti visibili - ---- - -### Test 5: Pulsante "Aggiungi Asta" ? - -**Steps**: -1. Naviga su un'asta -2. **Verifica**: Address bar mostra URL asta -3. Click "Aggiungi Asta" -4. **Verifica**: Asta aggiunta con URL corretto - -**Risultato atteso**: ? URL letto correttamente dall'address bar - ---- - -## ?? Lezioni Apprese - -### 1. Event Handling in WPF - -**Quando collegare eventi**: -- ? XAML: Eventi semplici, nessuna logica complessa -- ? Constructor: Eventi che accedono a stato privato -- ? Mai: Eventi che dipendono da timing specifico - -### 2. UserControl Design - -**Self-Contained Pattern**: -```csharp -public class MyControl : UserControl -{ - // ? Gestisci il tuo stato - private void UpdateInternalState() { ... } - - // ? Notifica parent (opzionale) - private void NotifyParent() { RaiseEvent(...); } - - // ? Non dipendere dal parent per funzionare -} -``` - -### 3. Event Propagation - -**Ordine corretto**: -1. Aggiorna stato locale -2. Propaga evento -3. Parent riceve (se ascolta) - -**Non fare**: -1. Propaga evento -2. Parent aggiorna stato del control ? - -### 4. Debugging Event Flow - -**Come diagnosticare**: -```csharp -private void WebView_NavigationStarting(...) -{ - System.Diagnostics.Debug.WriteLine($"[NAV] Starting: {e.Uri}"); - BrowserAddress.Text = e.Uri; - System.Diagnostics.Debug.WriteLine($"[NAV] Address bar updated to: {BrowserAddress.Text}"); -} -``` - ---- - -## ?? File Modificati - -### 1. `Controls\BrowserControl.xaml.cs` - -**Modifiche**: -- ? Aggiunto collegamento eventi nel constructor -- ? Aggiunto `WebView_NavigationStarting()` con aggiornamento address bar -- ? Aggiunto `WebView_NavigationCompleted()` con aggiornamento address bar -- ? Mantenuti stub XAML per compatibilit (vuoti) - -**Righe modificate**: ~30 righe - ---- - -### 2. `Controls\BrowserControl.xaml` - -**Modifiche**: -- ? Rimossi binding `NavigationStarting` e `NavigationCompleted` -- ? Mantenuto binding `PreviewMouseRightButtonUp` - -**Righe modificate**: 2 righe - ---- - -## ? Conclusione - -### Problema Risolto ? -**Address bar ora si aggiorna correttamente ad ogni navigazione** - -### Architettura Migliorata ? -- Pi semplice (1 livello vs 3) -- Pi robusta (indipendente) -- Pi manutenibile (centralizzata) - -### Pattern Applicato ? -**Self-Contained Controls**: Ogni control gestisce il proprio stato autonomamente - -### Build Status ? -Compilazione riuscita senza errori o warning - ---- - -**Data Refactoring**: 2025 -**Versione**: 5.6+ -**Issue**: Address bar non si aggiorna -**Causa**: Architettura frammentata con troppi livelli -**Soluzione**: Gestione locale diretta nel BrowserControl -**Status**: ? RISOLTO - -## ?? Riferimenti - -- `Controls\BrowserControl.xaml.cs` - Refactored -- `Controls\BrowserControl.xaml` - XAML pulito -- Pattern: Self-Contained UserControls -- Principio: Update Local State First diff --git a/Mimante/Documentation/REFACTORING_COOKIE_DETECTION_TIMING.md b/Mimante/Documentation/REFACTORING_COOKIE_DETECTION_TIMING.md deleted file mode 100644 index ae5d1e6..0000000 --- a/Mimante/Documentation/REFACTORING_COOKIE_DETECTION_TIMING.md +++ /dev/null @@ -1,802 +0,0 @@ -# ?? Refactoring: Sistema Cookie Detection & Auto-Login - -## ?? Problema Originale - -### Log Sintomatico - -``` -[17:30:53] [SESSION] Nessuna sessione salvata -[17:30:53] [BROWSER] Inizializzazione WebView2 in background... -[17:30:55] [INFO] Per accedere: ? ? Mostrato dopo 2 secondi -[17:30:55] [INFO] 1. Click su 'Non connesso'... -[17:31:43] [BROWSER] WebView2 inizializzato ? ? Pronta dopo 50 secondi! -[17:31:45] [BROWSER] Login rilevato -[17:31:45] [SESSION OK] Validata e attiva -``` - -### Analisi Root Cause - -**Timing Sbagliato**: -``` -17:30:53 ? LoadSavedSession() - ? - Task.Run(() => { - await Task.Delay(2000); ? ? Aspetta solo 2 secondi - ? - await GetCookieFromWebView(); ? ? WebView NON ancora pronta! - ? - "Nessun cookie" ? Mostra istruzioni - }) - -17:31:43 ? WebView finalmente pronta (50 secondi dopo!) - ? - CheckAndImportCookie() ? ? Importazione riuscita -``` - -**Problema**: La verifica cookie avviene **prima** che WebView sia pronta. - ---- - -## ? Soluzione: Attesa Intelligente con TaskCompletionSource - -### Pattern Implementato - -``` -Avvio App - ? -LoadSavedSession() - ?? Sessione salvata valida? ? Verifica + Aggiorna UI - ?? Sessione scaduta/assente? - ? - CheckBrowserCookieAfterWebViewReady() - ? - WaitForWebViewInitAsync(60 secondi) ? ? ATTENDE finch pronta - ? - WebView pronta? - ?? S ? GetCookieFromWebView() - ? ?? Cookie presente? ? Importazione automatica - ? ?? Cookie assente? ? Mostra istruzioni - ?? No (timeout) ? Mostra istruzioni -``` - ---- - -## ?? Modifiche Implementate - -### 1?? MainWindow.WebView.cs - Segnalazione Completamento - -**File**: `Core\MainWindow.WebView.cs` - -#### Nuovo Campo - -```csharp -private TaskCompletionSource? _webViewInitCompletionSource; -``` - -**Scopo**: Permette ad altri thread di **aspettare** che WebView sia pronta. - -#### InitializeWebView2() - BEFORE ? - -```csharp -private async void InitializeWebView2() -{ - await EmbeddedWebView.EnsureCoreWebView2Async(null); - - if (EmbeddedWebView.CoreWebView2 != null) - { - _isWebViewInitialized = true; - EmbeddedWebView.CoreWebView2.Navigate("https://it.bidoo.com"); - Log("[BROWSER] WebView2 inizializzato", LogLevel.Success); - - // Registra evento - EmbeddedWebView.CoreWebView2.NavigationCompleted += OnWebViewNavigationCompleted; - } -} -``` - -#### InitializeWebView2() - AFTER ? - -```csharp -private async void InitializeWebView2() -{ - try - { - await Task.Delay(500); - await EmbeddedWebView.EnsureCoreWebView2Async(null); - - if (EmbeddedWebView.CoreWebView2 != null) - { - _isWebViewInitialized = true; - EmbeddedWebView.CoreWebView2.Navigate("https://it.bidoo.com"); - Log("[BROWSER] WebView2 inizializzato e pre-caricato", LogLevel.Success); - - EmbeddedWebView.CoreWebView2.NavigationCompleted += OnWebViewNavigationCompleted; - - // ? NUOVO: Notifica che WebView pronta - _webViewInitCompletionSource?.TrySetResult(true); - - // ? NUOVO: Verifica immediata cookie - await CheckAndImportCookieIfAvailable(); - } - else - { - _webViewInitCompletionSource?.TrySetResult(false); - } - } - catch (Exception ex) - { - Log($"[WARN] Inizializzazione fallita: {ex.Message}", LogLevel.Warn); - _webViewInitCompletionSource?.TrySetResult(false); - } -} -``` - -**Cambiamenti**: -1. ? Notifica completamento via `TaskCompletionSource` -2. ? Verifica cookie immediata dopo init -3. ? Gestione errori con notifica fallimento - ---- - -#### Nuovo Metodo: CheckAndImportCookieIfAvailable() - -```csharp -/// -/// Verifica e importa cookie se disponibile -/// -private async Task CheckAndImportCookieIfAvailable() -{ - try - { - // Aspetta che pagina sia caricata - await Task.Delay(1000); - - var cookie = await GetCookieFromWebView(); - - if (!string.IsNullOrEmpty(cookie)) - { - var currentSession = _sessionService?.GetCurrentSession(); - - // Importa solo se diverso da quello salvato - if (currentSession == null || - string.IsNullOrEmpty(currentSession.CookieString) || - !currentSession.CookieString.Contains(cookie)) - { - Log("[BROWSER] Cookie rilevato - importazione automatica...", LogLevel.Info); - await AutoImportCookieFromWebView(cookie); - } - } - } - catch (Exception ex) - { - Log($"[DEBUG] Verifica cookie fallita: {ex.Message}", LogLevel.Info); - } -} -``` - -**Scopo**: -- Verifica presenza cookie nel browser -- Importa automaticamente se trovato -- Non duplica importazione se gi presente - ---- - -#### Nuovo Metodo: WaitForWebViewInitAsync() - -```csharp -/// -/// Aspetta che WebView sia inizializzata (con timeout) -/// -private async Task WaitForWebViewInitAsync(int timeoutSeconds = 60) -{ - if (_isWebViewInitialized) - return true; - - _webViewInitCompletionSource = new TaskCompletionSource(); - - // Timeout di 60 secondi - var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds)); - var completedTask = await Task.WhenAny(_webViewInitCompletionSource.Task, timeoutTask); - - if (completedTask == timeoutTask) - { - Log("[WARN] Timeout attesa inizializzazione WebView2", LogLevel.Warn); - return false; - } - - return await _webViewInitCompletionSource.Task; -} -``` - -**Utilizzo**: -```csharp -// Aspetta che WebView sia pronta (max 60 secondi) -var ready = await WaitForWebViewInitAsync(60); - -if (ready) -{ - // WebView pronta, posso accedere ai cookie - var cookie = await GetCookieFromWebView(); -} -else -{ - // Timeout - WebView non si inizializzata -} -``` - ---- - -#### Semplificato: OnWebViewNavigationCompleted() - -**BEFORE** ?: -```csharp -private async void OnWebViewNavigationCompleted(...) -{ - var url = EmbeddedWebView.CoreWebView2.Source; - - if (url.Contains("bidoo.com") && !url.Contains("login")) - { - var cookie = await GetCookieFromWebView(); - - if (!string.IsNullOrEmpty(cookie)) - { - var currentSession = _sessionService?.GetCurrentSession(); - - if (currentSession == null || ...) - { - Log("[BROWSER] Login rilevato - importazione..."); - await AutoImportCookieFromWebView(cookie); - } - } - } -} -``` - -**AFTER** ?: -```csharp -private async void OnWebViewNavigationCompleted(...) -{ - if (!e.IsSuccess || EmbeddedWebView?.CoreWebView2 == null) - return; - - var url = EmbeddedWebView.CoreWebView2.Source; - - if (url.Contains("bidoo.com") && !url.Contains("login")) - { - // ? REFACTORED: Delega a metodo centrale - await CheckAndImportCookieIfAvailable(); - } -} -``` - -**Benefici**: -- Codice duplicato eliminato -- Logica centralizzata in `CheckAndImportCookieIfAvailable()` -- Pi facile da mantenere - ---- - -### 2?? MainWindow.UserInfo.cs - Attesa Intelligente - -**File**: `Core\MainWindow.UserInfo.cs` - -#### LoadSavedSession() - BEFORE ? - -```csharp -private void LoadSavedSession() -{ - var session = _sessionService?.GetCurrentSession(); - - if (session == null) - { - Log("[SESSION] Nessuna sessione salvata"); - - // ? PROBLEMA: Attesa fissa 2 secondi - Task.Run(async () => - { - await Task.Delay(2000); // ? WebView NON ancora pronta! - - await Dispatcher.InvokeAsync(async () => - { - var cookie = await GetCookieFromWebView(); - - if (string.IsNullOrEmpty(cookie)) - { - Log("[INFO] Per accedere:"); - // ...istruzioni - } - }); - }); - } -} -``` - -#### LoadSavedSession() - AFTER ? - -```csharp -private void LoadSavedSession() -{ - var session = _sessionService?.GetCurrentSession(); - - if (session != null && session.IsValid) - { - // Ripristina sessione + verifica validit - // ... - } - else - { - Log("[SESSION] Nessuna sessione salvata"); - - // ? NUOVO: Attende WebView pronta prima di verificare - CheckBrowserCookieAfterWebViewReady(); - - SetUserBanner(string.Empty, 0); - } -} -``` - ---- - -#### Nuovo Metodo: CheckBrowserCookieAfterWebViewReady() - -```csharp -/// -/// Attende che WebView sia pronta, poi verifica presenza cookie -/// -private void CheckBrowserCookieAfterWebViewReady() -{ - Task.Run(async () => - { - try - { - // ? CHIAVE: Aspetta che WebView sia inizializzata (max 60 secondi) - Log("[DEBUG] Attesa inizializzazione WebView...", LogLevel.Info); - var webViewReady = await WaitForWebViewInitAsync(60); - - if (!webViewReady) - { - // Timeout - mostra istruzioni - await Dispatcher.InvokeAsync(() => - { - Log("[INFO] Per accedere:"); - Log("[INFO] 1. Click su 'Non connesso' nella sidebar"); - // ... - }); - return; - } - - // ? WebView pronta - verifica cookie - await Dispatcher.InvokeAsync(async () => - { - var browserCookie = await GetCookieFromWebView(); - - if (string.IsNullOrEmpty(browserCookie)) - { - // Nessun cookie - mostra istruzioni - Log("[INFO] Per accedere:"); - // ... - } - else - { - // Cookie presente - gi gestito da CheckAndImportCookieIfAvailable - Log("[INFO] Cookie rilevato - importazione in corso..."); - } - }); - } - catch (Exception ex) - { - Log($"[DEBUG] Errore verifica cookie: {ex.Message}"); - } - }); -} -``` - -**Flow**: -``` -CheckBrowserCookieAfterWebViewReady() - ? -WaitForWebViewInitAsync(60) ? Blocca fino a quando WebView pronta - ? -WebView pronta? (dopo 0-60 secondi) - ?? S ? GetCookieFromWebView() - ? ?? Cookie presente? ? Log "importazione in corso" - ? ?? Cookie assente? ? Mostra istruzioni - ?? No (timeout) ? Mostra istruzioni -``` - ---- - -## ?? Flusso Completo Refactorato - -### Scenario 1: Primo Avvio (Browser Gi Loggato) - -``` -17:30:53 ? Avvio App - ? -MainWindow() - ? -LoadSavedSession() - ?? Sessione salvata? No - ?? CheckBrowserCookieAfterWebViewReady() - ? - WaitForWebViewInitAsync(60) - ? [ATTENDE...] - ? -17:31:43 ? WebView pronta! (50 secondi dopo) - ? - GetCookieFromWebView() ? Cookie trovato! - ? - Log: "Cookie rilevato - importazione in corso..." - ? -17:31:45 ? CheckAndImportCookieIfAvailable() - ? - AutoImportCookieFromWebView() - ? - ValidateAndActivateSessionAsync() - ? - SetUserBanner("sirbietole23", 44) - ? - Log: "[SESSION OK] Validata e attiva: sirbietole23, 44 puntate" -``` - -**Risultato**: ? Auto-login automatico **senza** mostrare istruzioni inutili - ---- - -### Scenario 2: Primo Avvio (Browser Pulito) - -``` -17:30:53 ? Avvio App - ? -LoadSavedSession() - ? -CheckBrowserCookieAfterWebViewReady() - ? -WaitForWebViewInitAsync(60) - ? [ATTENDE...] - ? -17:31:43 ? WebView pronta! - ? - GetCookieFromWebView() ? Nessun cookie - ? - Log: "[INFO] Per accedere:" - Log: "[INFO] 1. Click su 'Non connesso'" - Log: "[INFO] 2. Si aprir la scheda Browser" - Log: "[INFO] 3. Fai login su Bidoo" - Log: "[INFO] 4. La connessione sar automatica" -``` - -**Risultato**: ? Istruzioni mostrate **solo** se realmente necessarie - ---- - -### Scenario 3: Sessione Salvata Scaduta - -``` -17:30:53 ? Avvio App - ? -LoadSavedSession() - ?? Sessione salvata? S - ?? Verifica validit... - ? - UpdateUserInfoAsync() ? ? Fallita (cookie scaduto) - ? - Log: "[SESSION] Sessione scaduta" - ? - CheckBrowserCookieAfterWebViewReady() - ? - WaitForWebViewInitAsync(60) - ? [ATTENDE...] - ? -17:31:43 ? WebView pronta! - ? - GetCookieFromWebView() - ?? Cookie nuovo trovato? ? Importazione automatica ? - ?? Nessun cookie? ? Mostra istruzioni -``` - ---- - -## ?? Confronto Prima/Dopo - -### BEFORE ? - -| Aspetto | Comportamento | -|---------|---------------| -| **Timing verifica** | Fissa 2 secondi | -| **WebView pronta?** | No (init 50 sec) | -| **Risultato** | Cookie non trovato | -| **Istruzioni** | Sempre mostrate | -| **Auto-login** | Solo dopo click tab Browser | -| **UX** | Confusa (istruzioni inutili) | - -### AFTER ? - -| Aspetto | Comportamento | -|---------|---------------| -| **Timing verifica** | Attesa intelligente (max 60 sec) | -| **WebView pronta?** | S (attesa fino a ready) | -| **Risultato** | Cookie trovato | -| **Istruzioni** | Solo se necessarie | -| **Auto-login** | Automatico all'avvio | -| **UX** | Chiara e intuitiva | - ---- - -## ?? Benefici del Refactoring - -### 1. Timing Corretto - -**Prima** ?: -``` -Verifica cookie dopo 2 secondi (WebView non pronta) -? Cookie non trovato -? Istruzioni mostrate -? Dopo 50 secondi: WebView pronta -? Cookie trovato -? Auto-login funziona (ma istruzioni gi mostrate) -``` - -**Dopo** ?: -``` -Attende fino a 60 secondi che WebView sia pronta -? WebView pronta dopo 50 secondi -? Cookie trovato -? Auto-login automatico -? Istruzioni NON mostrate -``` - ---- - -### 2. Codice Pi Pulito - -**Eliminato Codice Duplicato**: -- `OnWebViewNavigationCompleted` ? Delega a `CheckAndImportCookieIfAvailable` -- Logica cookie centralizzata -- Pi facile da mantenere - -**Pattern TaskCompletionSource**: -```csharp -// Altri thread possono aspettare WebView pronta -var ready = await WaitForWebViewInitAsync(60); - -if (ready) -{ - // WebView pronta, posso lavorare -} -``` - ---- - -### 3. UX Migliorata - -**Prima** ?: -``` -Utente apre app con browser loggato -? [INFO] Per accedere: 1. Click..., 2. Vai... -? ?? "Ma io sono gi loggato!" -? Dopo 50 secondi: auto-login funziona -? ?? "Perch mi hai detto di fare login?!" -``` - -**Dopo** ?: -``` -Utente apre app con browser loggato -? [DEBUG] Attesa inizializzazione WebView... -? ? (attesa 50 secondi) -? [INFO] Cookie rilevato - importazione in corso... -? [SESSION OK] Validata e attiva: username, XX puntate -? ?? "Perfetto, tutto automatico!" -``` - ---- - -### 4. Robustezza - -**Gestione Timeout**: -```csharp -var ready = await WaitForWebViewInitAsync(60); - -if (!ready) -{ - // WebView non pronta dopo 60 secondi - // Mostra istruzioni come fallback -} -``` - -**Gestione Errori**: -```csharp -catch (Exception ex) -{ - Log($"[DEBUG] Errore verifica cookie: {ex.Message}"); - // Non crasha l'app -} -``` - ---- - -## ?? Test di Verifica - -### Test 1: Primo Avvio con Browser Loggato ? - -**Steps**: -1. Cancella sessione salvata -2. Fai login su Bidoo nel browser -3. Chiudi app completamente -4. Riavvia app -5. **NON** cliccare su nessuna tab -6. Aspetta 50-60 secondi -7. Controlla log - -**Log Atteso**: -``` -[17:30:53] [SESSION] Nessuna sessione salvata -[17:30:53] [BROWSER] Inizializzazione WebView2 in background... -[17:30:53] [DEBUG] Attesa inizializzazione WebView... -[17:31:43] [BROWSER] WebView2 inizializzato e pre-caricato -[17:31:45] [INFO] Cookie rilevato - importazione in corso... -[17:31:45] [BROWSER] Cookie rilevato - importazione automatica... -[17:31:45] [SESSION OK] Validata e attiva: username, XX puntate -[17:31:45] [BROWSER] Connessione automatica completata -``` - -**Verificare**: -- ? Nessuna riga "[INFO] Per accedere:" -- ? Auto-login completato entro 60 secondi -- ? Username e puntate mostrate in sidebar - ---- - -### Test 2: Primo Avvio con Browser Pulito ? - -**Steps**: -1. Cancella sessione salvata -2. Pulisci cookie browser -3. Riavvia app -4. Aspetta 60 secondi -5. Controlla log - -**Log Atteso**: -``` -[17:30:53] [SESSION] Nessuna sessione salvata -[17:30:53] [BROWSER] Inizializzazione WebView2 in background... -[17:30:53] [DEBUG] Attesa inizializzazione WebView... -[17:31:43] [BROWSER] WebView2 inizializzato e pre-caricato -[17:31:45] [INFO] Per accedere: -[17:31:45] [INFO] 1. Click su 'Non connesso' nella sidebar -[17:31:45] [INFO] 2. Si aprir la scheda Browser -[17:31:45] [INFO] 3. Fai login su Bidoo -[17:31:45] [INFO] 4. La connessione sar automatica -``` - -**Verificare**: -- ? Istruzioni mostrate **dopo** 50-60 secondi (quando WebView pronta) -- ? Nessun log "Cookie rilevato" -- ? Sidebar mostra "Non connesso" in rosso - ---- - -### Test 3: Sessione Salvata Valida ? - -**Steps**: -1. Avvia app con sessione salvata valida -2. Controlla log - -**Log Atteso**: -``` -[17:30:53] [SESSION] Ripristino sessione per: username -[17:30:53] [SESSION] Verifica validit sessione... -[17:30:55] [SESSION] Sessione valida - username (XX puntate) -``` - -**Verificare**: -- ? Nessun log "[DEBUG] Attesa inizializzazione WebView" -- ? Validazione immediata (2-3 secondi) -- ? Nessuna interazione con WebView - ---- - -### Test 4: Timeout WebView (Edge Case) ? - -**Steps** (simulazione): -1. Disabilita WebView2 Runtime -2. Avvia app -3. Aspetta 60+ secondi - -**Log Atteso**: -``` -[17:30:53] [SESSION] Nessuna sessione salvata -[17:30:53] [BROWSER] Inizializzazione WebView2 in background... -[17:30:53] [WARN] Inizializzazione WebView2 fallita: [errore] -[17:30:53] [INFO] WebView2 sar inizializzata al primo utilizzo -[17:30:53] [DEBUG] Attesa inizializzazione WebView... -[17:31:53] [WARN] Timeout attesa inizializzazione WebView2 -[17:31:53] [INFO] Per accedere: -[17:31:53] [INFO] 1. Click su 'Non connesso' nella sidebar -... -``` - -**Verificare**: -- ? Timeout dopo 60 secondi -- ? Istruzioni mostrate come fallback -- ? App non crasha - ---- - -## ?? File Modificati - -| File | Modifiche | Descrizione | -|------|-----------|-------------| -| `Core\MainWindow.WebView.cs` | +50 linee | TaskCompletionSource, WaitForWebViewInitAsync, CheckAndImportCookieIfAvailable | -| `Core\MainWindow.UserInfo.cs` | +40 linee | CheckBrowserCookieAfterWebViewReady, attesa intelligente | - -**Totale**: 2 file, ~90 linee aggiunte - ---- - -## ?? Risultato Finale - -### Log Perfetto (Browser Loggato) - -``` -[17:30:53] [LOAD] 6 aste caricate con stato iniziale: Paused -[17:30:53] [OK] Impostazioni caricate -[17:30:53] [OK] AutoBidder v4.0 avviato -[17:30:53] [SESSION] Nessuna sessione salvata -[17:30:53] [BROWSER] Inizializzazione WebView2 in background... -[17:30:53] [DEBUG] Attesa inizializzazione WebView per verifica cookie... -[17:31:43] [BROWSER] WebView2 inizializzato e pre-caricato -[17:31:45] [BROWSER] Cookie rilevato nel browser - importazione automatica... -[17:31:45] [SESSION OK] Validata e attiva: sirbietole23, 44 puntate -[17:31:45] [BROWSER] Connessione automatica completata -``` - -**Niente**: -- ? Istruzioni login inutili -- ? Click su tab Browser richiesto -- ? Confusione utente - -**Tutto**: -- ? Attesa intelligente -- ? Auto-login automatico -- ? UX cristallina - ---- - -**Data Refactoring**: 2025 -**Versione**: 7.0+ -**Issue**: Cookie detection falliva (timing sbagliato) -**Soluzione**: TaskCompletionSource + attesa intelligente -**Pattern**: Async coordination con timeout -**Status**: ? COMPLETATO - -## ?? Pattern Utilizzati - -### TaskCompletionSource Pattern - -**Uso**: -```csharp -// Setup -private TaskCompletionSource? _tcs; - -// Producer (thread init) -_tcs?.TrySetResult(true); // Notifica completamento - -// Consumer (thread verifica) -await _tcs.Task; // Attende completamento - -// Timeout -var timeout = Task.Delay(60000); -var completed = await Task.WhenAny(_tcs.Task, timeout); -``` - -**Benefici**: -- Coordinazione async tra thread -- Timeout integrato -- Cancellazione supportata -- Thread-safe - -### References - -- [TaskCompletionSource Class](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskcompletionsource-1) -- [Async/Await Best Practices](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming) diff --git a/Mimante/Documentation/REFACTORING_EXECUTIVE_SUMMARY.md b/Mimante/Documentation/REFACTORING_EXECUTIVE_SUMMARY.md deleted file mode 100644 index a154e0d..0000000 --- a/Mimante/Documentation/REFACTORING_EXECUTIVE_SUMMARY.md +++ /dev/null @@ -1,275 +0,0 @@ -# ?? Executive Summary: Refactoring Completo Sistema Impostazioni - -## ?? Obiettivo - -Garantire la **persistenza completa** di TUTTE le impostazioni dell'applicazione tra le sessioni, eliminando i problemi di salvataggio parziale e cookie "non valido". - ---- - -## ?? Problemi Risolti - -### 1. Cookie "Non Valido" al Riavvio -**Sintomo**: Cookie salvato correttamente ma marcato come "non valido" all'avvio successivo. - -**Causa**: Cookie salvato in `session.dat` ma NON caricato nella TextBox UI. - -**Fix**: Aggiunto caricamento esplicito del cookie in `LoadDefaultSettings()`. - -**Risultato**: ? Cookie sempre visualizzato e funzionante. - ---- - -### 2. Checkbox Export Non Salvate -**Sintomo**: 3 checkbox su 6 non persistevano tra sessioni. - -**Checkbox mancanti**: -- ? `IncludeMetadata` -- ? `RemoveAfterExport` -- ? `OverwriteExisting` - -**Causa**: `SaveSettingsButton_Click()` non salvava queste 3 propriet. - -**Fix**: Aggiunte le 3 righe mancanti nel metodo di salvataggio. - -**Risultato**: ? Tutte le 6 checkbox persistono correttamente. - ---- - -## ? Modifiche Implementate - -### File: `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - -#### 1. `LoadDefaultSettings()` - Cookie Loading -```csharp -// ? AGGIUNTO -var session = Services.SessionManager.LoadSession(); -if (session != null && !string.IsNullOrEmpty(session.CookieString)) -{ - SettingsCookieTextBox.Text = session.CookieString; -} -``` - -**Effetto**: Cookie caricato all'avvio dell'applicazione. - ---- - -#### 2. `SaveSettingsButton_Click()` - Complete Export Options -```csharp -// ? GI SALVATE -settings.IncludeOnlyUsedBids = IncludeUsedBids.IsChecked == true; -settings.IncludeLogs = IncludeLogs.IsChecked == true; -settings.IncludeUserBids = IncludeUserBids.IsChecked == true; - -// ? AGGIUNTE (ERANO MANCANTI) -settings.IncludeMetadata = IncludeMetadata.IsChecked == true; -settings.RemoveAfterExport = RemoveAfterExport.IsChecked == true; -settings.OverwriteExisting = OverwriteExisting.IsChecked == true; -``` - -**Effetto**: Tutte le checkbox export salvate correttamente. - ---- - -#### 3. Documentazione Inline -```csharp -// === SEZIONE 1: Impostazioni Predefinite Aste === -// === SEZIONE 2: Limiti Log === -// === SEZIONE 3: Stati Iniziali Aste === -// === SEZIONE 4: Cookie (da SessionManager separato) === -``` - -**Effetto**: Codice pi leggibile e manutenibile. - ---- - -## ?? Risultati - -### Prima del Refactoring ? - -| Impostazione | Persistenza | -|--------------|-------------| -| Cookie | ? Non visualizzato (sembrava "non valido") | -| IncludeMetadata | ? Non salvata | -| RemoveAfterExport | ? Non salvata | -| OverwriteExisting | ? Non salvata | -| Altre impostazioni | ? Funzionanti | - -**User Experience**: ?? Frustrante - cookie e checkbox non funzionavano - ---- - -### Dopo il Refactoring ? - -| Impostazione | Persistenza | -|--------------|-------------| -| Cookie | ? Visualizzato e funzionante | -| IncludeMetadata | ? Salvata | -| RemoveAfterExport | ? Salvata | -| OverwriteExisting | ? Salvata | -| Tutte le altre | ? Funzionanti | - -**User Experience**: ?? Perfetta - tutto funziona come previsto - ---- - -## ?? Test Verificati - -? **Test 1: Cookie Persistence** -- Salva cookie ? Chiudi app ? Riapri -- Risultato: Cookie presente e funzionante - -? **Test 2: Checkbox Export** -- Modifica checkbox ? Salva ? Chiudi ? Riapri -- Risultato: Tutte le checkbox mantengono lo stato - -? **Test 3: Salvataggio Completo** -- Modifica TUTTE le impostazioni ? Salva ? Riavvia -- Risultato: Nessuna impostazione persa - ---- - -## ?? Storage Architecture - -``` -Storage System -??? SessionManager (session.dat - DPAPI Encrypted) -? ??? CookieString ? Cookie autenticazione -? ??? Username ? Nome utente -? ??? RemainingBids ? Puntate residue -? -??? SettingsManager (settings.json - Plain JSON) - ??? Export Settings - ? ??? ExportPath ? Percorso - ? ??? LastExportExt ? Formato (.json/.xml/.csv) - ? ??? ExportScope ? Scope (All/Closed/Unknown/Open) - ? ??? IncludeOnlyUsedBids ? - ? ??? IncludeLogs ? - ? ??? IncludeUserBids ? - ? ??? IncludeMetadata ? (FIX) - ? ??? RemoveAfterExport ? (FIX) - ? ??? OverwriteExisting ? (FIX) - ? - ??? Auction Defaults - ? ??? DefaultBidBeforeDeadlineMs ? - ? ??? DefaultCheckAuctionOpenBeforeBid ? - ? ??? DefaultMinPrice ? - ? ??? DefaultMaxPrice ? - ? ??? DefaultMaxClicks ? - ? - ??? Log Limits - ? ??? MaxLogLinesPerAuction ? - ? ??? MaxGlobalLogLines ? - ? - ??? Initial States - ??? DefaultStartAuctionsOnLoad ? - ??? DefaultNewAuctionState ? -``` - ---- - -## ?? Sicurezza - -- ? Cookie crittografato con **Windows DPAPI** -- ? Solo l'utente corrente pu decrittare -- ? Cookie NON salvato in plain text - ---- - -## ?? Metriche - -| Metrica | Valore | -|---------|--------| -| **File modificati** | 1 | -| **Righe modificate** | ~50 | -| **Nuove righe di codice** | ~10 | -| **Righe di documentazione** | ~30 | -| **Problemi risolti** | 2 (cookie + 3 checkbox) | -| **Impostazioni coperte** | 100% (23/23) | -| **Test passati** | 3/3 ? | -| **Build status** | ? Success | -| **Regressioni** | 0 ? | - ---- - -## ?? Best Practices Applicate - -### 1. Load ? Modify ? Save Pattern -```csharp -var settings = SettingsManager.Load() ?? new AppSettings(); // Load -settings.Property = newValue; // Modify -SettingsManager.Save(settings); // Save (mantiene tutto il resto) -``` - -### 2. Simmetria Load/Save -Ogni propriet **caricata** deve essere **salvata** (e viceversa). - -### 3. Doppio Sistema Storage Documentato -- Cookie ? `SessionManager` (crittografato) -- Tutto il resto ? `SettingsManager` (JSON) - -### 4. Error Handling Robusto -```csharp -try { ... } -catch (Exception ex) -{ - Log($"[ERRORE] ...: {ex.Message}", LogLevel.Error); -} -``` - ---- - -## ?? Documentazione - -Creata documentazione completa: -- ? `Documentation\REFACTORING_SETTINGS_PERSISTENCE.md` (documento principale) -- ? Sezioni commentate nel codice -- ? Summary esecutivo (questo documento) - ---- - -## ?? Prossimi Passi (Opzionali) - -### Miglioramenti Futuri -1. **Unit Tests**: Aggiungere test automatici per persistenza -2. **Validation Layer**: Validazione input prima del salvataggio -3. **Settings Migration**: Gestire aggiornamenti schema settings.json -4. **Backup/Restore**: Funzionalit backup/ripristino impostazioni -5. **Export/Import Settings**: Condivisione impostazioni tra dispositivi - ---- - -## ? Conclusioni - -### Obiettivi Raggiunti -- ? Cookie persiste tra sessioni -- ? Tutte le checkbox export persistono -- ? Nessuna impostazione persa -- ? User experience migliorata -- ? Codice pi leggibile -- ? Zero regressioni - -### Impatto -- **Utente**: Esperienza fluida, nessuna frustrazi one -- **Sviluppatore**: Codice pi chiaro e manutenibile -- **Manutenibilit**: Documentazione completa - -### Status -?? **REFACTORING COMPLETATO CON SUCCESSO** - ---- - -**Data**: 2025 -**Versione**: 5.3+ -**Autore**: AI Assistant -**Review**: ? Approved -**Build Status**: ? Passing -**Tests**: ? 3/3 Passed - ---- - -## ?? Riferimenti Rapidi - -- **Problema Cookie**: `Documentation\REFACTORING_SETTINGS_PERSISTENCE.md` Causa 1 -- **Problema Checkbox**: `Documentation\REFACTORING_SETTINGS_PERSISTENCE.md` Causa 2 -- **Pattern Load/Save**: `Documentation\REFACTORING_SETTINGS_PERSISTENCE.md` Lezione 2 -- **Test Verification**: `Documentation\REFACTORING_SETTINGS_PERSISTENCE.md` Test di Verifica diff --git a/Mimante/Documentation/REFACTORING_SESSION_SERVICE_COMPLETE.md b/Mimante/Documentation/REFACTORING_SESSION_SERVICE_COMPLETE.md deleted file mode 100644 index 539d477..0000000 --- a/Mimante/Documentation/REFACTORING_SESSION_SERVICE_COMPLETE.md +++ /dev/null @@ -1,488 +0,0 @@ -# ?? Refactoring Completato: SessionService - -## ? Implementazione Completata - -### Nuovi File Creati - -1. **`Services\SessionService.cs`** (NUOVO) - - Gestione centralizzata sessione utente - - Metodi: LoadSession, SaveSession, ValidateAndActivateSessionAsync, RefreshUserInfoAsync - - Eventi: OnLog, OnSessionChanged - - Pattern: Single Responsibility + Dependency Injection - -2. **`Documentation\REFACTORING_SESSION_SERVICE_PROPOSAL.md`** - - Proposta di refactoring completa - - Analisi del problema - - Soluzione architetturale - -3. **`Documentation\REFACTORING_SESSION_SERVICE_COMPLETE.md`** (questo file) - - Riepilogo implementazione - - Istruzioni testing - - Benefici ottenuti - ---- - -## ?? File Modificati - -### 1. `Services\AuctionMonitor.cs` -**Modifica**: Aggiunto metodo `GetApiClient()` -```csharp -public BidooApiClient GetApiClient() -{ - return _apiClient; -} -``` - -### 2. `Core\MainWindow.UserInfo.cs` -**Modifiche**: -- ? Aggiunto field `_sessionService` -- ? Aggiunto metodo `InitializeSessionService()` -- ? Refactored `LoadSavedSession()` - ora usa SessionService -- ? Semplificati `UserBannerTimer_Tick()` e `UserHtmlTimer_Tick()` -- ? Rimosso codice legacy complesso con Task.Run e fallback - -**Prima** (78 righe, logica complessa): -```csharp -private void LoadSavedSession() -{ - var session = SessionManager.LoadSession(); - _auctionMonitor.InitializeSessionWithCookie(...); - - Task.Run(async () => { - // Prova UpdateUserInfoAsync - // Se fallisce, prova GetUserDataFromHtmlAsync - // Gestione errori sparsa - }); -} -``` - -**Dopo** (35 righe, logica chiara): -```csharp -private async void LoadSavedSession() -{ - var session = _sessionService.LoadSession(); - SettingsCookieTextBox.Text = session.CookieString; - - var result = await _sessionService.ValidateAndActivateSessionAsync( - session.CookieString, session.Username - ); - - // Gestione errori unificata -} -``` - -### 3. `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` -**Modifica**: Refactored `SaveCookieButton_Click()` - -**Prima**: -```csharp -_auctionMonitor.InitializeSessionWithCookie(cookie, string.Empty); -var success = await _auctionMonitor.UpdateUserInfoAsync(); -var session = _auctionMonitor.GetSession(); - -if (success && session != null) { - Services.SessionManager.SaveSession(session); - // ... -} -``` - -**Dopo**: -```csharp -var result = await _sessionService.ValidateAndActivateSessionAsync(cookie); - -if (result.Success && result.Session != null) { - _sessionService.SaveSession(result.Session); - // ... -} -``` - -### 4. `MainWindow.xaml.cs` -**Modifiche**: -- ? Aggiunto `InitializeSessionService()` nel constructor -- ? Aggiunto `LoadSavedSession()` nel constructor -- ? Rimossi `UpdateUserBannerInfoAsync()` e `UpdateUserHtmlInfoAsync()` (non pi necessari) - ---- - -## ?? Metriche del Refactoring - -| Metrica | Prima | Dopo | Miglioramento | -|---------|-------|------|---------------| -| **File coinvolti** | 3 | 1 (+SessionService) | +33% separazione | -| **Righe LoadSavedSession()** | 78 | 35 | -55% complessit | -| **Righe SaveCookie()** | 25 | 15 | -40% complessit | -| **Chiamate API dirette** | 5 | 0 | -100% accoppiamento | -| **Gestione errori** | Sparsa | Unificata | +100% chiarezza | -| **Testabilit** | Difficile | Facile | +200% | - ---- - -## ?? Nuovo Flusso Applicazione - -### Avvio Applicazione - -``` -1. MainWindow Constructor - ? -2. InitializeComponent() - ? -3. _auctionMonitor = new AuctionMonitor() - ? -4. InitializeSessionService() ? NUOVO - ?? _sessionService = new SessionService(_auctionMonitor.GetApiClient()) - ?? Event handlers setup - ?? Log: "[OK] SessionService inizializzato" - ? -5. InitializeCommands() - ? -6. LoadSavedAuctions() - ? -7. LoadExportSettings() - ? -8. LoadDefaultSettings() - ? -9. InitializeUserInfoTimers() - ? -10. LoadSavedSession() ? NUOVO - ?? _sessionService.LoadSession() - ?? Mostra cookie in UI - ?? _sessionService.ValidateAndActivateSessionAsync() - ?? InitializeSessionWithCookie() - ?? UpdateUserInfoAsync() ? Attiva sessione - ?? GetSession() ? Recupera dati - ?? OnSessionChanged event ? SetUserBanner() - ? -11. Log: "[OK] AutoBidder v4.0 avviato" - ? -? Applicazione pronta con sessione attiva -``` - -### Salvataggio Cookie - -``` -1. Utente inserisce cookie nelle Impostazioni - ? -2. Clic su "Salva" - ? -3. SaveCookieButton_Click() - ? -4. _sessionService.ValidateAndActivateSessionAsync(cookie) - ?? InitializeSessionWithCookie() - ?? UpdateUserInfoAsync() ? Attiva sessione - ?? GetSession() ? Recupera dati - ?? Log: "[SESSION OK] Validata e attiva: username, XX puntate" - ?? OnSessionChanged event ? SetUserBanner() - ? -5. _sessionService.SaveSession(result.Session) - ?? SessionManager.SaveSession() ? Salva su disco - ?? Log: "[SESSION] Salvata sessione per: username" - ? -6. Log: "[OK] Cookie valido e salvato - Utente: username" - ? -? Sessione validata, attivata e salvata -``` - -### Refresh Periodico - -``` -1. Timer tick (ogni 5 minuti) - ? -2. UserHtmlTimer_Tick() - ? -3. _sessionService.RefreshUserInfoAsync() - ?? UpdateUserInfoAsync() ? Aggiorna dati - ?? GetSession() ? Recupera dati aggiornati - ?? OnSessionChanged event ? SetUserBanner() - ? -? Dati utente aggiornati senza intervento manuale -``` - ---- - -## ?? Benefici Ottenuti - -### 1. Semplicit -- **Prima**: Logica sparsa in 3 file con 5 metodi diversi -- **Dopo**: 1 classe SessionService con API chiara e documentata - -### 2. Affidabilit -- **Prima**: Ordine chiamate API non garantito ? errori casuali -- **Dopo**: `ValidateAndActivateSessionAsync()` garantisce ordine corretto ? funziona sempre - -### 3. Manutenibilit -- **Prima**: Modificare gestione sessione richiedeva aggiornamenti in 3 file -- **Dopo**: Tutte le modifiche centralizzate in SessionService.cs - -### 4. Testabilit -- **Prima**: Impossibile testare in isolamento (dipendenze nascoste) -- **Dopo**: SessionService pu essere testato con mock di BidooApiClient - -### 5. Debug -- **Prima**: Log sparsi, difficile tracciare flusso -- **Dopo**: Tutti i log hanno prefisso `[SESSION]`, facile seguire flusso - -### 6. Chiarezza -- **Prima**: Non chiaro chi gestisce la sessione (MainWindow? AuctionMonitor? BidooApiClient?) -- **Dopo**: SessionService ha la responsabilit unica e chiara - ---- - -## ?? Testing Checklist - -### Test 1: Avvio con Sessione Salvata ? -**Steps**: -1. Salva un cookie valido -2. Chiudi completamente l'app -3. Riapri l'app -4. Verifica che i dati utente appaiano entro 5 secondi - -**Log attesi**: -``` -[SESSION] Caricata sessione per: username -[OK] Sessione caricata per: username -[SESSION] Inizializzazione cookie nel client HTTP... -[SESSION] Attivazione sessione tramite buy_bids.php... -[SESSION OK] Validata e attiva: username, XX puntate -``` - -### Test 2: Salvataggio Nuovo Cookie ? -**Steps**: -1. Vai su Impostazioni -2. Inserisci cookie valido -3. Clicca "Salva" -4. Verifica che dati utente appaiano immediatamente - -**Log attesi**: -``` -[SESSION] Inizializzazione cookie nel client HTTP... -[SESSION] Attivazione sessione tramite buy_bids.php... -[SESSION OK] Validata e attiva: username, XX puntate -[SESSION] Salvata sessione per: username -[OK] Cookie valido e salvato - Utente: username, Puntate: XX -``` - -### Test 3: Cookie Scaduto ? -**Steps**: -1. Inserisci cookie scaduto o invalido -2. Clicca "Salva" -3. Verifica messaggio di errore chiaro - -**Log attesi**: -``` -[SESSION] Inizializzazione cookie nel client HTTP... -[SESSION] Attivazione sessione tramite buy_bids.php... -[SESSION ERROR] Impossibile attivare sessione - cookie potrebbe essere scaduto o non valido -[ERRORE] Impossibile attivare sessione - cookie potrebbe essere scaduto o non valido -``` - -### Test 4: Refresh Periodico ? -**Steps**: -1. Avvia app con sessione valida -2. Attendi 5 minuti -3. Verifica che dati utente vengano aggiornati - -**Log attesi** (ogni 5 minuti): -``` -[SESSION] Refresh dati utente... -[SESSION] Dati aggiornati: username, XX puntate -``` - -### Test 5: Nessuna Sessione Salvata ? -**Steps**: -1. Elimina `%AppData%\AutoBidder\session.dat` -2. Avvia app -3. Verifica messaggio informativo - -**Log attesi**: -``` -[SESSION] Nessuna sessione valida trovata -[INFO] Nessuna sessione salvata trovata -[INFO] Vai su Impostazioni per configurare il cookie -``` - ---- - -## ?? Architettura Finale - -``` -?????????????????????????????????????????????????????????????????? -? MainWindow ? -? (Presentation Layer - solo UI e coordinamento) ? -? ? -? - InitializeComponent() ? -? - InitializeSessionService() ? Setup SessionService ? -? - LoadSavedSession() ? Semplice chiamata a SessionService ? -? - SaveCookieButton_Click() ? Semplice chiamata a SessionService? -? - SetUserBanner() ? Aggiorna UI ? -?????????????????????????????????????????????????????????????????? - ? - ? usa - ? -?????????????????????????????????????????????????????????????????? -? SessionService ? -? (Business Logic Layer - gestione sessione) ? -? ? -? + LoadSession() ? BidooSession? ? -? + SaveSession(session) ? bool ? -? + ValidateAndActivateSessionAsync(cookie) ? SessionValidationResult? -? + RefreshUserInfoAsync() ? bool ? -? + GetCurrentSession() ? BidooSession? ? -? + ClearSession() ? -? ? -? Events: ? -? OnLog ? string ? -? OnSessionChanged ? BidooSession ? -?????????????????????????????????????????????????????????????????? - ? - ? usa - ? -?????????????????????????????????????????????????????????????????? -? BidooApiClient ? -? (Data Access Layer - chiamate HTTP) ? -? ? -? + InitializeSessionWithCookie(cookie, username) ? -? + UpdateUserInfoAsync() ? bool ? -? + GetSession() ? BidooSession ? -? + PollAuctionStateAsync() ? AuctionState ? -? + PlaceBidAsync() ? BidResult ? -?????????????????????????????????????????????????????????????????? - ? - ? accede - ? -?????????????????????????????????????????????????????????????????? -? SessionManager ? -? (Persistence Layer - storage crittografato) ? -? ? -? + LoadSession() ? BidooSession? ? -? + SaveSession(session) ? bool ? -? + ClearSession() ? bool ? -? ? -? File: %AppData%\AutoBidder\session.dat (DPAPI encrypted) ? -?????????????????????????????????????????????????????????????????? -``` - -**Separazione delle responsabilit**: -- **MainWindow**: Solo UI e coordinamento -- **SessionService**: Business logic sessione -- **BidooApiClient**: Chiamate HTTP -- **SessionManager**: Persistenza crittografata - ---- - -## ?? Pattern Applicati - -### 1. Single Responsibility Principle (SRP) -Ogni classe ha una sola responsabilit: -- MainWindow ? UI -- SessionService ? Business logic sessione -- BidooApiClient ? HTTP calls -- SessionManager ? Persistence - -### 2. Dependency Injection (DI) -```csharp -_sessionService = new SessionService(_auctionMonitor.GetApiClient()); -``` -SessionService riceve BidooApiClient tramite constructor injection. - -### 3. Event-Driven Architecture -```csharp -_sessionService.OnLog += (msg) => Log(msg); -_sessionService.OnSessionChanged += (session) => SetUserBanner(...); -``` -SessionService notifica cambiamenti tramite eventi invece di chiamare direttamente MainWindow. - -### 4. Facade Pattern -`ValidateAndActivateSessionAsync()` nasconde la complessit di: -1. Inizializzazione cookie -2. Attivazione sessione server -3. Validazione dati -4. Gestione errori - -### 5. Result Object Pattern -```csharp -public class SessionValidationResult -{ - public bool Success { get; set; } - public BidooSession? Session { get; set; } - public string? ErrorMessage { get; set; } -} -``` -Invece di lanciare eccezioni, restituisce un oggetto risultato. - ---- - -## ?? Breaking Changes - -### Nessuno! -Il refactoring mantiene la compatibilit completa con il codice esistente. - -**Motivo**: Abbiamo aggiunto SessionService come nuovo layer, senza rimuovere metodi esistenti in AuctionMonitor (per ora). - -**Prossimi step opzionali**: -- Rimuovere metodi legacy da AuctionMonitor (InitializeSession, UpdateUserInfoAsync, ecc.) -- Questi metodi ora sono obsoleti ma mantenuti per compatibilit - ---- - -## ?? Lezioni Apprese - -### 1. Refactoring Incrementale -Abbiamo aggiunto SessionService senza rimuovere codice esistente ? zero breaking changes. - -### 2. Separazione delle Responsabilit -Prima: MainWindow faceva troppe cose (UI + sessione + storage). -Dopo: Ogni classe ha un compito chiaro. - -### 3. Dependency Injection > Direct Coupling -Prima: `_auctionMonitor.UpdateUserInfoAsync()` (accoppiamento stretto). -Dopo: `_sessionService.ValidateAndActivateSessionAsync()` (disaccoppiato). - -### 4. Events > Callbacks -Events permettono a SessionService di notificare MainWindow senza conoscerlo direttamente. - -### 5. Testabilit come Obiettivo -SessionService pu essere testato in isolamento con mock di BidooApiClient. - ---- - -## ? Conclusione - -### Problema Risolto ? -**Cookie funziona solo dopo "Salva" manuale** ? **Cookie funziona sempre all'avvio** - -### Causa Identificata ? -Ordine chiamate API non garantito ? sessione "fredda" all'avvio - -### Soluzione Implementata ? -SessionService con `ValidateAndActivateSessionAsync()` garantisce ordine corretto - -### Benefici Ottenuti ? -- ? Codice pi semplice (-55% complessit) -- ? Pi affidabile (ordine garantito) -- ? Pi manutenibile (centralizzato) -- ? Pi testabile (DI pattern) -- ? Pi chiaro (responsabilit definite) - -### Build Status ? -Compilazione riuscita senza errori o warning - -### Status Refactoring ? -?? **COMPLETATO CON SUCCESSO** - ---- - -**Data**: 2025 -**Versione**: 5.6+ -**Refactoring**: SessionService Implementation -**Lines Changed**: ~150 righe modificate, ~250 righe aggiunte -**Files Changed**: 4 modified, 1 created -**Breaking Changes**: 0 -**Status**: ? PRODUCTION READY - -## ?? Riferimenti - -- `Services\SessionService.cs` - Nuova implementazione -- `Documentation\REFACTORING_SESSION_SERVICE_PROPOSAL.md` - Proposta originale -- `Core\MainWindow.UserInfo.cs` - Refactored -- `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - Refactored -- `MainWindow.xaml.cs` - Updated constructor diff --git a/Mimante/Documentation/REFACTORING_SESSION_SERVICE_PROPOSAL.md b/Mimante/Documentation/REFACTORING_SESSION_SERVICE_PROPOSAL.md deleted file mode 100644 index 8197a75..0000000 --- a/Mimante/Documentation/REFACTORING_SESSION_SERVICE_PROPOSAL.md +++ /dev/null @@ -1,592 +0,0 @@ -# ?? Refactoring Proposto: Gestione Sessione Unificata - -## ?? Problema Attuale - -### Architettura Frammentata - -``` -MainWindow - ??> LoadSavedSession() - ??> SaveCookieButton_Click() - ??> AuctionMonitor - ??> BidooApiClient - ??> InitializeSessionWithCookie() - ??> UpdateUserInfoAsync() - ??> GetUserDataFromHtmlAsync() -``` - -**Problemi**: -1. **Troppi livelli**: MainWindow ? AuctionMonitor ? BidooApiClient -2. **Responsabilit confuse**: Chi gestisce la sessione? MainWindow, AuctionMonitor o BidooApiClient? -3. **Stato duplicato**: Session salvata in file + in memoria BidooApiClient -4. **Flussi complicati**: Diversi metodi per stessa operazione (UpdateUserInfoAsync vs GetUserDataFromHtmlAsync) -5. **Nessun pattern chiaro**: Ogni metodo fa le cose diversamente - ---- - -## ? Soluzione: Gestione Sessione Unificata - -### Nuovo Pattern: SessionService - -``` -MainWindow - ??> SessionService (NUOVO) - ? ??> LoadSession() - ? ??> SaveSession() - ? ??> ValidateAndActivateSession() - ? ??> GetUserInfo() - ? - ??> AuctionMonitor - ??> BidooApiClient (usa session da SessionService) -``` - -### Vantaggi: -- ? **Single Responsibility**: Ogni classe ha un unico scopo -- ? **Dependency Injection**: SessionService iniettato dove serve -- ? **Testabile**: Ogni componente pu essere testato isolatamente -- ? **Chiaro**: Flusso lineare e prevedibile - ---- - -## ?? Implementazione - -### 1. SessionService.cs (NUOVO) - -```csharp -namespace AutoBidder.Services -{ - /// - /// Servizio centralizzato per gestione sessione utente - /// Responsabile di: Load, Save, Validate, Activate - /// - public class SessionService - { - private readonly BidooApiClient _apiClient; - private BidooSession? _currentSession; - - public event Action? OnLog; - public event Action? OnSessionChanged; - - public SessionService(BidooApiClient apiClient) - { - _apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient)); - } - - /// - /// Carica sessione salvata (se esiste) - /// - public BidooSession? LoadSession() - { - try - { - var session = SessionManager.LoadSession(); - - if (session != null && session.IsValid) - { - _currentSession = session; - OnLog?.Invoke($"[SESSION] Caricata sessione per: {session.Username}"); - return session; - } - - OnLog?.Invoke("[SESSION] Nessuna sessione valida trovata"); - return null; - } - catch (Exception ex) - { - OnLog?.Invoke($"[SESSION ERROR] Caricamento fallito: {ex.Message}"); - return null; - } - } - - /// - /// Salva sessione su disco (crittografata) - /// - public bool SaveSession(BidooSession session) - { - try - { - if (session == null || !session.IsValid) - { - OnLog?.Invoke("[SESSION ERROR] Sessione non valida, impossibile salvare"); - return false; - } - - var success = SessionManager.SaveSession(session); - - if (success) - { - _currentSession = session; - OnLog?.Invoke($"[SESSION] Salvata sessione per: {session.Username}"); - OnSessionChanged?.Invoke(session); - } - - return success; - } - catch (Exception ex) - { - OnLog?.Invoke($"[SESSION ERROR] Salvataggio fallito: {ex.Message}"); - return false; - } - } - - /// - /// Valida e attiva sessione: verifica che il cookie funzioni - /// Questo il metodo PRINCIPALE da usare all'avvio e dopo modifica cookie - /// - public async Task ValidateAndActivateSessionAsync(string cookieString, string? username = null) - { - var result = new SessionValidationResult(); - - try - { - // 1. Inizializza cookie nel client HTTP - OnLog?.Invoke("[SESSION] Inizializzazione cookie..."); - _apiClient.InitializeSessionWithCookie(cookieString, username ?? string.Empty); - - // 2. CHIAVE: Attiva sessione server-side con buy_bids.php - // Questo necessario per "riscaldare" la sessione - OnLog?.Invoke("[SESSION] Attivazione sessione tramite API..."); - var activationSuccess = await _apiClient.UpdateUserInfoAsync(); - - if (!activationSuccess) - { - result.Success = false; - result.ErrorMessage = "Impossibile attivare sessione - cookie potrebbe essere scaduto"; - OnLog?.Invoke($"[SESSION ERROR] {result.ErrorMessage}"); - return result; - } - - // 3. Recupera dati utente aggiornati - var session = _apiClient.GetSession(); - - if (session == null || string.IsNullOrEmpty(session.Username)) - { - result.Success = false; - result.ErrorMessage = "Sessione attivata ma dati utente non disponibili"; - OnLog?.Invoke($"[SESSION ERROR] {result.ErrorMessage}"); - return result; - } - - // 4. Successo! - result.Success = true; - result.Session = session; - _currentSession = session; - - OnLog?.Invoke($"[SESSION OK] Sessione validata e attiva: {session.Username}, {session.RemainingBids} puntate"); - OnSessionChanged?.Invoke(session); - - return result; - } - catch (Exception ex) - { - result.Success = false; - result.ErrorMessage = ex.Message; - OnLog?.Invoke($"[SESSION EXCEPTION] {ex.Message}"); - return result; - } - } - - /// - /// Ottiene dati utente correnti (dalla sessione in memoria) - /// - public BidooSession? GetCurrentSession() - { - return _currentSession; - } - - /// - /// Aggiorna dati utente (puntate residue, credito, ecc.) - /// Da chiamare periodicamente o dopo ogni puntata - /// - public async Task RefreshUserInfoAsync() - { - try - { - var success = await _apiClient.UpdateUserInfoAsync(); - - if (success) - { - _currentSession = _apiClient.GetSession(); - OnSessionChanged?.Invoke(_currentSession); - } - - return success; - } - catch (Exception ex) - { - OnLog?.Invoke($"[SESSION ERROR] Refresh fallito: {ex.Message}"); - return false; - } - } - - /// - /// Pulisce sessione corrente - /// - public void ClearSession() - { - _currentSession = null; - SessionManager.ClearSession(); - OnLog?.Invoke("[SESSION] Sessione pulita"); - } - } - - /// - /// Risultato della validazione sessione - /// - public class SessionValidationResult - { - public bool Success { get; set; } - public BidooSession? Session { get; set; } - public string? ErrorMessage { get; set; } - } -} -``` - ---- - -### 2. Refactoring MainWindow.UserInfo.cs - -```csharp -namespace AutoBidder -{ - public partial class MainWindow - { - private SessionService _sessionService; // NUOVO - - // Nel constructor: - public MainWindow() - { - // ...existing code... - - // NUOVO: Inizializza SessionService - _sessionService = new SessionService(_auctionMonitor.GetApiClient()); - _sessionService.OnLog += (msg) => Log(msg); - _sessionService.OnSessionChanged += (session) => - { - Dispatcher.Invoke(() => SetUserBanner(session.Username, session.RemainingBids)); - }; - - // ...existing code... - } - - /// - /// Carica sessione salvata - SEMPLIFICATO - /// - private async void LoadSavedSession() - { - try - { - // 1. Carica da disco - var session = _sessionService.LoadSession(); - - if (session == null) - { - Log("[INFO] Nessuna sessione salvata trovata"); - Log("[INFO] Vai su Impostazioni per configurare il cookie"); - return; - } - - // 2. Mostra cookie in UI - try - { - SettingsCookieTextBox.Text = session.CookieString ?? string.Empty; - } - catch { } - - StartButton.IsEnabled = true; - - Log($"[OK] Sessione caricata per: {session.Username}"); - - // 3. Valida e attiva in background - _ = Task.Run(async () => - { - var result = await _sessionService.ValidateAndActivateSessionAsync( - session.CookieString, - session.Username - ); - - if (!result.Success) - { - Dispatcher.Invoke(() => - { - Log($"[WARN] Validazione fallita: {result.ErrorMessage}"); - Log($"[INFO] Aggiorna il cookie nelle Impostazioni"); - }); - } - }); - } - catch (Exception ex) - { - Log($"[WARN] Errore caricamento sessione: {ex.Message}"); - } - } - - /// - /// Salva cookie - SEMPLIFICATO - /// - private async void SaveCookieButton_Click(object sender, RoutedEventArgs e) - { - try - { - var cookie = SettingsCookieTextBox.Text?.Trim(); - - if (string.IsNullOrEmpty(cookie)) - { - return; - } - - // Valida e attiva sessione - var result = await _sessionService.ValidateAndActivateSessionAsync(cookie); - - if (result.Success && result.Session != null) - { - // Salva su disco - _sessionService.SaveSession(result.Session); - - StartButton.IsEnabled = true; - Log($"[OK] Cookie valido e salvato - Utente: {result.Session.Username}"); - } - else - { - Log($"[ERRORE] {result.ErrorMessage ?? "Cookie non valido o scaduto"}"); - } - } - catch (Exception ex) - { - Log($"[ERRORE] Salvataggio cookie: {ex.Message}"); - } - } - - /// - /// Aggiorna banner utente - SEMPLIFICATO - /// - private void SetUserBanner(string username, int? remainingBids) - { - try - { - var session = _sessionService.GetCurrentSession(); - - if (!string.IsNullOrEmpty(username)) - { - // Header - RemainingBidsText.Text = remainingBids?.ToString() ?? "0"; - AuctionMonitor.ShopCreditText.Text = session?.ShopCredit > 0 - ? $"EUR {session.ShopCredit:F2}" - : "EUR 0.00"; - BannerAsteDaRiscattare.Text = "0"; - - // Sidebar - SidebarUsernameText.Text = username; - - if (session?.UserId > 0) - { - SidebarUserIdText.Text = $"ID: {session.UserId}"; - SidebarUserIdText.Visibility = Visibility.Visible; - } - else - { - SidebarUserIdText.Visibility = Visibility.Collapsed; - } - - if (!string.IsNullOrEmpty(session?.Email)) - { - SidebarUserEmailText.Text = session.Email; - SidebarUserEmailText.Visibility = Visibility.Visible; - } - else - { - SidebarUserEmailText.Visibility = Visibility.Collapsed; - } - - SidebarUserInfoPanel.Visibility = Visibility.Visible; - } - else - { - // Reset - SidebarUserInfoPanel.Visibility = Visibility.Collapsed; - RemainingBidsText.Text = "0"; - AuctionMonitor.ShopCreditText.Text = "EUR 0.00"; - BannerAsteDaRiscattare.Text = "0"; - } - } - catch { } - } - - /// - /// Timer aggiornamento info utente - SEMPLIFICATO - /// - private async void UserHtmlTimer_Tick(object? sender, EventArgs e) - { - await _sessionService.RefreshUserInfoAsync(); - } - } -} -``` - ---- - -### 3. Refactoring AuctionMonitor.cs - -```csharp -namespace AutoBidder.Services -{ - public class AuctionMonitor - { - private readonly BidooApiClient _apiClient; - - // ...existing code... - - /// - /// Espone ApiClient per SessionService - NUOVO - /// - public BidooApiClient GetApiClient() => _apiClient; - - // RIMUOVI questi metodi (ora gestiti da SessionService): - // - InitializeSession() - // - InitializeSessionWithCookie() - // - UpdateUserInfoAsync() - // - GetSession() - // - GetUserDataAsync() - // - GetUserBannerInfoAsync() - // - GetUserDataFromHtmlAsync() - - // Mantieni solo la logica di monitoraggio aste - } -} -``` - ---- - -## ?? Confronto Prima/Dopo - -### Prima: Flusso Frammentato - -``` -1. LoadSavedSession() - ??> SessionManager.LoadSession() - ??> _auctionMonitor.InitializeSessionWithCookie() - ??> Task.Run() - ??> UpdateUserInfoAsync() [a volte fallisce] - ??> GetUserDataFromHtmlAsync() [fallback] -``` - -**Problemi**: -- Logica sparsa in 3 file diversi -- Ordine chiamate confuso -- Nessuna gestione errori unificata - ---- - -### Dopo: Flusso Unificato - -``` -1. LoadSavedSession() - ??> _sessionService.LoadSession() - ??> Mostra cookie in UI - ??> _sessionService.ValidateAndActivateSessionAsync() - ??> SEMPRE chiama UpdateUserInfoAsync() prima -``` - -**Vantaggi**: -- Logica centralizzata in SessionService -- Ordine chiamate garantito -- Gestione errori unificata -- Testabile - ---- - -## ? Benefici - -### 1. Semplicit -- **Prima**: 5 metodi sparsi in 3 classi -- **Dopo**: 1 classe SessionService con API chiara - -### 2. Affidabilit -- **Prima**: Ordine chiamate non garantito -- **Dopo**: `ValidateAndActivateSessionAsync()` garantisce ordine corretto - -### 3. Manutenibilit -- **Prima**: Modifiche richiedono aggiornamento in 3 posti -- **Dopo**: Modifiche centralizzate in SessionService - -### 4. Testabilit -- **Prima**: Difficile testare (dipendenze nascoste) -- **Dopo**: SessionService testabile in isolamento - -### 5. Debug -- **Prima**: Log sparsi, difficile tracciare flusso -- **Dopo**: Log centralizzati con prefisso [SESSION] - ---- - -## ?? Prossimi Passi - -### Fase 1: Implementazione Base ? -1. Creare `Services\SessionService.cs` -2. Aggiungere `SessionValidationResult` -3. Aggiungere metodo `GetApiClient()` in AuctionMonitor - -### Fase 2: Refactoring MainWindow -1. Aggiungere field `_sessionService` -2. Inizializzare nel constructor -3. Refactorare `LoadSavedSession()` -4. Refactorare `SaveCookieButton_Click()` -5. Rimuovere logica duplicata - -### Fase 3: Cleanup -1. Rimuovere metodi session da AuctionMonitor -2. Rimuovere metodi inutili da MainWindow -3. Aggiornare timer per usare SessionService - -### Fase 4: Testing -1. Test caricamento sessione all'avvio -2. Test salvataggio nuovo cookie -3. Test validazione cookie scaduto -4. Test refresh info utente - ---- - -## ?? Note Implementative - -### Dependency Injection - -```csharp -// Nel constructor MainWindow: -_sessionService = new SessionService(_auctionMonitor.GetApiClient()); -_sessionService.OnLog += (msg) => Log(msg); -_sessionService.OnSessionChanged += UpdateUserBanner; -``` - -### Event Handling - -```csharp -_sessionService.OnSessionChanged += (session) => -{ - Dispatcher.Invoke(() => - { - SetUserBanner(session.Username, session.RemainingBids); - }); -}; -``` - -### Error Handling - -```csharp -var result = await _sessionService.ValidateAndActivateSessionAsync(cookie); - -if (!result.Success) -{ - MessageBox.Show(result.ErrorMessage, "Errore", MessageBoxButton.OK); - return; -} - -// Success -Log($"[OK] Cookie valido: {result.Session.Username}"); -``` - ---- - -**Status**: ?? PROPOSTA -**Priorit**: ?? ALTA -**Impatto**: ? Risolve problema alla radice -**Complessit**: ?? Media (refactoring significativo ma chiaro) diff --git a/Mimante/Documentation/REFACTORING_SETTINGS_PERSISTENCE.md b/Mimante/Documentation/REFACTORING_SETTINGS_PERSISTENCE.md deleted file mode 100644 index 47542ff..0000000 --- a/Mimante/Documentation/REFACTORING_SETTINGS_PERSISTENCE.md +++ /dev/null @@ -1,611 +0,0 @@ -# ?? Refactoring Completo: Sistema di Persistenza Impostazioni - -## ?? Problema Rilevato - -**Diverse impostazioni non persistevano** tra le sessioni dell'applicazione, nonostante venissero visualizzate correttamente nell'UI. Il problema si manifest ava anche con il cookie, che pur essendo salvato correttamente, veniva marcato come "non valido" al riavvio dell'applicazione. - -### ?? Sintomi - -1. **Cookie "non valido" al riavvio**: - - Cookie salvato correttamente in `session.dat` - - All'avvio app: TextBox cookie VUOTA - - Messaggio "cookie non valido" - - Reinserendo lo STESSO cookie ? funziona - -2. **Checkbox Export non salvate**: - - ? `IncludeUsedBids` ? salvata - - ? `IncludeLogs` ? salvata - - ? `IncludeUserBids` ? salvata - - ? `IncludeMetadata` ? **NON salvata** - - ? `RemoveAfterExport` ? **NON salvata** - - ? `OverwriteExisting` ? **NON salvata** - -3. **Altre impostazioni funzionanti**: - - ? Anticipo puntata - - ? Prezzo min/max - - ? Max clicks - - ? Stati iniziali aste - - ? Limiti log - - ? Percorso export - - ? Formato export - ---- - -## ?? Analisi delle Cause - -### Causa 1: Cookie Non Caricato in UI - -Il cookie viene salvato in un file separato (`SessionManager`), ma **non veniva mai caricato** nella TextBox all'avvio dell'applicazione. - -**File problematico**: `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - -```csharp -// ? PROBLEMA: Cookie NON caricato -private void LoadDefaultSettings() -{ - var settings = SettingsManager.Load(); - - // Carica altre impostazioni... - DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString(); - // ... - - // ? MANCA: Caricamento cookie da SessionManager -} -``` - -**Risultato**: -- Cookie salvato in `%AppData%\AutoBidder\session.dat` ? -- Cookie NON visualizzato in UI ? -- Validazione cookie fallisce perch TextBox vuota ? - -### Causa 2: Checkbox Export Non Salvate - -Il metodo `SaveSettingsButton_Click()` salvava solo 3 delle 6 checkbox export. - -**File problematico**: `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - -```csharp -// ? PROBLEMA: Solo 3 checkbox salvate -private void SaveSettingsButton_Click(object sender, RoutedEventArgs e) -{ - var settings = SettingsManager.Load() ?? new AppSettings(); - - // ? Salvate - settings.IncludeOnlyUsedBids = IncludeUsedBids.IsChecked == true; - settings.IncludeLogs = IncludeLogs.IsChecked == true; - settings.IncludeUserBids = IncludeUserBids.IsChecked == true; - - // ? MANCANO queste 3 - // settings.IncludeMetadata = IncludeMetadata.IsChecked == true; - // settings.RemoveAfterExport = RemoveAfterExport.IsChecked == true; - // settings.OverwriteExisting = OverwriteExisting.IsChecked == true; - - SettingsManager.Save(settings); -} -``` - -**Risultato**: -- Checkbox modificate dall'utente ? -- Valori NON scritti in `settings.json` ? -- Al riavvio: checkbox tornano ai valori default ? - -### Causa 3: LoadExportSettings() Funzionava - -Il metodo `LoadExportSettings()` caricava TUTTE le checkbox correttamente, incluse le 3 mancanti. - -**File**: `Core\EventHandlers\MainWindow.EventHandlers.Export.cs` - -```csharp -// ? Questo metodo funzionava correttamente -private void LoadExportSettings() -{ - var s = SettingsManager.Load(); - if (s != null) - { - try { IncludeUsedBids.IsChecked = s.IncludeOnlyUsedBids; } catch { } - try { IncludeLogs.IsChecked = s.IncludeLogs; } catch { } - try { IncludeUserBids.IsChecked = s.IncludeUserBids; } catch { } - try { IncludeMetadata.IsChecked = s.IncludeMetadata; } catch { } // ? Caricata - try { RemoveAfterExport.IsChecked = s.RemoveAfterExport; } catch { } // ? Caricata - try { OverwriteExisting.IsChecked = s.OverwriteExisting; } catch { } // ? Caricata - } -} -``` - -**Il problema era quindi nel SALVATAGGIO, non nel caricamento.** - ---- - -## ? Soluzione Implementata - -### 1?? Caricamento Cookie in LoadDefaultSettings() - -**File**: `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - -```csharp -private void LoadDefaultSettings() -{ - try - { - var settings = SettingsManager.Load(); - - // Carica tutte le altre impostazioni... - DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString(); - // ... - - // ? AGGIUNTO: Carica il cookie salvato nella TextBox - var session = Services.SessionManager.LoadSession(); - if (session != null && !string.IsNullOrEmpty(session.CookieString)) - { - SettingsCookieTextBox.Text = session.CookieString; - } - } - catch (Exception ex) - { - Log($"[ERRORE] Caricamento impostazioni: {ex.Message}", LogLevel.Error); - } -} -``` - -**Effetto**: -- Cookie caricato all'avvio ? -- TextBox cookie popolata ? -- Nessun messaggio "cookie non valido" ? - -### 2?? Salvataggio Completo Checkbox Export - -**File**: `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - -```csharp -private void SaveSettingsButton_Click(object sender, RoutedEventArgs e) -{ - try - { - // ? Carica le impostazioni esistenti per non perdere gli altri valori - var settings = SettingsManager.Load() ?? new AppSettings(); - - // Salva percorso e formato - settings.ExportPath = ExportPathTextBox.Text; - settings.LastExportExt = ExtJson.IsChecked == true ? ".json" : - ExtXml.IsChecked == true ? ".xml" : ".csv"; - - // Salva scope - var cbClosed = this.FindName("ExportClosedToolbar") as CheckBox; - var cbUnknown = this.FindName("ExportUnknownToolbar") as CheckBox; - var cbOpen = this.FindName("ExportOpenToolbar") as CheckBox; - - var scope = "All"; - if (cbClosed?.IsChecked == true) scope = "Closed"; - else if (cbUnknown?.IsChecked == true) scope = "Unknown"; - else if (cbOpen?.IsChecked == true) scope = "Open"; - - settings.ExportScope = scope; - settings.ExportOpen = cbOpen?.IsChecked ?? true; - settings.ExportClosed = cbClosed?.IsChecked ?? true; - settings.ExportUnknown = cbUnknown?.IsChecked ?? true; - - // ? TUTTE le checkbox (incluse le 3 mancanti) - settings.IncludeOnlyUsedBids = IncludeUsedBids.IsChecked == true; - settings.IncludeLogs = IncludeLogs.IsChecked == true; - settings.IncludeUserBids = IncludeUserBids.IsChecked == true; - settings.IncludeMetadata = IncludeMetadata.IsChecked == true; // ? AGGIUNTO - settings.RemoveAfterExport = RemoveAfterExport.IsChecked == true; // ? AGGIUNTO - settings.OverwriteExisting = OverwriteExisting.IsChecked == true; // ? AGGIUNTO - - SettingsManager.Save(settings); - ExportPreferences.SaveLastExportExtension(settings.LastExportExt); - } - catch (Exception ex) - { - Log($"[ERRORE] Salvataggio impostazioni export: {ex.Message}", LogLevel.Error); - } -} -``` - -**Effetto**: -- Tutte le checkbox salvate correttamente ? -- Valori persistono tra sessioni ? -- Nessuna impostazione persa ? - -### 3?? Documentazione e Organizzazione del Codice - -**Aggiunta sezioni commentate** per chiarezza: - -```csharp -// === SEZIONE 1: Impostazioni Predefinite Aste === -// === SEZIONE 2: Limiti Log === -// === SEZIONE 3: Stati Iniziali Aste === -// === SEZIONE 4: Cookie (da SessionManager separato) === - -// === SEZIONE EXPORT: Percorso e Formato === -// === SEZIONE EXPORT: Scope (Aste da esportare) === -// === SEZIONE EXPORT: Opzioni ? FIX: Aggiunte le 3 checkbox mancanti === - -// === SEZIONE DEFAULTS: Validazione e Salvataggio === -// === SEZIONE DEFAULTS: Limiti Log === -// === SEZIONE DEFAULTS: Stati Iniziali Aste === -``` - ---- - -## ?? Flusso Completo di Persistenza - -### Avvio Applicazione - -``` -1. MainWindow() Constructor - ? -2. InitializeComponent() - ? -3. LoadSavedAuctions() - ? -4. LoadExportSettings() ? Carica checkbox export da settings.json - ? -5. LoadDefaultSettings() ? Carica defaults aste + COOKIE da session.dat ? - ? -6. UpdateGlobalControlButtons() - ? -? Cookie visualizzato in UI -? Checkbox export impostate correttamente -``` - -### Salvataggio Impostazioni - -``` -1. Utente modifica impostazioni - ? -2. Clicca "Salva" - ? -3. SettingsControl.SaveAllSettings_Click() - ? -4. RaiseEvent(SaveCookieClickedEvent) - ? SaveCookieButton_Click() - - Valida cookie con API - - SessionManager.SaveSession() ? session.dat - ? -5. RaiseEvent(SaveSettingsClickedEvent) - ? SaveSettingsButton_Click() - - SettingsManager.Load() ? Carica esistente - - Aggiorna TUTTE le checkbox export ? - - SettingsManager.Save() ? settings.json - ? -6. RaiseEvent(SaveDefaultsClickedEvent) - ? SaveDefaultsButton_Click() - - SettingsManager.Load() ? Carica esistente - - Aggiorna defaults e stati aste - - SettingsManager.Save() ? settings.json - ? -7. MessageBox: "Tutte le impostazioni salvate con successo" - ? -? Cookie in session.dat -? Tutte le impostazioni in settings.json -``` - -### Riapertura Applicazione - -``` -1. MainWindow() Constructor - ? -2. LoadDefaultSettings() - ? SessionManager.LoadSession() - ? SettingsCookieTextBox.Text = session.CookieString ? - ? -3. LoadExportSettings() - ? SettingsManager.Load() - ? IncludeMetadata.IsChecked = settings.IncludeMetadata ? - ? RemoveAfterExport.IsChecked = settings.RemoveAfterExport ? - ? OverwriteExisting.IsChecked = settings.OverwriteExisting ? - ? -? Cookie presente in UI -? Checkbox export impostate correttamente -? Nessun messaggio "cookie non valido" -``` - ---- - -## ?? Confronto Prima/Dopo - -### Cookie di Autenticazione - -| Scenario | Prima ? | Dopo ? | -|----------|----------|---------| -| **Avvio app** | TextBox vuota | Cookie caricato da `session.dat` | -| **Validazione** | "Cookie non valido" | Cookie valido ? | -| **Reinserimento** | Necessario ogni avvio | Mai necessario | -| **Funzionamento** | Cookie deve essere reinserito | Cookie persiste automaticamente | - -### Checkbox Export - -| Checkbox | Prima ? | Dopo ? | -|----------|----------|---------| -| **IncludeUsedBids** | Salvata ? | Salvata ? | -| **IncludeLogs** | Salvata ? | Salvata ? | -| **IncludeUserBids** | Salvata ? | Salvata ? | -| **IncludeMetadata** | **NON salvata** ? | **Salvata** ? | -| **RemoveAfterExport** | **NON salvata** ? | **Salvata** ? | -| **OverwriteExisting** | **NON salvata** ? | **Salvata** ? | - ---- - -## ?? Test di Verifica - -### Test 1: Persistenza Cookie - -**Steps**: -1. ? Apri app (prima volta) -2. ? Vai su Impostazioni -3. ? Inserisci cookie valido -4. ? Clicca **Salva** -5. ? Verifica log: `[OK] Cookie valido per utente: Username` -6. ? **Chiudi** applicazione -7. ? **Riapri** applicazione -8. ? Vai su Impostazioni -9. ? **Verifica**: Cookie presente nella TextBox -10. ? **Verifica**: Nessun messaggio "cookie non valido" - -**Risultato atteso**: ? Cookie presente e funzionante - -### Test 2: Persistenza Checkbox Export - -**Steps**: -1. ? Apri app -2. ? Vai su Impostazioni -3. ? Modifica le checkbox: - - ? `IncludeMetadata` ? **Deseleziona** - - ? `RemoveAfterExport` ? **Seleziona** - - ? `OverwriteExisting` ? **Seleziona** -4. ? Clicca **Salva** -5. ? **Chiudi** applicazione -6. ? **Riapri** applicazione -7. ? Vai su Impostazioni -8. ? **Verifica**: - - ? `IncludeMetadata` ? **Deselezionata** - - ? `RemoveAfterExport` ? **Selezionata** - - ? `OverwriteExisting` ? **Selezionata** - -**Risultato atteso**: ? Tutte le checkbox mantengono lo stato - -### Test 3: Salvataggio Completo - -**Steps**: -1. ? Apri app -2. ? Vai su Impostazioni -3. ? Modifica **TUTTE** le impostazioni: - - Cookie di autenticazione - - Percorso export - - Formato export (JSON) - - Tutte le checkbox export - - Anticipo puntata: 300ms - - Prezzo min: 5 - - Prezzo max: 50 - - Max clicks: 10 - - Stati iniziali: "In Pausa" - - Max log asta: 1000 - - Max log globale: 2000 -4. ? Clicca **Salva** -5. ? **Chiudi** applicazione -6. ? **Riapri** applicazione -7. ? Vai su Impostazioni -8. ? **Verifica**: Tutte le impostazioni sono mantenute - -**Risultato atteso**: ? Nessuna impostazione persa - ---- - -## ?? File Modificati - -### 1. `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - -**Modifiche principali**: -- ? `LoadDefaultSettings()`: Aggiunto caricamento cookie da `SessionManager` -- ? `SaveSettingsButton_Click()`: Aggiunte 3 checkbox mancanti nel salvataggio -- ? Aggiunta documentazione inline con sezioni commentate -- ? Rimossi log generici di successo (solo errori e cookie) - -**Righe modificate**: ~50 righe - -**Test**: ? Build riuscita senza errori - ---- - -## ?? Struttura Storage - -### File di Persistenza - -``` -%AppData%\AutoBidder\ -??? session.dat (crittografato DPAPI) -? ??? CookieString ? Cookie autenticazione -? ??? Username ? Nome utente -? ??? RemainingBids ? Puntate residue - -%LocalAppData%\AutoBidder\ -??? settings.json (JSON in chiaro) -? ??? ExportPath ? Percorso export -? ??? LastExportExt ? Formato export (.json/.xml/.csv) -? ??? ExportScope ? Scope export (All/Closed/Unknown/Open) -? ??? ExportOpen ? Esporta aste aperte -? ??? ExportClosed ? Esporta aste chiuse -? ??? ExportUnknown ? Esporta aste unknown -? ??? IncludeOnlyUsedBids ? Include solo puntate utilizzate -? ??? IncludeLogs ? Include log aste -? ??? IncludeUserBids ? Include storico puntate utenti -? ??? IncludeMetadata ? Include metadata (FIX) -? ??? RemoveAfterExport ? Rimuovi dopo export (FIX) -? ??? OverwriteExisting ? Sovrascrivi file esistenti (FIX) -? ??? DefaultBidBeforeDeadlineMs ? Anticipo puntata -? ??? DefaultCheckAuctionOpenBeforeBid ? Verifica stato asta -? ??? DefaultMinPrice ? Prezzo minimo -? ??? DefaultMaxPrice ? Prezzo massimo -? ??? DefaultMaxClicks ? Max clicks -? ??? MaxLogLinesPerAuction ? Max righe log per asta -? ??? MaxGlobalLogLines ? Max righe log globale -? ??? DefaultStartAuctionsOnLoad ? Stato aste al caricamento -? ??? DefaultNewAuctionState ? Stato nuove aste - -??? auctions.json (JSON in chiaro) - ??? [Lista aste salvate] -``` - ---- - -## ?? Lezioni Apprese - -### 1. Doppio Sistema di Storage - -Quando si hanno **due sistemi di persistenza separati**, cruciale: -- ? Documentare CHIARAMENTE cosa va dove -- ? Caricare dati dal sistema CORRETTO -- ? Non confondere i due sistemi - -**Cookie** ? `SessionManager` (crittografato) -**Tutto il resto** ? `SettingsManager` (JSON) - -### 2. Pattern "Load ? Modify ? Save" - -```csharp -// ? PATTERN CORRETTO -private void SaveSettings() -{ - // 1. Carica esistente - var settings = SettingsManager.Load() ?? new AppSettings(); - - // 2. Modifica solo le propriet necessarie - settings.Property1 = newValue; - settings.Property2 = otherValue; - - // 3. Salva (mantiene TUTTO il resto) - SettingsManager.Save(settings); -} - -// ? PATTERN SBAGLIATO -private void SaveSettings() -{ - // Crea nuovo oggetto ? perde tutto - var settings = new AppSettings() - { - Property1 = newValue - }; - - SettingsManager.Save(settings); // Sovrascrive file! -} -``` - -### 3. Simmetria Load/Save - -Per ogni propriet salvata, deve esserci il corrispondente caricamento: - -```csharp -// ? SIMMETRIA CORRETTA -private void LoadSettings() -{ - settings.Property1 = ... - settings.Property2 = ... - settings.Property3 = ... -} - -private void SaveSettings() -{ - settings.Property1 = ... - settings.Property2 = ... - settings.Property3 = ... // Tutte le propriet salvate -} - -// ? ASIMMETRIA (BUG) -private void LoadSettings() -{ - settings.Property1 = ... - settings.Property2 = ... - settings.Property3 = ... // Caricata -} - -private void SaveSettings() -{ - settings.Property1 = ... - settings.Property2 = ... - // Property3 manca ? NON salvata! -} -``` - -### 4. Testing Persistenza - -Per verificare la persistenza, testare **sempre** il ciclo completo: -1. Modifica impostazione -2. Salva -3. **Chiudi applicazione** (non solo tab) -4. **Riapri applicazione** -5. Verifica che l'impostazione sia mantenuta - ---- - -## ?? Note Importanti - -### Sicurezza - -- ? Cookie crittografato con **DPAPI** (Windows Data Protection API) -- ? Solo l'utente corrente pu decrittare `session.dat` -- ? Cookie NON salvato in `settings.json` (che in chiaro) - -### Compatibilit - -- ? Se `session.dat` non esiste ? TextBox vuota (primo avvio) -- ? Se `settings.json` non esiste ? valori default -- ? Se file corrotti ? fallback ai valori default -- ? Nessun crash in caso di errori - -### Performance - -- ? Caricamento veloce (file piccoli ~5-50KB) -- ? Salvataggio asincrono non blocca UI -- ? Serializzazione JSON ottimizzata - ---- - -## ? Checklist Verifiche - -### Persistenza Cookie -- [x] Cookie salvato in `session.dat` crittografato -- [x] Cookie caricato all'avvio in TextBox -- [x] Cookie caricato all'apertura tab Impostazioni -- [x] Nessun messaggio "cookie non valido" con cookie valido -- [x] Funzionamento dopo riavvio applicazione - -### Persistenza Checkbox Export -- [x] `IncludeUsedBids` persiste -- [x] `IncludeLogs` persiste -- [x] `IncludeUserBids` persiste -- [x] `IncludeMetadata` persiste ? (FIX) -- [x] `RemoveAfterExport` persiste ? (FIX) -- [x] `OverwriteExisting` persiste ? (FIX) - -### Persistenza Altre Impostazioni -- [x] Percorso export persiste -- [x] Formato export persiste -- [x] Anticipo puntata persiste -- [x] Prezzo min/max persiste -- [x] Max clicks persiste -- [x] Stati iniziali aste persistono -- [x] Limiti log persistono - -### Build e Test -- [x] Compilazione riuscita senza errori -- [x] Nessun warning rilevante -- [x] Test funzionali passati -- [x] Documentazione aggiornata - ---- - -**Data Refactoring**: 2025 -**Versione**: 5.3+ -**Issue 1**: Cookie non persisteva (non caricato in UI) -**Issue 2**: 3 checkbox export non salvate -**Status**: ? RISOLTO - -## ?? Riferimenti - -- `Services\SessionManager.cs` - Storage cookie crittografato -- `Utilities\SettingsManager.cs` - Storage impostazioni JSON -- `Core\EventHandlers\MainWindow.EventHandlers.Settings.cs` - Gestione eventi impostazioni -- `Core\EventHandlers\MainWindow.EventHandlers.Export.cs` - Caricamento impostazioni export -- `Documentation\FIX_COOKIE_PERSISTENCE.md` - Fix precedente cookie -- `Documentation\FIX_SETTINGS_SAVE_AND_LOGGING.md` - Fix precedente logging diff --git a/Mimante/Documentation/REFACTORING_SUMMARY.md b/Mimante/Documentation/REFACTORING_SUMMARY.md deleted file mode 100644 index fbd185d..0000000 --- a/Mimante/Documentation/REFACTORING_SUMMARY.md +++ /dev/null @@ -1,172 +0,0 @@ -# Refactoring Summary - AutoBidder v4.0 - -## Overview -Il codice stato completamente refactorizzato dividendo la classe `MainWindow` in pi file parziali (partial classes) per migliorare l'organizzazione, la manutenibilit e la leggibilit del codice. - -## Nuova Struttura dei File - -### 1. **MainWindow.xaml.cs** (File Principale) -- Contiene solo l'inizializzazione core e i gestori degli eventi del monitor -- Responsabilit: - - Inizializzazione dei servizi (`AuctionMonitor`) - - Binding degli eventi del monitor - - Gestione degli aggiornamenti dallo stato delle aste - - Coordinamento generale dell'applicazione - -### 2. **MainWindow.Commands.cs** -- Gestione dei comandi WPF (ICommand pattern) -- Implementazioni dei comandi per: - - Avvio/Stop/Pausa globale - - Comandi specifici della griglia (Start/Pause/Stop/Bid per singola asta) - -### 3. **MainWindow.AuctionManagement.cs** -- Logica di gestione delle aste -- Funzionalit: - - Aggiunta aste (da ID o URL) - - Salvataggio e caricamento delle aste - - Validazione e parsing degli input - -### 4. **MainWindow.EventHandlers.Browser.cs** -- Gestori eventi per il browser integrato (WebView2) -- Funzionalit: - - Navigazione (Back/Forward/Refresh/Home) - - Gestione URL e indirizzi - - Menu contestuale personalizzato - - Integrazione con le aste - -### 5. **MainWindow.EventHandlers.Export.cs** -- Gestione dell'esportazione dati -- Funzionalit: - - Esportazione massiva aste - - Esportazione singola asta - - Supporto formati: CSV, JSON, XML - - Configurazione delle opzioni di export - - Rimozione automatica dopo export - -### 6. **MainWindow.EventHandlers.Settings.cs** -- Gestione delle impostazioni e configurazioni -- Funzionalit: - - Salvataggio/caricamento cookie di sessione - - Import cookie dal browser - - Salvataggio preferenze export - - Gestione impostazioni globali - -### 7. **MainWindow.EventHandlers.Stats.cs** -- Gestione delle statistiche e analisi aste chiuse -- Funzionalit: - - Caricamento statistiche da file esportati - - Analisi dati aggregati - - Applicazione raccomandazioni (insights) - - Gestione puntate gratuite - -### 8. **MainWindow.Logging.cs** -- Sistema di logging centralizzato -- Funzionalit: - - Logging colorato per livello (Info/Warning/Error) - - Timestamp automatico - - Auto-scroll intelligente - - Pulizia log - -### 9. **MainWindow.UIUpdates.cs** -- Aggiornamenti dell'interfaccia utente -- Funzionalit: - - Aggiornamento dettagli asta selezionata - - Refresh log asta - - Aggiornamento griglia bidders - - Gestione stato bottoni - - Aggiornamento contatori - -### 10. **MainWindow.UrlParsing.cs** -- Utility per parsing e validazione URL -- Funzionalit: - - Validazione URL Bidoo - - Estrazione ID asta da URL - - Estrazione nome prodotto da URL - - Supporto per formati multipli - -### 11. **MainWindow.UserInfo.cs** -- Gestione informazioni utente e banner -- Funzionalit: - - Timer per aggiornamento periodico - - Aggiornamento banner utente - - Sincronizzazione dati HTML - - Caricamento sessione salvata - - Verifica validit cookie - -### 12. **MainWindow.ButtonHandlers.cs** -- Gestori dei click dei bottoni UI -- Funzionalit: - - Start/Stop/Pause globale - - Aggiunta/Rimozione aste - - Reset impostazioni - - Pulizia liste e log - - Gestione TextBox per parametri asta - -### 13. **MainWindow.EventHandlers.cs** -- File stub per binding XAML -- Contiene solo dichiarazioni per compatibilit XAML -- Le implementazioni reali sono nei file dedicati - -## Vantaggi del Refactoring - -### 1. **Organizzazione Migliorata** -- Ogni file ha una responsabilit specifica e ben definita -- Facile trovare il codice relativo a una funzionalit specifica -- Riduzione della complessit cognitiva - -### 2. **Manutenibilit** -- Modifiche isolate: cambiare la logica di export non impatta altre aree -- Pi facile testare singole funzionalit -- Riduzione dei conflitti in caso di lavoro in team - -### 3. **Leggibilit** -- File pi piccoli e focalizzati (100-300 righe invece di 1000+) -- Nomi file descrittivi che indicano chiaramente il contenuto -- Documentazione XML per ogni partial class - -### 4. **Scalabilit** -- Facile aggiungere nuove funzionalit in file separati -- Struttura modulare permette estensioni future -- Separazione delle preoccupazioni (Separation of Concerns) - -### 5. **Pattern Utilizzati** -- **Partial Classes**: Divisione logica della classe principale -- **Single Responsibility Principle**: Ogni file ha una responsabilit unica -- **Command Pattern**: Separazione dei comandi UI dalla logica -- **Event-Driven Architecture**: Gestione eventi centralizzata - -## Compatibilit -- ? Tutte le funzionalit esistenti sono preservate -- ? Nessuna modifica al file XAML richiesta -- ? Tutti i binding e gli event handler continuano a funzionare -- ? Compilazione riuscita senza errori o warning - -## File Originali Modificati -1. `MainWindow.xaml.cs` - Refactorizzato e ridotto -2. `MainWindow.EventHandlers.cs` - Ridotto a stub - -## File Nuovi Creati -1. `MainWindow.Commands.cs` -2. `MainWindow.AuctionManagement.cs` -3. `MainWindow.EventHandlers.Browser.cs` -4. `MainWindow.EventHandlers.Export.cs` -5. `MainWindow.EventHandlers.Settings.cs` -6. `MainWindow.EventHandlers.Stats.cs` -7. `MainWindow.Logging.cs` -8. `MainWindow.UIUpdates.cs` -9. `MainWindow.UrlParsing.cs` -10. `MainWindow.UserInfo.cs` -11. `MainWindow.ButtonHandlers.cs` - -## Prossimi Passi Consigliati -1. ? Testing completo di tutte le funzionalit -2. Aggiungere unit test per ogni partial class -3. Documentare ogni metodo pubblico con XML comments -4. Considerare l'uso di dependency injection per i servizi -5. Valutare l'estrazione di ulteriori classi helper dove appropriato - -## Note Tecniche -- Il pattern delle partial classes permette di mantenere una singola istanza logica di `MainWindow` -- Tutti i membri (campi, propriet, metodi) sono condivisi tra i file parziali -- I modificatori di accesso (`private`, `public`, ecc.) sono consistenti -- L'ordine di compilazione dei file parziali irrilevante per il compilatore C# diff --git a/Mimante/Documentation/UI_PRODUCT_VALUE_IMPLEMENTATION.md b/Mimante/Documentation/UI_PRODUCT_VALUE_IMPLEMENTATION.md deleted file mode 100644 index c3153ce..0000000 --- a/Mimante/Documentation/UI_PRODUCT_VALUE_IMPLEMENTATION.md +++ /dev/null @@ -1,335 +0,0 @@ -# ?? Product Value Calculator - Implementazione UI Completata - -## ? Stato Implementazione - -L'interfaccia grafica per il calcolo del valore del prodotto stata **completata e integrata** nel pannello "Impostazioni Asta". - -## ?? Dove Trovarla - -### Posizione UI -1. Avvia l'applicazione -2. Aggiungi un'asta alla lista monitorata -3. **Seleziona l'asta** cliccando sulla riga nella griglia -4. Nel **pannello destro "Impostazioni"** (in basso a sinistra) -5. Troverai un **Expander "?? Informazioni Prodotto"** -6. Clicca per espandere la sezione - -### Layout Visivo - -``` -?? IMPOSTAZIONI ?????????????????????????????? -? ? -? Nome Asta ? -? https://it.bidoo.com/auction.php?a=... ? -? ? -? [Browser Interno] [Browser Esterno] ? -? [Copia URL] [Esporta] ? -? ? -? ? ?? Informazioni Prodotto ? -? ?? Compra Subito: 20.00 ? -? ?? Spedizione: - ? -? ?? Limite: 1 volta ogni 30 giorni ? -? ? ? -? ?? ?? Valore Attuale ? -? ? Prezzo attuale: 1.50 ? -? ? Mie puntate: 10 (2.00) ? -? ? ?????????????????????? ? -? ? Costo totale: 3.50 ? -? ? Risparmio: +16.50 (82.5%) ? -? ? ? -? ? ?? Raccomandazione: ? -? ? Conveniente! Continua a puntare. ? -? ? ? -? ?? [?? Carica Info Prodotto] ? -? ? -? Anticipo (ms): [200] Min EUR: [0] ? -? Max EUR: [0] Max Clicks: [0] ? -? ? Verifica stato asta prima di puntare ? -? ? -? [Reset] ? -??????????????????????????????????????????????? -``` - -## ?? Componenti UI - -### 1. Informazioni Statiche -- **Compra Subito**: Prezzo "Compra Subito" del prodotto (estratto dall'HTML) -- **Spedizione**: Spese di spedizione (se disponibili) -- **Limite**: Limite di vincita (es: "1 volta ogni 30 giorni") - -### 2. Valore Calcolato (Dinamico) -Appare solo quando il valore stato calcolato: - -- **Prezzo attuale**: Prezzo corrente dell'asta -- **Mie puntate**: Numero puntate costo (default 0.20/puntata) -- **Costo totale**: Prezzo + Puntate + Spedizione -- **Risparmio**: Differenza vs Compra Subito (+ verde, - rosso) - -### 3. Raccomandazione -Messaggio intelligente basato sulla convenienza: -- ? **Conveniente**: "Conveniente! Continua a puntare." -- ? **Non conveniente**: "Non conviene pi. Stai spendendo troppo." -- ?? **Neutro**: "Valuta attentamente prima di continuare." - -### 4. Pulsante Azione -- **?? Carica Info Prodotto**: Scarica dati dalla pagina dell'asta - - Al clic: Scarica HTML, estrae info, aggiorna UI - - Stato caricamento mostrato sotto il pulsante - -## ?? Quando Si Caricano i Dati - -### Opzione 1: Manuale (Attuale) -1. Selezioni l'asta -2. Espandi "?? Informazioni Prodotto" -3. Clicchi "?? Carica Info Prodotto" -4. Attendi qualche secondo -5. Le informazioni appaiono - -### Opzione 2: Automatico (Da Implementare) -- All'aggiunta dell'asta: Carica automaticamente in background -- Ad ogni puntata: Aggiorna il valore calcolato -- Ogni N secondi: Refresh automatico durante il monitoraggio - -## ?? Dati Estratti dall'HTML - -### Prezzo "Compra Subito" -Cerca questi pattern nell'HTML: -```html - -
20,00
- - -20,00 - - - - Valore: 20,00 - -``` - -### Limite Vincita -```html - - -``` - -## ?? Calcolo del Valore - -### Formula -``` -Costo Puntate = Numero Puntate Utente 0.20 -Costo Totale = Prezzo Attuale + Costo Puntate + Spese Spedizione -Risparmio = (Compra Subito + Spedizione) - Costo Totale -Percentuale = (Risparmio / (Compra Subito + Spedizione)) 100 -``` - -### Esempio Pratico -- **Asta**: 47 Puntate (valore 9.40) -- **Prezzo attuale**: 0.33 -- **Mie puntate**: 10 0.20 = 2.00 -- **Spedizione**: 0 (digitale) -- **Costo totale**: 0.33 + 2.00 = **2.33** -- **Compra Subito**: 9.40 -- **Risparmio**: 9.40 - 2.33 = **+7.07 (75.2%)** ? - -**Raccomandazione**: Conveniente! Vale la pena continuare. - -## ?? Completamento Implementazione - -### Mancano Solo (2 Step): - -#### Step 1: Binding Evento nel MainWindow.xaml -Aggiungi alla definizione del `AuctionMonitorControl`: - -```xml - -``` - -#### Step 2: Handler nel MainWindow -File: `Core/MainWindow.ControlEvents.cs` - -```csharp -private void AuctionMonitor_RefreshProductInfoClicked(object sender, RoutedEventArgs e) -{ - RefreshProductInfo_Click(sender, e); -} -``` - -File: `Core/MainWindow.ButtonHandlers.cs` (o nuovo file) - -```csharp -private async void RefreshProductInfo_Click(object sender, RoutedEventArgs e) -{ - if (_selectedAuction == null) - { - MessageBox.Show( - "Seleziona un'asta dalla griglia", - "Nessuna Selezione", - MessageBoxButton.OK, - MessageBoxImage.Information); - return; - } - - try - { - // Mostra stato caricamento - AuctionMonitor.ProductInfoStatusText.Text = "Caricamento..."; - - // Scarica info prodotto - var apiClient = new BidooApiClient(); - var session = _auctionMonitor.GetSession(); - apiClient.InitializeSession(session.AuthToken, session.Username); - - bool extracted = await AuctionMonitorProductValueExtensions.InitializeProductInfoAsync( - apiClient, - _selectedAuction.AuctionInfo - ); - - if (extracted) - { - // Aggiorna UI con i dati estratti - UpdateProductInfoDisplay(_selectedAuction); - AuctionMonitor.ProductInfoStatusText.Text = "Informazioni caricate"; - Log($"[INFO] Informazioni prodotto caricate per: {_selectedAuction.Name}", LogLevel.Success); - } - else - { - AuctionMonitor.ProductInfoStatusText.Text = "Nessuna informazione trovata"; - Log($"[WARN] Impossibile estrarre info prodotto per: {_selectedAuction.Name}", LogLevel.Warn); - } - } - catch (Exception ex) - { - AuctionMonitor.ProductInfoStatusText.Text = $"Errore: {ex.Message}"; - Log($"[ERROR] Caricamento info prodotto: {ex.Message}", LogLevel.Error); - MessageBox.Show($"Errore durante il caricamento:\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error); - } -} - -private void UpdateProductInfoDisplay(AuctionViewModel vm) -{ - var auction = vm.AuctionInfo; - - // Aggiorna campi statici - if (auction.BuyNowPrice.HasValue) - { - AuctionMonitor.ProductBuyNowPriceText.Text = $"{auction.BuyNowPrice.Value:F2}"; - } - else - { - AuctionMonitor.ProductBuyNowPriceText.Text = "-"; - } - - if (auction.ShippingCost.HasValue && auction.ShippingCost.Value > 0) - { - AuctionMonitor.ProductShippingCostText.Text = $"{auction.ShippingCost.Value:F2}"; - } - else - { - AuctionMonitor.ProductShippingCostText.Text = "-"; - } - - if (auction.HasWinLimit && !string.IsNullOrWhiteSpace(auction.WinLimitDescription)) - { - AuctionMonitor.ProductWinLimitText.Text = auction.WinLimitDescription; - } - else - { - AuctionMonitor.ProductWinLimitText.Text = "Nessun limite"; - } - - // Calcola e mostra valore se disponibile - if (auction.CalculatedValue != null) - { - UpdateProductValueDisplay(auction.CalculatedValue); - } -} - -private void UpdateProductValueDisplay(ProductValue value) -{ - // Mostra il pannello valore - AuctionMonitor.ProductValueBorder.Visibility = Visibility.Visible; - - // Aggiorna campi - AuctionMonitor.ValueCurrentPriceText.Text = $"{value.CurrentPrice:F2}"; - AuctionMonitor.ValueMyBidsText.Text = $"{value.MyBids} 0.20 = {value.MyBidsCost:F2}"; - AuctionMonitor.ValueTotalCostText.Text = $"{value.TotalCostIfWin:F2}"; - - if (value.Savings.HasValue) - { - var savingsText = value.Savings.Value >= 0 - ? $"+{value.Savings.Value:F2} ({value.SavingsPercentage:F1}%)" - : $"{value.Savings.Value:F2} ({value.SavingsPercentage:F1}%)"; - - AuctionMonitor.ValueSavingsText.Text = savingsText; - AuctionMonitor.ValueSavingsText.Foreground = value.IsWorthIt - ? new SolidColorBrush(Color.FromRgb(0, 216, 0)) // Verde - : new SolidColorBrush(Color.FromRgb(232, 17, 35)); // Rosso - - // Mostra raccomandazione - AuctionMonitor.ValueRecommendationBorder.Visibility = Visibility.Visible; - - if (value.IsWorthIt) - { - AuctionMonitor.ValueRecommendationText.Text = - "Conveniente! Vale la pena continuare a puntare."; - } - else - { - AuctionMonitor.ValueRecommendationText.Text = - "Non conviene pi. Il costo totale supera il prezzo 'Compra Subito'."; - } - } -} -``` - -## ?? Note Implementative - -### Aggiornamento Automatico del Valore -Per aggiornare il valore durante il monitoraggio, aggiungi in `Monitor_OnAuctionUpdated`: - -```csharp -// Aggiorna valore ogni 10 reset per ridurre overhead -if (auction.ResetCount % 10 == 0 && auction.CalculatedValue != null) -{ - AuctionMonitorProductValueExtensions.UpdateProductValue(auction, state); - - if (_selectedAuction == auction) - { - UpdateProductValueDisplay(auction.CalculatedValue); - } -} -``` - -### Persistenza -Le informazioni del prodotto vengono salvate automaticamente nel file JSON delle aste: -- `BuyNowPrice` -- `ShippingCost` -- `HasWinLimit` -- `WinLimitDescription` - -## ? Testing - -1. **Test caricamento info**: - - Aggiungi asta, seleziona, clicca "Carica Info Prodotto" - - Verifica che i campi si popolino - -2. **Test calcolo valore**: - - Dopo aver caricato info, fai alcune puntate - - Verifica che il valore si aggiorni - -3. **Test risparmio positivo/negativo**: - - Con asta economica: Vedi risparmio positivo (verde) - - Con asta costosa: Vedi risparmio negativo (rosso) - -4. **Test limite vincita**: - - Asta con limite: Vedi "1 volta ogni X giorni" - - Asta senza limite: Vedi "Nessun limite" - -## ?? Ready! - -L'UI pronta e funzionale. Mancano solo i 2 piccoli step finali per collegare l'handler! diff --git a/Mimante/Documentation/XAML_REFACTORING_CHECKLIST.md b/Mimante/Documentation/XAML_REFACTORING_CHECKLIST.md deleted file mode 100644 index cdf09fd..0000000 --- a/Mimante/Documentation/XAML_REFACTORING_CHECKLIST.md +++ /dev/null @@ -1,304 +0,0 @@ -# ? XAML Refactoring - Checklist Completamento - -## ?? Obiettivo -Refactoring completo del MainWindow.xaml utilizzando UserControls modulari per migliorare manutenibilit, scalabilit e design. - ---- - -## ? Fase 1: Creazione UserControls - -### AuctionMonitorControl -- [x] Creato `Controls/AuctionMonitorControl.xaml` (430 linee) -- [x] Creato `Controls/AuctionMonitorControl.xaml.cs` -- [x] Implementati 17 Routed Events -- [x] Header con toolbar (Start, Pause, Stop, Add, Remove) -- [x] Griglia aste con 7 colonne -- [x] Pannello dettagli con impostazioni -- [x] Lista bidders con DataGrid -- [x] Log asta specifico -- [x] Log globale nel footer - -### BrowserControl -- [x] Creato `Controls/BrowserControl.xaml` (120 linee) -- [x] Creato `Controls/BrowserControl.xaml.cs` -- [x] Implementati 6 Routed Events -- [x] Toolbar navigazione (Back, Forward, Refresh, Home) -- [x] Barra indirizzi con SSL indicator -- [x] WebView2 embedded -- [x] Bottone "Aggiungi Asta" - -### StatisticsControl -- [x] Creato `Controls/StatisticsControl.xaml` (80 linee) -- [x] Creato `Controls/StatisticsControl.xaml.cs` -- [x] Implementato 1 Routed Event -- [x] Header con bottone carica -- [x] DataGrid con 5 colonne statistiche -- [x] Footer con status e progress bar - -### SettingsControl -- [x] Creato `Controls/SettingsControl.xaml` (200 linee) -- [x] Creato `Controls/SettingsControl.xaml.cs` -- [x] Implementati 8 Routed Events -- [x] Sezione configurazione sessione (cookie) -- [x] Guida ottenimento cookie -- [x] Sezione impostazioni export -- [x] Formato export (CSV/JSON/XML) -- [x] Opzioni export (checkboxes) -- [x] Sezione impostazioni predefinite aste - ---- - -## ? Fase 2: Refactoring MainWindow.xaml - -- [x] Ridotto da 1000+ a ~100 linee -- [x] Implementato TabControl con 4 tab -- [x] Applicati stili personalizzati per tab headers -- [x] Integrati UserControls in ogni tab -- [x] Collegati eventi UserControls - -### Tab Create -- [x] ?? Monitor Aste ? AuctionMonitorControl -- [x] ?? Browser ? BrowserControl -- [x] ?? Statistiche ? StatisticsControl -- [x] ?? Impostazioni ? SettingsControl - ---- - -## ? Fase 3: Aggiornamento Code-Behind - -### MainWindow.xaml.cs -- [x] Aggiunto property exposure per UserControl elements -- [x] Mantenuta compatibilit con codice esistente -- [x] Configurato DataContext -- [x] Inizializzati servizi e timers - -### MainWindow.ControlEvents.cs (NEW) -- [x] Creato file per event routing -- [x] Implementati handler per AuctionMonitorControl (11 eventi) -- [x] Implementati handler per BrowserControl (6 eventi) -- [x] Implementati handler per StatisticsControl (1 evento) -- [x] Implementati handler per SettingsControl (8 eventi) -- [x] Collegamento ai metodi esistenti - ---- - -## ? Fase 4: Testing & Validation - -### Compilation -- [x] Build riuscita senza errori -- [x] Zero warning -- [x] Tutti i riferimenti risolti - -### Design-Time -- [x] XAML Designer carica MainWindow.xaml -- [x] XAML Designer carica ogni UserControl -- [x] IntelliSense funziona correttamente -- [x] Property binding funzionanti - -### Runtime (Da Testare) -- [ ] Avvio applicazione -- [ ] Navigazione tra tab -- [ ] Aggiunta/rimozione aste -- [ ] Monitoraggio aste funzionante -- [ ] Browser navigazione -- [ ] Caricamento statistiche -- [ ] Salvataggio impostazioni -- [ ] Export aste - ---- - -## ? Fase 5: Documentazione - -- [x] Creato `REFACTORING_SUMMARY.md` (code-behind) -- [x] Creato `XAML_REFACTORING_SUMMARY.md` (XAML) -- [x] Creato `ARCHITECTURE_OVERVIEW.md` (overview) -- [x] Creato `XAML_REFACTORING_CHECKLIST.md` (questo file) -- [x] XML comments in UserControls -- [x] README.md aggiornato (TODO) - ---- - -## ? Fase 6: Pulizia & Ottimizzazione - -### Codice Legacy -- [ ] Valutare rimozione `MainWindow.EventHandlers.Browser.cs` (logica ora in BrowserControl) -- [ ] Consolidare file partial se necessario -- [ ] Rimuovere codice morto/commentato - -### Performance -- [x] Lazy loading tab implementato (built-in TabControl) -- [x] Async operations mantenute -- [x] Virtual scrolling DataGrid -- [ ] Memory profiling (future) - -### UI/UX -- [x] Palette colori consistente -- [x] Icone emoji per usabilit -- [x] Layout responsive -- [ ] Accessibility (ARIA, keyboard navigation) -- [ ] Temi dark/light (future) - ---- - -## ?? Checklist Post-Refactoring - -### Immediate Actions (Da fare subito) -1. [ ] **Test Completo Applicazione** - - Avviare l'app - - Testare ogni tab - - Verificare tutti i flussi utente - - Log eventuali bug - -2. [ ] **Code Review** - - Revisione UserControls - - Revisione event routing - - Verificare best practices WPF - -3. [ ] **Git Commit** - ```bash - git add . - git commit -m "feat: Refactoring XAML con UserControls modulari - - - Creati 4 UserControls (AuctionMonitor, Browser, Statistics, Settings) - - MainWindow.xaml ridotto da 1000+ a ~100 linee - - Implementato TabControl con routing eventi - - Mantiene 100% compatibilit con codice esistente - - Aggiunta documentazione completa" - - git push origin main - ``` - -### Short-Term (Prossime settimane) -4. [ ] **Unit Testing UserControls** - - Test isolati per ogni controllo - - Test event propagation - - Test data binding - -5. [ ] **ViewModels Dedicati** - - `AuctionMonitorViewModel` - - `BrowserViewModel` - - `StatisticsViewModel` - - `SettingsViewModel` - -6. [ ] **Styling System** - - ResourceDictionary condivisi - - Temi customizzabili - - Branding consistente - -### Medium-Term (Prossimi mesi) -7. [ ] **Dependency Injection** - - Configurare DI container - - Iniettare servizi nei ViewModels - - Eliminare dipendenze dirette - -8. [ ] **Advanced Features** - - Drag & drop aste nella griglia - - Filtri e sorting avanzati - - Export batch con progress - - Notifiche sistema - -9. [ ] **Accessibility & Localization** - - WCAG 2.1 compliance - - Keyboard shortcuts - - Multilingua (IT, EN, FR, ES, DE) - -### Long-Term (Future) -10. [ ] **Plugin Architecture** - - Interface per plugin - - Dynamic loading UserControls - - Extension marketplace - -11. [ ] **Cloud Integration** - - Sync impostazioni cloud - - Backup automatico - - Multi-device support - -12. [ ] **Analytics & Telemetry** - - Usage statistics - - Error reporting automatico - - Performance monitoring - ---- - -## ?? Metriche Successo - -| Obiettivo | Target | Status | -|-----------|--------|--------| -| File XAML ridotto | <200 linee | ? 100 linee | -| UserControls creati | 4+ | ? 4 | -| Compatibilit | 100% | ? 100% | -| Build errors | 0 | ? 0 | -| Documentazione | Completa | ? Completa | -| Design consistency | Alta | ? Alta | -| Testabilit | >80% | ? ~85% | -| Performance | Nessun degrado | ? Migliorata | - ---- - -## ?? Known Issues & Workarounds - -### Issue 1: WebView2 Initialization -**Problema**: WebView2 potrebbe non inizializzarsi al primo avvio -**Workaround**: Installare WebView2 Runtime -**Fix Permanente**: Bundling WebView2 nell'installer - -### Issue 2: Event Routing Delay -**Problema**: Primo click su bottone potrebbe avere delay -**Workaround**: Nessuno necessario (cold start normale) -**Fix Permanente**: Preload UserControls critici - -### Issue 3: TabControl Memory -**Problema**: Tab non vengono unloaded quando non visibili -**Workaround**: Manuale GC se necessario -**Fix Permanente**: Implementare lazy unloading - ---- - -## ?? Risorse Utili - -### WPF Best Practices -- [Microsoft WPF Guide](https://docs.microsoft.com/en-us/dotnet/desktop/wpf/) -- [MVVM Pattern](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/enterprise-application-patterns/mvvm) -- [UserControls vs CustomControls](https://stackoverflow.com/questions/471059/) - -### Tools -- **XAML Styler**: Formattazione XAML automatica -- **Snoop**: WPF debugging visual tree -- **dotMemory**: Memory profiling -- **ReSharper**: Code analysis - ---- - -## ?? Conclusioni - -### ? Completato con Successo -Il refactoring XAML stato completato con successo, creando una base solida e scalabile per AutoBidder v4.0. L'applicazione ora segue le best practices WPF moderne con: - -- ? Architettura modulare e manutenibile -- ? Separazione chiara delle responsabilit -- ? Design professionale e consistente -- ? Compatibilit 100% retroattiva -- ? Documentazione completa - -### ?? Pronto per Produzione -L'applicazione pronta per: -- Testing estensivo -- Deploy in produzione -- Future estensioni -- Sviluppo in team - -### ?? Benefici Misurabili -- **Manutenibilit**: +400% (da file monolitico a moduli) -- **Testabilit**: +300% (controlli isolati) -- **Leggibilit**: +500% (file piccoli e focused) -- **Scalabilit**: ? (architettura estendibile) - ---- - -**Data Completamento**: 2024 -**Versione**: AutoBidder v4.0 -**Status**: ? **REFACTORING COMPLETO** - ---- - -?? **Next Steps**: Procedi con testing e validazione funzionale! ?? diff --git a/Mimante/Documentation/XAML_REFACTORING_SUMMARY.md b/Mimante/Documentation/XAML_REFACTORING_SUMMARY.md deleted file mode 100644 index 539cdc7..0000000 --- a/Mimante/Documentation/XAML_REFACTORING_SUMMARY.md +++ /dev/null @@ -1,360 +0,0 @@ -# XAML Refactoring Summary - AutoBidder v4.0 - -## Overview -Il file MainWindow.xaml stato completamente refactorizzato utilizzando **UserControls modulari** organizzati in un **TabControl**. Questo approccio segue le best practices WPF e migliora drasticamente la manutenibilit del codice UI. - -## Nuova Struttura UI - -### MainWindow.xaml (File Principale) -- Contiene solo il TabControl principale con 4 tab -- Ogni tab ospita un UserControl dedicato -- Design pulito e professionale con stili personalizzati - -### UserControls Creati - -#### 1. **AuctionMonitorControl.xaml** (`Controls/`) -**Responsabilit**: Monitoraggio e gestione aste in tempo reale - -**Sezioni**: -- **Header Toolbar**: - - Titolo con conteggio aste - - Info utente (username e crediti) - - Bottoni: Avvia, Pausa, Stop, Aggiungi, Rimuovi - -- **Contenuto Principale** (2 colonne con splitter): - - **Lista Aste** (sinistra): - - DataGrid con aste monitorate - - Colonne: Nome, Timer, Prezzo, Ultimo, Stato, Reset, Click - - - **Dettagli Asta** (destra): - - Info asta selezionata - - Impostazioni asta (Timer, Delay, Prezzi, etc.) - - Lista bidders - - Log asta specifico - -- **Footer**: - - Log globale con scrolling automatico - - Bottone pulizia log - -**Eventi Esposti** (17 eventi via Routed Events): -- StartClicked, PauseAllClicked, StopClicked -- AddUrlClicked, RemoveUrlClicked -- AuctionSelectionChanged -- CopyUrlClicked, ResetSettingsClicked -- ClearBiddersClicked, ClearLogClicked, ClearGlobalLogClicked -- TimerClickChanged, DelayMsChanged -- MinPriceChanged, MaxPriceChanged -- MinResetsChanged, MaxResetsChanged, MaxClicksChanged - ---- - -#### 2. **BrowserControl.xaml** (`Controls/`) -**Responsabilit**: Browser integrato per navigazione Bidoo.com - -**Sezioni**: -- **Toolbar**: - - Bottoni navigazione: Indietro, Avanti, Ricarica, Home - - Barra indirizzi con icona SSL - - Bottoni: Vai, Aggiungi Asta - -- **WebView2**: - - Browser Chromium embedded - - Navigazione completa - - Context menu personalizzato - -**Eventi Esposti** (6 eventi): -- BrowserBackClicked, BrowserForwardClicked -- BrowserRefreshClicked, BrowserHomeClicked -- BrowserGoClicked, BrowserAddAuctionClicked - ---- - -#### 3. **StatisticsControl.xaml** (`Controls/`) -**Responsabilit**: Analisi statistiche aste chiuse - -**Sezioni**: -- **Header**: - - Titolo con icona - - Bottone "Carica Statistiche" - -- **DataGrid Statistiche**: - - Colonne: Prodotto, Prezzo Medio, Click Medi, Vincitore Frequente, # Aste - - Sorting e alternating rows - -- **Footer**: - - Status text - - Progress bar per caricamento - -**Eventi Esposti** (1 evento): -- LoadClosedAuctionsClicked - ---- - -#### 4. **SettingsControl.xaml** (`Controls/`) -**Responsabilit**: Configurazioni applicazione - -**Sezioni**: -- **Configurazione Sessione**: - - TextBox per cookie __stattrb - - Bottoni: Salva, Importa dal Browser, Cancella - - Guida passo-passo per ottenere il cookie - -- **Impostazioni Export**: - - Percorso export con bottone Sfoglia - - Formato: RadioButtons (CSV, JSON, XML) - - Opzioni: CheckBoxes (include logs, bidders, etc.) - - Bottoni: Salva, Ripristina - -- **Impostazioni Predefinite Aste**: - - Valori default per nuove aste - - Timer, Delay, Prezzi, Max Click - - Bottoni: Salva, Reset - -**Eventi Esposti** (8 eventi): -- SaveCookieClicked, ImportCookieClicked, CancelCookieClicked -- ExportBrowseClicked, SaveSettingsClicked, CancelSettingsClicked -- SaveDefaultsClicked, CancelDefaultsClicked - ---- - -## File Struttura - -``` -AutoBidder/ -??? MainWindow.xaml # TabControl principale -??? MainWindow.xaml.cs # Core initialization -??? MainWindow.ControlEvents.cs # NEW: Event routing da UserControls -??? MainWindow.Commands.cs # Command implementations -??? MainWindow.AuctionManagement.cs # Auction CRUD -??? MainWindow.EventHandlers.Browser.cs # Browser logic (legacy, ora deprecato) -??? MainWindow.EventHandlers.Export.cs # Export logic -??? MainWindow.EventHandlers.Settings.cs # Settings logic -??? MainWindow.EventHandlers.Stats.cs # Statistics logic -??? MainWindow.Logging.cs # Logging system -??? MainWindow.UIUpdates.cs # UI updates -??? MainWindow.UrlParsing.cs # URL utilities -??? MainWindow.UserInfo.cs # User info & session -??? MainWindow.ButtonHandlers.cs # Button handlers (legacy) -??? Controls/ - ??? AuctionMonitorControl.xaml # Monitor aste UI - ??? AuctionMonitorControl.xaml.cs # Event handlers - ??? BrowserControl.xaml # Browser UI - ??? BrowserControl.xaml.cs # Event handlers - ??? StatisticsControl.xaml # Statistiche UI - ??? StatisticsControl.xaml.cs # Event handlers - ??? SettingsControl.xaml # Impostazioni UI - ??? SettingsControl.xaml.cs # Event handlers -``` - ---- - -## Pattern e Tecniche Utilizzate - -### 1. **UserControl Pattern** -Ogni schermata principale un UserControl riutilizzabile e testabile in isolamento. - -### 2. **Routed Events** -Gli UserControls espongono eventi personalizzati che "bubblano" fino al MainWindow: -```csharp -// Definizione evento nel UserControl -public static readonly RoutedEvent StartClickedEvent = - EventManager.RegisterRoutedEvent("StartClicked", ...); - -// Sottoscrizione nel MainWindow - -``` - -### 3. **Property Exposure** -Il MainWindow espone propriet pubbliche che mappano agli elementi interni dei UserControls: -```csharp -public DataGrid MultiAuctionsGrid => AuctionMonitor.MultiAuctionsGrid; -public RichTextBox LogBox => AuctionMonitor.LogBox; -``` -Questo mantiene la compatibilit con il codice esistente senza modifiche massive. - -### 4. **Event Routing** -`MainWindow.ControlEvents.cs` funge da **Event Router** che collega gli eventi dei controlli ai metodi esistenti: -```csharp -private void AuctionMonitor_StartClicked(object sender, RoutedEventArgs e) -{ - StartButton_Click(sender, e); // Chiama il metodo esistente -} -``` - -### 5. **Separation of Concerns** -- **UI** (XAML): Definisce solo l'aspetto e la struttura -- **Code-Behind** (xaml.cs): Gestisce solo eventi locali e notifiche -- **MainWindow**: Coordina la logica business tra i controlli - ---- - -## Vantaggi del Refactoring XAML - -### 1. **Modularit** -? Ogni UserControl pu essere sviluppato, testato e debuggato indipendentemente -? Riutilizzabilit: i controlli possono essere usati in altre finestre/applicazioni -? Facilit di manutenzione: modifiche isolate senza impatto globale - -### 2. **Design-Time Experience** -? Designer di Visual Studio funziona perfettamente su ogni controllo -? IntelliSense completo per binding e propriet -? Anteprima separata di ogni controllo - -### 3. **Performance** -? Lazy loading: i tab caricano il contenuto solo quando selezionati -? Minor overhead iniziale dell'applicazione -? Rendering pi efficiente con UI compartimentata - -### 4. **Scalabilit** -? Facile aggiungere nuovi tab/controlli -? Struttura pronta per supportare plugins/estensioni -? Testing UI automatizzato pi semplice - -### 5. **Leggibilit** -? File XAML pi piccoli (~100-300 righe vs 1000+) -? Struttura gerarchica chiara e intuitiva -? Nomi descrittivi per ogni componente - ---- - -## Compatibilit Retroattiva - -### ? 100% Compatibile -Il refactoring mantiene la **completa compatibilit** con il codice esistente: - -1. **Property Exposure**: Tutti gli elementi UI sono accessibili come prima - ```csharp - MultiAuctionsGrid.ItemsSource = _auctionViewModels; // Funziona ancora! - ``` - -2. **Event Routing**: Gli eventi vengono inoltrati ai metodi esistenti - ```csharp - StartButton_Click() // Chiamato quando si clicca "Avvia" nel controllo - ``` - -3. **Nessuna Modifica Richiesta**: - - ? Tutti i file `MainWindow.*.cs` funzionano senza modifiche - - ? ViewModels, Services, Models inalterati - - ? Logica business intatta - ---- - -## Design UI Migliorato - -### Palette Colori Consistente -- **Primary**: `#3498DB` (Blu) - Azioni principali -- **Success**: `#27AE60` (Verde) - Operazioni riuscite -- **Warning**: `#F39C12` (Arancione) - Attenzione -- **Danger**: `#E74C3C` (Rosso) - Stop/Elimina -- **Dark**: `#2C3E50` (Blu scuro) - Backgrounds -- **Light**: `#ECF0F1` (Grigio chiaro) - Alternanza righe - -### Icone Emoji -Utilizzo di emoji per migliorare l'usabilit: -- ?? Monitor Aste -- ?? Browser -- ?? Statistiche -- ?? Impostazioni -- ? Avvia -- ? Pausa -- ? Stop -- ? Aggiungi -- ? Rimuovi -- ?? Ricarica -- ?? Log -- ?? SSL - -### Responsive Layout -- GridSplitter per ridimensionare sezioni -- ScrollViewer dove necessario -- Adaptive sizing per risoluzioni diverse - ---- - -## Testing e Validazione - -### ? Test Effettuati -1. **Compilazione**: ? Build riuscita senza errori -2. **Binding**: ? Tutti i binding funzionano correttamente -3. **Eventi**: ? Tutti gli eventi si propagano correttamente -4. **Navigation**: ? Tab switching funziona perfettamente -5. **Designer**: ? XAML Designer carica tutti i controlli - -### ?? Test Raccomandati -- [ ] Test funzionali completi di ogni tab -- [ ] Test WebView2 inizializzazione e navigazione -- [ ] Test aggiunta/rimozione aste dalla UI -- [ ] Test caricamento statistiche -- [ ] Test salvataggio/caricamento impostazioni -- [ ] Test su risoluzioni diverse (HD, FullHD, 4K) - ---- - -## Prossimi Passi Consigliati - -### 1. **Rimozione Codice Legacy** (Opzionale) -Alcuni file partial potrebbero essere semplificati ora che la logica nei controlli: -- `MainWindow.EventHandlers.Browser.cs` ? Logica ora in `BrowserControl` -- Valutare consolidamento di altri file - -### 2. **ViewModels per UserControls** -Creare ViewModels dedicati per ogni controllo: -``` -ViewModels/ -??? AuctionMonitorViewModel.cs -??? BrowserViewModel.cs -??? StatisticsViewModel.cs -??? SettingsViewModel.cs -``` - -### 3. **Dependency Injection** -Iniettare servizi nei ViewModels invece di passare dal MainWindow: -```csharp -public AuctionMonitorControl(IAuctionMonitor monitor, ILogger logger) -{ - _monitor = monitor; - _logger = logger; -} -``` - -### 4. **Data Binding Avanzato** -Sostituire event handlers con Command binding dove possibile: -```xaml - + + + + + +
+
+ + + + + + +
+
+ + @if (!string.IsNullOrEmpty(errorMessage)) + { +
+
+ +
+ Limitazione Browser: @errorMessage +
+
+
+ } + + @if (!string.IsNullOrEmpty(extractedCookie)) + { +
+
+
+ +
+ Cookie Estratto: +
+ +
+
+
+
+ + + Vai a Impostazioni + +
+
+
+ } + +
+ +
+ +
+
+ +
+
?? Come Usare il Browser Integrato
+
    +
  1. Clicca su "Apri Bidoo" per caricare il sito
  2. +
  3. Effettua il login con le tue credenziali Bidoo
  4. +
  5. Clicca su "Estrai Cookie" per recuperare il cookie di sessione
  6. +
  7. Il cookie verr copiato automaticamente negli appunti
  8. +
  9. Vai alla pagina Impostazioni e incollalo nella sezione "Sessione Bidoo"
  10. +
+
+ + + Nota: A causa delle limitazioni CORS, il cookie potrebbe non essere accessibile automaticamente. + In tal caso, usa gli strumenti sviluppatore del browser (F12) per estrarlo manualmente. + +
+
+
+
+ +
+
+
Metodo Alternativo (Consigliato)
+
+
+

Se l'iframe non funziona correttamente, usa questo metodo:

+
+
+
+ +
+
+
Apri Bidoo in una Nuova Scheda
+ + https://it.bidoo.com + +
+
+ +
+
+ +
+
+
Estrai il Cookie Manualmente
+

Usa F12 ? Application/Storage ? Cookies ? bidoo.com ? Copia __stattrb

+
+
+ +
+
+ +
+
+
Incolla nelle Impostazioni
+ + Vai alle Impostazioni + +
+
+
+
+
+ + + + +@code { + private ElementReference iframeElement; + private string currentUrl = "about:blank"; + private string iframeUrl = "about:blank"; + private bool canGoBack = false; + private bool canGoForward = false; + private string? errorMessage = null; + private string? extractedCookie = null; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + // Inizializza listener iframe + await JSRuntime.InvokeVoidAsync("initializeBrowserFrame"); + } + } + + private async Task NavigateToBidoo() + { + try + { + iframeUrl = "https://it.bidoo.com"; + currentUrl = iframeUrl; + errorMessage = null; + StateHasChanged(); + } + catch (Exception ex) + { + errorMessage = $"Errore durante la navigazione: {ex.Message}"; + } + } + + private async Task NavigateBack() + { + try + { + await JSRuntime.InvokeVoidAsync("navigateBack"); + canGoBack = await JSRuntime.InvokeAsync("canGoBack"); + } + catch + { + errorMessage = "Navigazione indietro non disponibile"; + } + } + + private async Task NavigateForward() + { + try + { + await JSRuntime.InvokeVoidAsync("navigateForward"); + canGoForward = await JSRuntime.InvokeAsync("canGoForward"); + } + catch + { + errorMessage = "Navigazione avanti non disponibile"; + } + } + + private async Task RefreshPage() + { + try + { + await JSRuntime.InvokeVoidAsync("refreshFrame"); + errorMessage = null; + } + catch (Exception ex) + { + errorMessage = $"Errore durante il refresh: {ex.Message}"; + } + } + + private async Task ExtractCookie() + { + try + { + // Tenta di estrarre il cookie tramite JavaScript + extractedCookie = await JSRuntime.InvokeAsync("extractCookie", "bidoo.com"); + + if (string.IsNullOrEmpty(extractedCookie)) + { + errorMessage = "Impossibile estrarre il cookie automaticamente. Le limitazioni CORS bloccano l'accesso. Usa il metodo manuale F12."; + } + else + { + // Copia automaticamente negli appunti + await CopyCookie(); + errorMessage = null; + } + } + catch (Exception ex) + { + errorMessage = $"Errore estrazione cookie: {ex.Message}. Usa il metodo manuale con F12."; + extractedCookie = null; + } + } + + private async Task CopyCookie() + { + if (!string.IsNullOrEmpty(extractedCookie)) + { + await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", extractedCookie); + await JSRuntime.InvokeVoidAsync("alert", "? Cookie copiato negli appunti!"); + } + } +} diff --git a/Mimante/Pages/FreeBids.razor b/Mimante/Pages/FreeBids.razor new file mode 100644 index 0000000..7a3f89e --- /dev/null +++ b/Mimante/Pages/FreeBids.razor @@ -0,0 +1,406 @@ +@page "/freebids" +@inject AuctionMonitor AuctionMonitor +@inject IJSRuntime JSRuntime + +Puntate Gratuite - AutoBidder + +
+
+
+ +

Puntate Gratuite

+
+
+ + +
+
+ + +
+
+ +
+
?? Funzionalit in Sviluppo
+

+ Il sistema di raccolta automatica delle puntate gratuite attualmente in fase di sviluppo. +

+

+ Prossimamente: Rilevamento automatico delle aste con puntate gratuite, + partecipazione automatica e statistiche dettagliate. +

+
+
+
+ + +
+
+
+
+ +

@totalFreeBids

+

Puntate Gratuite Oggi

+
+
+
+
+
+
+ +

@usedFreeBids

+

Puntate Utilizzate

+
+
+
+
+
+
+ +

@pendingFreeBids

+

In Attesa

+
+
+
+
+
+
+ +

@totalWins

+

Aste Vinte

+
+
+
+
+ + +
+
+
Aste con Puntate Gratuite Disponibili
+
+
+
+ + + + + + + + + + + + + @if (freeBidsAuctions.Count == 0) + { + + + + } + else + { + @foreach (var auction in freeBidsAuctions) + { + + + + + + + + + } + } + +
Prodotto Puntate Gratuite Scadenza Prezzo Attuale Stato Azioni
+
+ +
Nessuna asta con puntate gratuite disponibile
+

Le aste appariranno automaticamente quando disponibili

+
+
@auction.ProductName + + @auction.FreeBidsAvailable + + @auction.ExpiryTime.ToString("dd/MM/yyyy HH:mm")@auction.CurrentPrice.ToString("F2") + + @auction.Status + + +
+ + +
+
+
+
+
+ + +
+
+
Configurazione Puntate Gratuite
+
+
+
+
+
+ + +
+ + Rileva e raccogli automaticamente le puntate gratuite disponibili + +
+ +
+
+ + +
+ + Usa automaticamente le puntate gratuite sulle aste selezionate + +
+ +
+ + + + Usa puntate gratuite solo su aste sotto questo prezzo + +
+ +
+ + + + Tempo minimo prima della scadenza per usare puntate gratuite + +
+
+ + + + Disponibile nella prossima versione + +
+
+ + +
+
+
Come Funzioneranno le Puntate Gratuite
+
+
+
+
+
Rilevamento Automatico
+

+ AutoBidder scansioner continuamente Bidoo.com per identificare le aste che offrono puntate gratuite. +

+ +
Raccolta Puntate
+

+ Le puntate gratuite verranno raccolte automaticamente non appena disponibili, prima che scadano. +

+ +
Utilizzo Strategico
+

+ Le puntate verranno utilizzate secondo le tue preferenze configurate (prezzo max, tempo rimanente, ecc.). +

+
+
+
Vantaggi
+
    +
  • ? Zero costo per le puntate gratuite
  • +
  • ? Maggiori opportunit di vincita
  • +
  • ? Nessun rischio economico
  • +
  • ? Gestione completamente automatica
  • +
+ +
Note Importanti
+
    +
  • ?? Le puntate gratuite hanno scadenza limitata
  • +
  • ?? Disponibilit limitata per prodotto/utente
  • +
  • ?? Vincere comunque richiede pagamento prodotto
  • +
+
+
+ +
+
+ +
+ Suggerimento: Combina le puntate gratuite con la strategia di bidding normale + per massimizzare le tue possibilit di vincita minimizzando i costi. +
+
+
+
+
+
+ + +@if (showInfoModal) +{ + +} + + + +@code { + // Stats + private int totalFreeBids = 0; + private int usedFreeBids = 0; + private int pendingFreeBids = 0; + private int totalWins = 0; + + // Configuration + private bool autoCollectEnabled = false; + private bool autoUseEnabled = false; + private decimal maxPriceAutoUse = 5.0m; + private int minTimeRemaining = 10; + + // Data + private List freeBidsAuctions = new(); + private bool showInfoModal = false; + + protected override void OnInitialized() + { + LoadMockData(); + } + + private void LoadMockData() + { + // Mock data for demonstration + totalFreeBids = 0; + usedFreeBids = 0; + pendingFreeBids = 0; + totalWins = 0; + + // Empty list - funzionalit non ancora implementata + freeBidsAuctions = new List(); + } + + private async Task RefreshData() + { + LoadMockData(); + await JSRuntime.InvokeVoidAsync("alert", "?? Funzionalit in sviluppo. I dati verranno aggiornati nella prossima versione."); + } + + private void ShowInfoModal() + { + showInfoModal = true; + } + + private void CloseInfoModal() + { + showInfoModal = false; + } + + private async Task UseFreeBids(FreeBidAuction auction) + { + await JSRuntime.InvokeVoidAsync("alert", $"?? Funzionalit in sviluppo.\n\nSar possibile utilizzare le puntate gratuite su: {auction.ProductName}"); + } + + private async Task ViewDetails(FreeBidAuction auction) + { + await JSRuntime.InvokeVoidAsync("alert", $"?? Dettagli Asta\n\nProdotto: {auction.ProductName}\nPuntate Gratuite: {auction.FreeBidsAvailable}\nPrezzo: {auction.CurrentPrice:F2}\nScadenza: {auction.ExpiryTime:dd/MM/yyyy HH:mm}"); + } + + private async Task SaveConfiguration() + { + await JSRuntime.InvokeVoidAsync("alert", "?? Configurazione sar disponibile nella prossima versione."); + } + + private string GetStatusBadgeClass(string status) + { + return status switch + { + "Disponibile" => "bg-success", + "In Uso" => "bg-warning text-dark", + "Scaduta" => "bg-danger", + "Completata" => "bg-info", + _ => "bg-secondary" + }; + } + + // Model + private class FreeBidAuction + { + public string ProductName { get; set; } = ""; + public int FreeBidsAvailable { get; set; } + public DateTime ExpiryTime { get; set; } + public decimal CurrentPrice { get; set; } + public string Status { get; set; } = "Disponibile"; + } +} diff --git a/Mimante/Pages/Index.razor b/Mimante/Pages/Index.razor new file mode 100644 index 0000000..f38476e --- /dev/null +++ b/Mimante/Pages/Index.razor @@ -0,0 +1,286 @@ +@page "/" +@inject AuctionMonitor AuctionMonitor +@inject AuctionStateService AuctionStateService +@inject IJSRuntime JSRuntime +@implements IDisposable + +Monitor Aste - AutoBidder + +
+
+ + + + + + +
+ +
+
+

Aste Monitorate (@auctions.Count)

+ @if (auctions.Count == 0) + { +
+ Nessuna asta monitorata. Clicca su "Aggiungi Asta" per iniziare. +
+ } + else + { +
+ + + + + + + + + + + + + + + @foreach (var auction in auctions) + { + + + + + + + + + + + } + +
Stato Nome Prezzo Timer Ultimo Reset Click Azioni
+ + @GetStatusIcon(auction) @GetStatusText(auction) + + @auction.Name@GetPriceDisplay(auction)@GetTimerDisplay(auction)@GetLastBidder(auction)@auction.ResetCount@GetMyBidsCount(auction) +
+ @if (auction.IsActive && !auction.IsPaused) + { + + } + else if (auction.IsPaused) + { + + } + else + { + + } + +
+
+
+ } +
+ + @if (selectedAuction != null) + { +
+
+

@selectedAuction.Name

+ + @GetStatusIcon(selectedAuction) @GetStatusText(selectedAuction) + +
+

ID: @selectedAuction.AuctionId

+ +
+
+ +
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+ +
+

Log Asta

+
+ @if (GetAuctionLog(selectedAuction).Any()) + { + @foreach (var logEntry in GetAuctionLog(selectedAuction)) + { +
@logEntry
+ } + } + else + { +
Nessun log disponibile
+ } +
+
+ +
+

Partecipanti (@selectedAuction.BidderStats.Count)

+ @if (selectedAuction.BidderStats.Count == 0) + { +

Nessun partecipante ancora

+ } + else + { +
+ + + + + + + + + + @foreach (var bidder in selectedAuction.BidderStats.Values.OrderByDescending(b => b.BidCount)) + { + + + + + + } + +
Utente Puntate Ultima
@bidder.Username@bidder.BidCount@bidder.LastBidTimeDisplay
+
+ } +
+
+ } + else + { +
+
+ +

Seleziona un'asta

+

Clicca su un'asta dalla lista per visualizzare i dettagli

+
+
+ } +
+ +
+
+

Log Globale

+ +
+
+ @if (globalLog.Count == 0) + { +
Nessun log ancora...
+ } + else + { + @foreach (var logEntry in globalLog.TakeLast(100)) + { +
@logEntry
+ } + } +
+
+
+ + +@if (showAddDialog) +{ + +} diff --git a/Mimante/Pages/Index.razor.cs b/Mimante/Pages/Index.razor.cs new file mode 100644 index 0000000..052d3dd --- /dev/null +++ b/Mimante/Pages/Index.razor.cs @@ -0,0 +1,366 @@ +using AutoBidder.Models; +using AutoBidder.Services; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace AutoBidder.Pages +{ + public partial class Index : IDisposable + { + private List auctions = new(); + private AuctionInfo? selectedAuction; + private List globalLog = new(); + private bool isMonitoringActive = false; + private System.Threading.Timer? refreshTimer; + + // Dialog Aggiungi Asta + private bool showAddDialog = false; + private string addDialogUrl = ""; + private string addDialogName = ""; + private string? addDialogError = null; + + protected override void OnInitialized() + { + LoadAuctionsFromDisk(); + + AuctionMonitor.OnLog += OnGlobalLog; + AuctionMonitor.OnAuctionUpdated += OnAuctionUpdated; + + refreshTimer = new System.Threading.Timer(async _ => + { + await InvokeAsync(StateHasChanged); + }, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); + + AddLog("Applicazione avviata"); + } + + private void LoadAuctionsFromDisk() + { + var loadedAuctions = AutoBidder.Utilities.PersistenceManager.LoadAuctions(); + + foreach (var auction in loadedAuctions) + { + auctions.Add(auction); + AuctionMonitor.AddAuction(auction); + } + + if (loadedAuctions.Count > 0) + { + AddLog($"Caricate {loadedAuctions.Count} aste salvate"); + } + } + + private void SaveAuctions() + { + AutoBidder.Utilities.PersistenceManager.SaveAuctions(auctions); + AddLog("Aste salvate"); + } + + private void AddLog(string message) + { + globalLog.Add($"[{DateTime.Now:HH:mm:ss}] {message}"); + StateHasChanged(); + } + + private void OnGlobalLog(string message) + { + globalLog.Add($"[{DateTime.Now:HH:mm:ss}] {message}"); + InvokeAsync(StateHasChanged); + } + + private void OnAuctionUpdated(AuctionState state) + { + var auction = auctions.FirstOrDefault(a => a.AuctionId == state.AuctionId); + if (auction != null) + { + InvokeAsync(StateHasChanged); + } + } + + private void SelectAuction(AuctionInfo auction) + { + selectedAuction = auction; + } + + // Gestione controlli globali + private void StartAll() + { + foreach (var auction in auctions) + { + auction.IsActive = true; + auction.IsPaused = false; + } + AuctionMonitor.Start(); + isMonitoringActive = true; + SaveAuctions(); + AddLog("? Avviate tutte le aste"); + } + + private void PauseAll() + { + foreach (var auction in auctions) + { + auction.IsPaused = true; + } + SaveAuctions(); + AddLog("?? Messe in pausa tutte le aste"); + } + + private void StopAll() + { + foreach (var auction in auctions) + { + auction.IsActive = false; + auction.IsPaused = false; + } + AuctionMonitor.Stop(); + isMonitoringActive = false; + SaveAuctions(); + AddLog("?? Fermate tutte le aste"); + } + + // Gestione singola asta + private void StartAuction(AuctionInfo auction) + { + auction.IsActive = true; + auction.IsPaused = false; + + if (!isMonitoringActive) + { + AuctionMonitor.Start(); + isMonitoringActive = true; + } + + SaveAuctions(); + AddLog($"?? Avviata asta: {auction.Name}"); + } + + private void PauseAuction(AuctionInfo auction) + { + auction.IsPaused = true; + SaveAuctions(); + AddLog($"?? In pausa asta: {auction.Name}"); + } + + private void ResumeAuction(AuctionInfo auction) + { + auction.IsPaused = false; + SaveAuctions(); + AddLog($"?? Ripresa asta: {auction.Name}"); + } + + private void StopAuction(AuctionInfo auction) + { + auction.IsActive = false; + auction.IsPaused = false; + SaveAuctions(); + AddLog($"?? Fermata asta: {auction.Name}"); + } + + // Dialog Aggiungi Asta + private void ShowAddAuctionDialog() + { + showAddDialog = true; + addDialogUrl = ""; + addDialogName = ""; + addDialogError = null; + } + + private void CloseAddDialog() + { + showAddDialog = false; + } + + private void AddAuction() + { + addDialogError = null; + + // Valida URL + if (!addDialogUrl.Contains("bidoo.com")) + { + addDialogError = "URL non valido. Deve essere un link di Bidoo.com"; + return; + } + + // Estrai ID asta dall'URL + var auctionId = ExtractAuctionId(addDialogUrl); + if (string.IsNullOrEmpty(auctionId)) + { + addDialogError = "Impossibile estrarre l'ID dell'asta dall'URL"; + return; + } + + // Verifica se gi esiste + if (auctions.Any(a => a.AuctionId == auctionId)) + { + addDialogError = "Questa asta gi monitorata"; + return; + } + + // Carica impostazioni default + var settings = AutoBidder.Utilities.SettingsManager.Load(); + + // Crea nuova asta + var newAuction = new AuctionInfo + { + AuctionId = auctionId, + Name = string.IsNullOrWhiteSpace(addDialogName) ? $"Asta {auctionId}" : addDialogName, + OriginalUrl = addDialogUrl, + BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs, + CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid, + MinPrice = settings.DefaultMinPrice, + MaxPrice = settings.DefaultMaxPrice, + MaxClicks = settings.DefaultMaxClicks, + IsActive = false, + IsPaused = false + }; + + auctions.Add(newAuction); + AuctionMonitor.AddAuction(newAuction); + SaveAuctions(); + + AddLog($"? Aggiunta asta: {newAuction.Name} (ID: {auctionId})"); + + CloseAddDialog(); + selectedAuction = newAuction; + } + + private string ExtractAuctionId(string url) + { + try + { + // Pattern: https://it.bidoo.com/asta/nome-prodotto-123456 + var match = System.Text.RegularExpressions.Regex.Match(url, @"(\d{5,})"); + return match.Success ? match.Groups[1].Value : ""; + } + catch + { + return ""; + } + } + + private void RemoveSelectedAuction() + { + if (selectedAuction != null) + { + var name = selectedAuction.Name; + AuctionMonitor.RemoveAuction(selectedAuction.AuctionId); + auctions.Remove(selectedAuction); + SaveAuctions(); + AddLog($"??? Rimossa asta: {name}"); + selectedAuction = null; + } + } + + private void ClearGlobalLog() + { + globalLog.Clear(); + AddLog("?? Log pulito"); + } + + private async Task CopyToClipboard(string text) + { + try + { + await JSRuntime.InvokeVoidAsync("navigator.clipboard.writeText", text); + AddLog("?? URL copiato negli appunti"); + } + catch + { + AddLog("? Impossibile copiare negli appunti"); + } + } + + // Helper methods per stili e classi + private string GetRowClass(AuctionInfo auction) + { + return auction == selectedAuction ? "table-active" : ""; + } + + private string GetStatusBadgeClass(AuctionInfo auction) + { + if (!auction.IsActive) return "bg-secondary"; + if (auction.IsPaused) return "bg-warning text-dark"; + return "bg-success"; + } + + private string GetStatusText(AuctionInfo auction) + { + if (!auction.IsActive) return "Fermo"; + if (auction.IsPaused) return "Pausa"; + return "Attivo"; + } + + private string GetStatusIcon(AuctionInfo auction) + { + if (!auction.IsActive) return "??"; + if (auction.IsPaused) return "??"; + return "??"; + } + + private string GetStatusAnimationClass(AuctionInfo auction) + { + if (!auction.IsActive) return ""; + if (auction.IsPaused) return "status-paused"; + return "status-active"; + } + + private string GetPriceDisplay(AuctionInfo auction) + { + if (auction.CalculatedValue?.CurrentPrice > 0) + return $"{auction.CalculatedValue.CurrentPrice:F2}"; + return "-"; + } + + private string GetPriceClass(AuctionInfo auction) + { + if (auction.CalculatedValue?.CurrentPrice > 0) + return "fw-bold text-success"; + return "text-muted"; + } + + private string GetTimerDisplay(AuctionInfo auction) + { + // TODO: Get from latest state + return "-"; + } + + private string GetLastBidder(AuctionInfo auction) + { + return auction.RecentBids.FirstOrDefault()?.Username ?? "-"; + } + + private int GetMyBidsCount(AuctionInfo auction) + { + return auction.BidHistory.Count(b => b.EventType == BidEventType.MyBid); + } + + private IEnumerable GetAuctionLog(AuctionInfo auction) + { + return auction.AuctionLog.TakeLast(50); + } + + private string GetLogEntryClass(string logEntry) + { + if (logEntry.Contains("?") || logEntry.Contains("Errore") || logEntry.Contains("errore")) + return "log-entry-error"; + if (logEntry.Contains("??") || logEntry.Contains("Warning") || logEntry.Contains("warning")) + return "log-entry-warning"; + return "log-entry-new"; + } + + public void Dispose() + { + refreshTimer?.Dispose(); + if (AuctionMonitor != null) + { + AuctionMonitor.OnLog -= OnGlobalLog; + AuctionMonitor.OnAuctionUpdated -= OnAuctionUpdated; + } + } + } +} diff --git a/Mimante/Pages/Settings.razor b/Mimante/Pages/Settings.razor new file mode 100644 index 0000000..59f4042 --- /dev/null +++ b/Mimante/Pages/Settings.razor @@ -0,0 +1,368 @@ +@page "/settings" +@inject SessionService SessionService +@inject AuctionMonitor AuctionMonitor +@inject IJSRuntime JSRuntime + +Impostazioni - AutoBidder + +
+
+ +

Impostazioni

+
+ +
+
+
Sessione Bidoo
+
+
+ @if (!string.IsNullOrEmpty(currentUsername)) + { +
+
+ +
+ Connesso come: @currentUsername +
+ Puntate residue: + @remainingBids +
+
+
+ + } + else + { +
+ Non sei connesso a Bidoo. +
+ + @if (!string.IsNullOrEmpty(connectionError)) + { +
+ @connectionError +
+ } + +
+ + + + Apri gli strumenti sviluppatore del browser (F12), vai alla tab "Network", + visita bidoo.com, copia il valore del cookie "__stattrb" o simile. + +
+ +
+ + + + Verr rilevato automaticamente se non specificato + +
+ + + } +
+
+ +
+
+
Impostazioni Predefinite Aste
+
+
+
+
+ + + + Millisecondi prima della scadenza per inviare la puntata + +
+ +
+ + +
+ +
+ + +
+ +
+ + + + 0 = illimitati + +
+ +
+ + + + Blocca puntate automatiche sotto questo limite + +
+ +
+
+ + +
+
+
+ + +
+
+ +
+
+
Limiti Log
+
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+
+ + + +@code { + private string? currentUsername; + private int remainingBids; + private string cookieInput = ""; + private string usernameInput = ""; + private string? connectionError = null; + private bool isConnecting = false; + private AutoBidder.Utilities.AppSettings settings = new(); + private System.Threading.Timer? updateTimer; + + protected override void OnInitialized() + { + LoadSession(); + LoadSettings(); + + // Auto-refresh dati utente ogni 30 secondi + updateTimer = new System.Threading.Timer(async _ => + { + if (!string.IsNullOrEmpty(currentUsername)) + { + await RefreshUserData(); + await InvokeAsync(StateHasChanged); + } + }, null, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); + } + + private void LoadSession() + { + // Carica sessione salvata + var savedSession = AutoBidder.Services.SessionManager.LoadSession(); + if (savedSession != null && savedSession.IsValid) + { + currentUsername = savedSession.Username; + remainingBids = savedSession.RemainingBids; + cookieInput = savedSession.CookieString ?? ""; + + // Inizializza il monitor con la sessione + if (!string.IsNullOrEmpty(savedSession.CookieString)) + { + AuctionMonitor.InitializeSessionWithCookie(savedSession.CookieString, savedSession.Username ?? ""); + } + } + else + { + // Prova a caricare da AuctionMonitor + var session = AuctionMonitor.GetSession(); + currentUsername = session?.Username; + remainingBids = session?.RemainingBids ?? 0; + } + } + + private void LoadSettings() + { + settings = AutoBidder.Utilities.SettingsManager.Load(); + } + + private async Task Connect() + { + if (string.IsNullOrWhiteSpace(cookieInput)) + return; + + isConnecting = true; + connectionError = null; + + try + { + AuctionMonitor.InitializeSessionWithCookie(cookieInput.Trim(), usernameInput.Trim()); + + var success = await AuctionMonitor.UpdateUserInfoAsync(); + if (success) + { + var session = AuctionMonitor.GetSession(); + if (session != null && !string.IsNullOrEmpty(session.Username)) + { + // Salva la sessione + AutoBidder.Services.SessionManager.SaveSession(session); + + LoadSession(); + cookieInput = ""; + usernameInput = ""; + connectionError = null; + + await JSRuntime.InvokeVoidAsync("alert", $"? Connesso con successo come {session.Username}!"); + } + else + { + connectionError = "Sessione creata ma dati utente non disponibili. Verifica il cookie."; + } + } + else + { + connectionError = "Impossibile connettersi. Verifica che il cookie sia corretto e non scaduto."; + } + } + catch (Exception ex) + { + connectionError = $"Errore durante la connessione: {ex.Message}"; + } + finally + { + isConnecting = false; + } + } + + private void Disconnect() + { + SessionService.ClearSession(); + AutoBidder.Services.SessionManager.ClearSession(); + currentUsername = null; + remainingBids = 0; + cookieInput = ""; + } + + private async Task RefreshUserData() + { + try + { + var success = await AuctionMonitor.UpdateUserInfoAsync(); + if (success) + { + var session = AuctionMonitor.GetSession(); + if (session != null) + { + currentUsername = session.Username; + remainingBids = session.RemainingBids; + + // Aggiorna sessione salvata + AutoBidder.Services.SessionManager.SaveSession(session); + } + } + } + catch + { + // Ignora errori di refresh silenziosamente + } + } + + private void SaveSettings() + { + AutoBidder.Utilities.SettingsManager.Save(settings); + _ = JSRuntime.InvokeVoidAsync("alert", "? Impostazioni salvate con successo!"); + } + + private string GetRemainingBidsClass() + { + if (remainingBids < 50) return "bg-danger"; + if (remainingBids < 150) return "bg-warning text-dark"; + return "bg-success"; + } + + public void Dispose() + { + updateTimer?.Dispose(); + } +} + +@implements IDisposable diff --git a/Mimante/Pages/Statistics.razor b/Mimante/Pages/Statistics.razor new file mode 100644 index 0000000..bef6c9e --- /dev/null +++ b/Mimante/Pages/Statistics.razor @@ -0,0 +1,200 @@ +@page "/statistics" +@inject StatsService StatsService +@inject IJSRuntime JSRuntime + +Statistiche - AutoBidder + +
+
+
+ +

Statistiche Prodotti

+
+ +
+ + @if (errorMessage != null) + { +
+
+ +
+
Errore nel caricamento statistiche
+

@errorMessage

+
+
+
+ } + + @if (stats != null && stats.Any()) + { +
+
+
+ + + + + + + + + + + + @foreach (var stat in stats.OrderByDescending(s => s.LastSeen)) + { + + + + + + + + } + +
ProdottoAste VistePuntate MediePrezzo MedioUltima Vista
@stat.ProductName + @stat.TotalAuctions + + @stat.AverageBidsUsed.ToString("F1") + + @stat.AverageFinalPrice.ToString("F2") + + @stat.LastSeen.ToString("dd/MM/yyyy HH:mm") +
+
+
+
+ +
+
+
+
+
+ +

@stats.Count

+

Prodotti Tracciati

+
+
+
+
+
+
+ +

@stats.Sum(s => s.TotalAuctions)

+

Aste Totali

+
+
+
+
+
+
+ +

@stats.Average(s => s.AverageFinalPrice).ToString("F2")

+

Prezzo Medio

+
+
+
+
+
+ } + else if (!isLoading && errorMessage == null) + { +
+
+ +
+
Nessuna statistica disponibile
+

Le statistiche verranno raccolte automaticamente durante il monitoraggio delle aste.

+
+
+
+ } + + @if (isLoading) + { +
+
+ Caricamento... +
+

Caricamento statistiche...

+
+ } +
+ + + +@code { + private List? stats; + private string? errorMessage; + private bool isLoading = false; + + protected override async Task OnInitializedAsync() + { + await RefreshStats(); + } + + private async Task RefreshStats() + { + try + { + isLoading = true; + errorMessage = null; + StateHasChanged(); + + stats = await StatsService.GetAllStatsAsync(); + } + catch (Exception ex) + { + errorMessage = $"Si verificato un errore: {ex.Message}"; + stats = new List(); + Console.WriteLine($"[ERROR] Statistics page: {ex}"); + } + finally + { + isLoading = false; + StateHasChanged(); + } + } +} diff --git a/Mimante/Pages/_Host.cshtml b/Mimante/Pages/_Host.cshtml new file mode 100644 index 0000000..eb2eace --- /dev/null +++ b/Mimante/Pages/_Host.cshtml @@ -0,0 +1,37 @@ +@page "/" +@using Microsoft.AspNetCore.Components.Web +@namespace AutoBidder.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers + + + + + + + + + + + + + + + + + +
+ + Si verificato un errore. + + + Si verificato un errore non gestito. Consultare la console del browser per ulteriori informazioni. + + Ricarica + ?? +
+ + + + + + diff --git a/Mimante/Pages/_Layout.cshtml b/Mimante/Pages/_Layout.cshtml new file mode 100644 index 0000000..ce0caf9 --- /dev/null +++ b/Mimante/Pages/_Layout.cshtml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + @RenderBody() + +
+ + Si verificato un errore. + + + Si verificato un errore non gestito. Consultare la console del browser per ulteriori informazioni. + + Ricarica + ?? +
+ + + + + diff --git a/Mimante/Program.cs b/Mimante/Program.cs new file mode 100644 index 0000000..3014646 --- /dev/null +++ b/Mimante/Program.cs @@ -0,0 +1,125 @@ +using AutoBidder.Services; +using AutoBidder.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.DataProtection; + +var builder = WebApplication.CreateBuilder(args); + +// Configura Kestrel per accesso remoto con supporto HTTPS +builder.WebHost.ConfigureKestrel(options => +{ + options.ListenAnyIP(5000); // HTTP + options.ListenAnyIP(5001, listenOptions => + { + listenOptions.UseHttps(); // HTTPS + }); +}); + +// Add services to the container +builder.Services.AddRazorPages(); +builder.Services.AddServerSideBlazor(); + +// Configura Data Protection per evitare CryptographicException +var dataProtectionPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "AutoBidder", + "DataProtection-Keys" +); + +if (!Directory.Exists(dataProtectionPath)) +{ + Directory.CreateDirectory(dataProtectionPath); +} + +builder.Services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(dataProtectionPath)) + .SetApplicationName("AutoBidder"); + +// Configura HTTPS Redirection per produzione +if (!builder.Environment.IsDevelopment()) +{ + builder.Services.AddHsts(options => + { + options.MaxAge = TimeSpan.FromDays(365); + options.IncludeSubDomains = true; + options.Preload = true; + }); +} + +// Configura Database SQLite per statistiche +builder.Services.AddDbContext(options => +{ + var dbPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "AutoBidder", + "statistics.db" + ); + + // Crea directory se non esiste + var directory = Path.GetDirectoryName(dbPath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + options.UseSqlite($"Data Source={dbPath}"); +}); + +// Registra servizi applicazione come Singleton per condividere stato +var htmlCacheService = new HtmlCacheService( + maxConcurrentRequests: 3, + requestsPerSecond: 5, + cacheExpiration: TimeSpan.FromMinutes(5), + maxRetries: 2 +); + +var auctionMonitor = new AuctionMonitor(); +htmlCacheService.OnLog += (msg) => Console.WriteLine(msg); + +builder.Services.AddSingleton(auctionMonitor); +builder.Services.AddSingleton(htmlCacheService); +builder.Services.AddSingleton(sp => new SessionService(auctionMonitor.GetApiClient())); +builder.Services.AddScoped(sp => +{ + var ctx = sp.GetRequiredService(); + return new StatsService(ctx); +}); +builder.Services.AddScoped(); + +// Configura SignalR per real-time updates +builder.Services.AddSignalR(options => +{ + options.MaximumReceiveMessageSize = 102400; // 100KB + options.EnableDetailedErrors = true; +}); + +var app = builder.Build(); + +// Crea database se non esiste (senza migrations) +using (var scope = app.Services.CreateScope()) +{ + var db = scope.ServiceProvider.GetRequiredService(); + db.Database.EnsureCreated(); // Crea schema automaticamente se non esiste +} + +// Configure the HTTP request pipeline +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); + app.UseHsts(); +} +else +{ + app.UseDeveloperExceptionPage(); +} + +app.UseHttpsRedirection(); +app.UseStaticFiles(); +app.UseRouting(); + +app.MapBlazorHub(); +app.MapFallbackToPage("/_Host"); + +app.Run(); diff --git a/Mimante/Properties/launchSettings.json b/Mimante/Properties/launchSettings.json new file mode 100644 index 0000000..e1f3f93 --- /dev/null +++ b/Mimante/Properties/launchSettings.json @@ -0,0 +1,37 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:55473", + "sslPort": 55472 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/Mimante/Services/AuctionStateService.cs b/Mimante/Services/AuctionStateService.cs new file mode 100644 index 0000000..8797389 --- /dev/null +++ b/Mimante/Services/AuctionStateService.cs @@ -0,0 +1,56 @@ +using AutoBidder.Models; +using System.Collections.Concurrent; + +namespace AutoBidder.Services +{ + /// + /// Servizio per gestione stato aste in ambiente Blazor + /// + public class AuctionStateService + { + private readonly ConcurrentDictionary _auctions = new(); + + public event Action? OnStateChanged; + public event Action? OnAuctionUpdated; + public event Action? OnAuctionAdded; + public event Action? OnAuctionRemoved; + + public IEnumerable GetAllAuctions() => _auctions.Values; + + public AuctionInfo? GetAuction(string auctionId) + { + _auctions.TryGetValue(auctionId, out var auction); + return auction; + } + + public void AddAuction(AuctionInfo auction) + { + if (_auctions.TryAdd(auction.AuctionId, auction)) + { + OnAuctionAdded?.Invoke(auction.AuctionId); + NotifyStateChanged(); + } + } + + public void RemoveAuction(string auctionId) + { + if (_auctions.TryRemove(auctionId, out _)) + { + OnAuctionRemoved?.Invoke(auctionId); + NotifyStateChanged(); + } + } + + public void UpdateAuction(string auctionId, Action updateAction) + { + if (_auctions.TryGetValue(auctionId, out var auction)) + { + updateAction(auction); + OnAuctionUpdated?.Invoke(auctionId); + NotifyStateChanged(); + } + } + + private void NotifyStateChanged() => OnStateChanged?.Invoke(); + } +} diff --git a/Mimante/Services/SessionManager.cs b/Mimante/Services/SessionManager.cs index 0ee41a8..5cb51a3 100644 --- a/Mimante/Services/SessionManager.cs +++ b/Mimante/Services/SessionManager.cs @@ -11,6 +11,7 @@ namespace AutoBidder.Services /// Gestore persistenza sessione Bidoo /// Salva in modo sicuro il cookie di autenticazione per riutilizzo /// Il cookie deve essere inserito manualmente dall'utente (copiato dal browser) + /// NOTA: Usa AES256 per compatibilit cross-platform (Linux/Docker) /// public class SessionManager { @@ -20,10 +21,13 @@ namespace AutoBidder.Services "session.dat" ); - private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("AutoBidder_V1_2025"); + // Chiave e IV per AES256 - In produzione dovrebbero essere gestiti in modo pi sicuro + // Per ora usiamo valori hardcoded per semplicit (il file comunque protetto da permessi filesystem) + private static readonly byte[] Key = SHA256.HashData(Encoding.UTF8.GetBytes("AutoBidder_Session_Key_V1_2025")); + private static readonly byte[] IV = MD5.HashData(Encoding.UTF8.GetBytes("AutoBidder_IV_V1")); /// - /// Salva la sessione in modo sicuro (crittografata con DPAPI) + /// Salva la sessione in modo sicuro (crittografata con AES256) /// public static bool SaveSession(BidooSession session) { @@ -42,9 +46,9 @@ namespace AutoBidder.Services WriteIndented = true }); - // Cripta usando DPAPI (Windows Data Protection API) + // Cripta usando AES256 var plainBytes = Encoding.UTF8.GetBytes(json); - var encryptedBytes = ProtectedData.Protect(plainBytes, Entropy, DataProtectionScope.CurrentUser); + var encryptedBytes = EncryptAES(plainBytes); // Salva su file File.WriteAllBytes(SessionFilePath, encryptedBytes); @@ -60,7 +64,7 @@ namespace AutoBidder.Services } /// - /// Carica la sessione salvata (decripta con DPAPI) + /// Carica la sessione salvata (decripta con AES256) /// public static BidooSession? LoadSession() { @@ -75,8 +79,8 @@ namespace AutoBidder.Services // Leggi file crittografato var encryptedBytes = File.ReadAllBytes(SessionFilePath); - // Decripta usando DPAPI - var plainBytes = ProtectedData.Unprotect(encryptedBytes, Entropy, DataProtectionScope.CurrentUser); + // Decripta usando AES256 + var plainBytes = DecryptAES(encryptedBytes); var json = Encoding.UTF8.GetString(plainBytes); // Deserializza JSON @@ -140,5 +144,35 @@ namespace AutoBidder.Services } return (false, null); } + + /// + /// Cripta dati usando AES256-CBC + /// + private static byte[] EncryptAES(byte[] plainBytes) + { + using var aes = Aes.Create(); + aes.Key = Key; + aes.IV = IV; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using var encryptor = aes.CreateEncryptor(); + return encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); + } + + /// + /// Decripta dati usando AES256-CBC + /// + private static byte[] DecryptAES(byte[] encryptedBytes) + { + using var aes = Aes.Create(); + aes.Key = Key; + aes.IV = IV; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using var decryptor = aes.CreateDecryptor(); + return decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); + } } } diff --git a/Mimante/Services/Settings.cs b/Mimante/Services/Settings.cs new file mode 100644 index 0000000..2130bab --- /dev/null +++ b/Mimante/Services/Settings.cs @@ -0,0 +1,11 @@ +using AutoBidder.Utilities; + +namespace AutoBidder.Services +{ + /// + /// Alias pubblico per AppSettings per uso in Blazor + /// + public class Settings : AppSettings + { + } +} diff --git a/Mimante/Services/StatsService.cs b/Mimante/Services/StatsService.cs index cebd982..58cdd3d 100644 --- a/Mimante/Services/StatsService.cs +++ b/Mimante/Services/StatsService.cs @@ -15,8 +15,8 @@ namespace AutoBidder.Services public StatsService(StatisticsContext ctx) { _ctx = ctx; - // Ensure DB created - _ctx.Database.Migrate(); + // Assicurati che il database esista (senza migrations) + _ctx.Database.EnsureCreated(); } private static string NormalizeKey(string? productName, string? auctionUrl) diff --git a/Mimante/Shared/MainLayout.razor b/Mimante/Shared/MainLayout.razor new file mode 100644 index 0000000..ff6e57c --- /dev/null +++ b/Mimante/Shared/MainLayout.razor @@ -0,0 +1,28 @@ +@inherits LayoutComponentBase + +
+ + +
+
+ +
+ +
+ @Body +
+
+
+ +
+ + Si verificato un errore. + + + Si verificato un errore non gestito. Consultare la console del browser per ulteriori informazioni. + + Ricarica + ?? +
diff --git a/Mimante/Shared/NavMenu.razor b/Mimante/Shared/NavMenu.razor new file mode 100644 index 0000000..4015bb8 --- /dev/null +++ b/Mimante/Shared/NavMenu.razor @@ -0,0 +1,121 @@ +@inject NavigationManager NavigationManager + + + + diff --git a/Mimante/Shared/UserBanner.razor b/Mimante/Shared/UserBanner.razor new file mode 100644 index 0000000..6288f6f --- /dev/null +++ b/Mimante/Shared/UserBanner.razor @@ -0,0 +1,145 @@ +@inject AuctionMonitor AuctionMonitor +@implements IDisposable + +
+ @if (!string.IsNullOrEmpty(username)) + { + + } + else + { + + } +
+ + + +@code { + private string? username; + private int remainingBids; + private System.Threading.Timer? updateTimer; + + protected override void OnInitialized() + { + _ = UpdateUserInfo(); // Fire-and-forget intenzionale qui + updateTimer = new System.Threading.Timer(async _ => + { + await UpdateUserInfo(); + await InvokeAsync(StateHasChanged); + }, null, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); + } + + private async Task UpdateUserInfo() + { + var session = AuctionMonitor.GetSession(); + username = session?.Username; + remainingBids = session?.RemainingBids ?? 0; + } + + private string GetBidsColorClass() + { + if (remainingBids < 50) return "badge-low-bids"; + if (remainingBids < 150) return "badge-medium-bids"; + return "badge-high-bids"; + } + + public void Dispose() + { + updateTimer?.Dispose(); + } +} diff --git a/Mimante/Utilities/SettingsManager.cs b/Mimante/Utilities/SettingsManager.cs index d41551f..102abde 100644 --- a/Mimante/Utilities/SettingsManager.cs +++ b/Mimante/Utilities/SettingsManager.cs @@ -4,7 +4,7 @@ using System.Text.Json; namespace AutoBidder.Utilities { - internal class AppSettings + public class AppSettings { // NUOVE IMPOSTAZIONI PREDEFINITE PER LE ASTE public int DefaultBidBeforeDeadlineMs { get; set; } = 200; @@ -70,7 +70,7 @@ namespace AutoBidder.Utilities public string MinLogLevel { get; set; } = "Normal"; } - internal static class SettingsManager + public 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"); diff --git a/Mimante/_Imports.razor b/Mimante/_Imports.razor new file mode 100644 index 0000000..57c9e21 --- /dev/null +++ b/Mimante/_Imports.razor @@ -0,0 +1,12 @@ +@using System.Net.Http +@using Microsoft.AspNetCore.Authorization +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using AutoBidder +@using AutoBidder.Shared +@using AutoBidder.Models +@using AutoBidder.Services diff --git a/Mimante/appsettings.json b/Mimante/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Mimante/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Mimante/docker-compose.yml b/Mimante/docker-compose.yml new file mode 100644 index 0000000..2a4a4a6 --- /dev/null +++ b/Mimante/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.8' + +services: + autobidder: + build: + context: . + dockerfile: Dockerfile + container_name: autobidder + ports: + - "5000:5000" + volumes: + - ./data:/app/data + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://+:5000 + restart: unless-stopped diff --git a/Mimante/wwwroot/css/animations.css b/Mimante/wwwroot/css/animations.css new file mode 100644 index 0000000..41f077e --- /dev/null +++ b/Mimante/wwwroot/css/animations.css @@ -0,0 +1,554 @@ +/* ===== ANIMATIONS.CSS ===== */ +/* Advanced animations and transitions for AutoBidder Blazor */ + +/* === KEYFRAME ANIMATIONS === */ + +/* Fade In Animations */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInLeft { + from { + opacity: 0; + transform: translateX(-30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes fadeInRight { + from { + opacity: 0; + transform: translateX(30px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +/* Slide Animations */ +@keyframes slideDown { + from { + max-height: 0; + opacity: 0; + } + to { + max-height: 500px; + opacity: 1; + } +} + +@keyframes slideUp { + from { + max-height: 500px; + opacity: 1; + } + to { + max-height: 0; + opacity: 0; + } +} + +/* Scale Animations */ +@keyframes scaleIn { + from { + opacity: 0; + transform: scale(0.9); + } + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes scaleOut { + from { + opacity: 1; + transform: scale(1); + } + to { + opacity: 0; + transform: scale(0.9); + } +} + +/* Pulse Animation */ +@keyframes pulse { + 0%, 100% { + transform: scale(1); + } + 50% { + transform: scale(1.05); + } +} + +/* Shake Animation */ +@keyframes shake { + 0%, 100% { + transform: translateX(0); + } + 10%, 30%, 50%, 70%, 90% { + transform: translateX(-5px); + } + 20%, 40%, 60%, 80% { + transform: translateX(5px); + } +} + +/* Bounce Animation */ +@keyframes bounce { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-10px); + } +} + +/* Spin Animation */ +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +/* Glow Animation */ +@keyframes glow { + 0%, 100% { + box-shadow: 0 0 5px rgba(13, 110, 253, 0.5); + } + 50% { + box-shadow: 0 0 20px rgba(13, 110, 253, 0.8); + } +} + +/* Progress Bar Animation */ +@keyframes progressBar { + from { + width: 0; + } + to { + width: 100%; + } +} + +/* Shimmer Effect */ +@keyframes shimmer { + 0% { + background-position: -1000px 0; + } + 100% { + background-position: 1000px 0; + } +} + +/* Typing Effect */ +@keyframes typing { + from { + width: 0; + } + to { + width: 100%; + } +} + +/* Blink Effect */ +@keyframes blink { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0; + } +} + +/* === UTILITY ANIMATION CLASSES === */ + +/* Fade Animations */ +.animate-fade-in { + animation: fadeIn 0.5s ease-in-out; +} + +.animate-fade-in-up { + animation: fadeInUp 0.5s ease-in-out; +} + +.animate-fade-in-down { + animation: fadeInDown 0.5s ease-in-out; +} + +.animate-fade-in-left { + animation: fadeInLeft 0.5s ease-in-out; +} + +.animate-fade-in-right { + animation: fadeInRight 0.5s ease-in-out; +} + +/* Scale Animations */ +.animate-scale-in { + animation: scaleIn 0.3s ease-in-out; +} + +.animate-scale-out { + animation: scaleOut 0.3s ease-in-out; +} + +/* Pulse Animation */ +.animate-pulse { + animation: pulse 2s ease-in-out infinite; +} + +/* Shake Animation */ +.animate-shake { + animation: shake 0.5s ease-in-out; +} + +/* Bounce Animation */ +.animate-bounce { + animation: bounce 1s ease-in-out infinite; +} + +/* Spin Animation */ +.animate-spin { + animation: spin 1s linear infinite; +} + +/* Glow Animation */ +.animate-glow { + animation: glow 2s ease-in-out infinite; +} + +/* Shimmer Effect */ +.animate-shimmer { + background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); + background-size: 2000px 100%; + animation: shimmer 2s linear infinite; +} + +/* Blink Effect */ +.animate-blink { + animation: blink 1s ease-in-out infinite; +} + +/* === TRANSITION UTILITIES === */ + +.transition-all { + transition: all 0.3s ease; +} + +.transition-fast { + transition: all 0.15s ease; +} + +.transition-slow { + transition: all 0.5s ease; +} + +.transition-transform { + transition: transform 0.3s ease; +} + +.transition-opacity { + transition: opacity 0.3s ease; +} + +.transition-colors { + transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; +} + +/* === HOVER EFFECTS === */ + +.hover-lift { + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.hover-lift:hover { + transform: translateY(-4px); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); +} + +.hover-scale { + transition: transform 0.3s ease; +} + +.hover-scale:hover { + transform: scale(1.05); +} + +.hover-rotate { + transition: transform 0.3s ease; +} + +.hover-rotate:hover { + transform: rotate(5deg); +} + +.hover-glow { + transition: box-shadow 0.3s ease; +} + +.hover-glow:hover { + box-shadow: 0 0 15px rgba(13, 110, 253, 0.5); +} + +.hover-underline { + position: relative; +} + +.hover-underline::after { + content: ''; + position: absolute; + width: 0; + height: 2px; + bottom: -2px; + left: 0; + background-color: currentColor; + transition: width 0.3s ease; +} + +.hover-underline:hover::after { + width: 100%; +} + +/* === STATUS ANIMATIONS === */ + +/* Active/Running Status */ +.status-active { + position: relative; + overflow: hidden; +} + +.status-active::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + animation: statusSlide 2s linear infinite; +} + +@keyframes statusSlide { + 0% { + left: -100%; + } + 100% { + left: 100%; + } +} + +/* Paused Status */ +.status-paused { + animation: pulse 2s ease-in-out infinite; +} + +/* Error Status */ +.status-error { + animation: shake 0.5s ease-in-out; +} + +/* Success Status */ +.status-success { + animation: scaleIn 0.3s ease-in-out; +} + +/* Loading Status */ +.status-loading { + position: relative; +} + +.status-loading::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + height: 2px; + width: 100%; + background: linear-gradient(90deg, transparent, var(--primary-color), transparent); + animation: statusSlide 1.5s linear infinite; +} + +/* === TABLE ROW ANIMATIONS === */ + +.table tbody tr { + transition: all 0.2s ease; +} + +.table tbody tr:hover { + transform: scale(1.01); + z-index: 1; +} + +.table-row-enter { + animation: fadeInUp 0.3s ease-in-out; +} + +.table-row-exit { + animation: fadeInDown 0.3s ease-in-out reverse; +} + +/* === BADGE ANIMATIONS === */ + +.badge { + transition: all 0.3s ease; +} + +.badge:hover { + transform: scale(1.1); +} + +.badge-pulse { + animation: pulse 1.5s ease-in-out infinite; +} + +.badge-glow { + animation: glow 2s ease-in-out infinite; +} + +/* === BUTTON ANIMATIONS === */ + +.btn-ripple { + position: relative; + overflow: hidden; +} + +.btn-ripple::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 255, 255, 0.5); + transform: translate(-50%, -50%); + transition: width 0.6s, height 0.6s; +} + +.btn-ripple:active::after { + width: 300px; + height: 300px; +} + +/* === MODAL ANIMATIONS === */ + +.modal-backdrop { + animation: fadeIn 0.3s ease; +} + +.modal-content { + animation: scaleIn 0.3s ease; +} + +/* === LOG ANIMATIONS === */ + +.log-entry-new { + animation: fadeInLeft 0.3s ease-in-out; + border-left: 3px solid var(--success-color); + padding-left: 0.5rem; +} + +.log-entry-error { + animation: shake 0.5s ease-in-out; + border-left: 3px solid var(--danger-color); + padding-left: 0.5rem; + background: rgba(220, 53, 69, 0.1); +} + +.log-entry-warning { + border-left: 3px solid var(--warning-color); + padding-left: 0.5rem; + background: rgba(255, 193, 7, 0.1); +} + +/* === DELAY UTILITIES === */ + +.delay-100 { + animation-delay: 0.1s; +} + +.delay-200 { + animation-delay: 0.2s; +} + +.delay-300 { + animation-delay: 0.3s; +} + +.delay-400 { + animation-delay: 0.4s; +} + +.delay-500 { + animation-delay: 0.5s; +} + +/* === STAGGERED ANIMATIONS === */ + +.stagger-item:nth-child(1) { animation-delay: 0.1s; } +.stagger-item:nth-child(2) { animation-delay: 0.2s; } +.stagger-item:nth-child(3) { animation-delay: 0.3s; } +.stagger-item:nth-child(4) { animation-delay: 0.4s; } +.stagger-item:nth-child(5) { animation-delay: 0.5s; } +.stagger-item:nth-child(6) { animation-delay: 0.6s; } +.stagger-item:nth-child(7) { animation-delay: 0.7s; } +.stagger-item:nth-child(8) { animation-delay: 0.8s; } +.stagger-item:nth-child(9) { animation-delay: 0.9s; } +.stagger-item:nth-child(10) { animation-delay: 1.0s; } + +/* === PERFORMANCE OPTIMIZATION === */ + +/* Use GPU acceleration for better performance */ +.animate-gpu { + transform: translateZ(0); + will-change: transform; +} + +/* Reduce motion for accessibility */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/Mimante/wwwroot/css/app.css b/Mimante/wwwroot/css/app.css new file mode 100644 index 0000000..7e61ce1 --- /dev/null +++ b/Mimante/wwwroot/css/app.css @@ -0,0 +1,603 @@ +:root { + /* Dark Theme Colors */ + --bg-primary: #0d1117; + --bg-secondary: #161b22; + --bg-tertiary: #21262d; + --bg-hover: #30363d; + --border-color: #30363d; + --text-primary: #c9d1d9; + --text-secondary: #8b949e; + --text-muted: #6e7681; + + /* Accent Colors */ + --primary-color: #58a6ff; + --success-color: #3fb950; + --warning-color: #d29922; + --danger-color: #f85149; + --info-color: #79c0ff; + + /* Shadows */ + --shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.5); + --shadow-md: 0 0.5rem 1rem rgba(0, 0, 0, 0.6); + --shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.7); + --transition-speed: 0.3s; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + background: var(--bg-primary); + color: var(--text-primary); +} + +.page { + position: relative; + display: flex; + flex-direction: row; + height: 100vh; + overflow: hidden; +} + +/* Sidebar Fissa */ +.sidebar { + width: 250px; + height: 100vh; + position: fixed; + top: 0; + left: 0; + background: linear-gradient(180deg, #1c2128 0%, #161b22 50%, #0d1117 100%); + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.5); + z-index: 1000; + display: flex; + flex-direction: column; + border-right: 1px solid var(--border-color); +} + +/* Main Content con Margine per Sidebar */ +main { + margin-left: 250px; + flex: 1; + display: flex; + flex-direction: column; + height: 100vh; + overflow-y: auto; + background: var(--bg-primary); +} + +.top-row { + background: var(--bg-secondary); + border-bottom: 1px solid var(--border-color); + height: auto; + min-height: 3.5rem; + display: flex; + align-items: center; + padding: 0.75rem 1.5rem; + box-shadow: var(--shadow-sm); +} + +.content { + flex: 1; + padding: 1.5rem; + overflow-y: auto; +} + +/* ==== AUCTION MONITOR STYLES ==== */ +.auction-monitor { + animation: fadeIn 0.5s ease-in; +} + +@keyframes fadeIn { + from { opacity: 0; transform: translateY(-10px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Toolbar */ +.toolbar { + margin-bottom: 1.5rem; + padding: 1rem; + background: var(--bg-secondary); + border-radius: 8px; + box-shadow: var(--shadow-sm); + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + border: 1px solid var(--border-color); +} + +.toolbar .btn { + border-radius: 6px; + font-weight: 500; + padding: 0.5rem 1rem; + transition: all var(--transition-speed) ease; + border: 1px solid transparent; +} + +.toolbar .btn:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: var(--shadow-md); +} + +/* Content Grid */ +.content-grid { + display: grid; + grid-template-columns: 1.2fr 0.8fr; + gap: 1.5rem; + margin-bottom: 1.5rem; +} + +/* Cards */ +.auctions-list, .auction-details, .global-log { + border: 1px solid var(--border-color); + border-radius: 10px; + padding: 1.5rem; + background: var(--bg-secondary); + box-shadow: var(--shadow-md); + transition: all var(--transition-speed) ease; +} + +.auctions-list h3, .auction-details h3, .global-log h4 { + color: var(--primary-color); + font-weight: 600; + margin-bottom: 1rem; + border-bottom: 2px solid var(--primary-color); + padding-bottom: 0.5rem; +} + +.auction-info { + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 1.25rem; +} + +.info-group { + margin-bottom: 1rem; +} + +.info-group label { + display: block; + font-weight: 600; + margin-bottom: 0.5rem; + color: var(--text-secondary); + font-size: 0.9rem; +} + +/* Tables */ +.table { + color: var(--text-primary); + border-color: var(--border-color); + background: transparent; +} + +.table thead { + background: linear-gradient(to right, var(--primary-color), #1f6feb); + color: white; +} + +.table thead th { + font-weight: 600; + border: none; + padding: 0.75rem; +} + +.table tbody tr { + transition: all 0.2s ease; + background: var(--bg-tertiary); + border-bottom: 1px solid var(--border-color); +} + +.table tbody tr:hover { + background: var(--bg-hover); + transform: scale(1.01); +} + +.table tbody tr.table-active { + background: linear-gradient(to right, rgba(88, 166, 255, 0.15), rgba(88, 166, 255, 0.25)); + border-left: 4px solid var(--primary-color); +} + +.table-striped tbody tr:nth-of-type(odd) { + background: var(--bg-tertiary); +} + +.table-striped tbody tr:nth-of-type(even) { + background: var(--bg-secondary); +} + +/* Badges */ +.badge { + font-weight: 600; + padding: 0.35rem 0.65rem; + border-radius: 20px; +} + +.badge-bg-primary { + background: var(--primary-color) !important; +} + +.badge-bg-success { + background: var(--success-color) !important; +} + +.badge-bg-warning { + background: var(--warning-color) !important; + color: #000 !important; +} + +.badge-bg-danger { + background: var(--danger-color) !important; +} + +.badge-bg-info { + background: var(--info-color) !important; + color: #000 !important; +} + +.badge-bg-secondary { + background: var(--text-secondary) !important; +} + +/* Forms */ +.form-control, .form-select { + background: var(--bg-tertiary); + border: 1px solid var(--border-color); + color: var(--text-primary); + border-radius: 6px; + transition: all var(--transition-speed) ease; +} + +.form-control:focus, .form-select:focus { + background: var(--bg-secondary); + border-color: var(--primary-color); + box-shadow: 0 0 0 0.2rem rgba(88, 166, 255, 0.25); + color: var(--text-primary); +} + +.form-control::placeholder { + color: var(--text-muted); +} + +.form-control:disabled, .form-select:disabled { + background: var(--bg-secondary); + opacity: 0.6; +} + +.form-check-input { + background-color: var(--bg-tertiary); + border-color: var(--border-color); +} + +.form-check-input:checked { + background-color: var(--primary-color); + border-color: var(--primary-color); +} + +.form-check-input:focus { + border-color: var(--primary-color); + box-shadow: 0 0 0 0.2rem rgba(88, 166, 255, 0.25); +} + +.form-label { + color: var(--text-primary); + font-weight: 500; +} + +/* Log Box - Terminal Dark Theme */ +.log-box { + height: 250px; + overflow-y: auto; + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 0.75rem; + background: #010409; + color: #c9d1d9; + font-family: 'Consolas', 'Courier New', monospace; + font-size: 0.813rem; + line-height: 1.5; + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); +} + +.log-box div { + padding: 0.25rem 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); +} + +.log-box::-webkit-scrollbar { + width: 8px; +} + +.log-box::-webkit-scrollbar-track { + background: #010409; + border-radius: 4px; +} + +.log-box::-webkit-scrollbar-thumb { + background: #30363d; + border-radius: 4px; +} + +.log-box::-webkit-scrollbar-thumb:hover { + background: #484f58; +} + +/* Alerts */ +.alert { + border-radius: 8px; + border: 1px solid; + box-shadow: var(--shadow-sm); + background: var(--bg-secondary); +} + +.alert-info { + background: linear-gradient(to right, rgba(121, 192, 255, 0.15), rgba(121, 192, 255, 0.1)); + border-color: var(--info-color); + color: var(--info-color); +} + +.alert-success { + background: linear-gradient(to right, rgba(63, 185, 80, 0.15), rgba(63, 185, 80, 0.1)); + border-color: var(--success-color); + color: var(--success-color); +} + +.alert-warning { + background: linear-gradient(to right, rgba(210, 153, 34, 0.15), rgba(210, 153, 34, 0.1)); + border-color: var(--warning-color); + color: var(--warning-color); +} + +.alert-danger { + background: linear-gradient(to right, rgba(248, 81, 73, 0.15), rgba(248, 81, 73, 0.1)); + border-color: var(--danger-color); + color: var(--danger-color); +} + +.alert-secondary { + background: linear-gradient(to right, rgba(139, 148, 158, 0.15), rgba(139, 148, 158, 0.1)); + border-color: var(--border-color); + color: var(--text-secondary); +} + +/* Cards */ +.card { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + border-radius: 12px; + color: var(--text-primary); +} + +.card-header { + background: var(--bg-tertiary); + border-bottom: 1px solid var(--border-color); + color: var(--text-primary); + font-weight: 600; + padding: 1.25rem; +} + +.card-body { + padding: 1.5rem; +} + +/* Buttons */ +.btn { + border-radius: 6px; + font-weight: 500; + transition: all var(--transition-speed) ease; + border: 1px solid transparent; +} + +.btn:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: var(--shadow-sm); +} + +.btn-primary { + background: var(--primary-color); + border-color: var(--primary-color); + color: #fff; +} + +.btn-primary:hover:not(:disabled) { + background: #1f6feb; + border-color: #1f6feb; +} + +.btn-success { + background: var(--success-color); + border-color: var(--success-color); + color: #fff; +} + +.btn-success:hover:not(:disabled) { + background: #2ea043; + border-color: #2ea043; +} + +.btn-warning { + background: var(--warning-color); + border-color: var(--warning-color); + color: #000; +} + +.btn-warning:hover:not(:disabled) { + background: #bb8009; + border-color: #bb8009; +} + +.btn-danger { + background: var(--danger-color); + border-color: var(--danger-color); + color: #fff; +} + +.btn-danger:hover:not(:disabled) { + background: #da3633; + border-color: #da3633; +} + +.btn-secondary { + background: var(--bg-tertiary); + border-color: var(--border-color); + color: var(--text-primary); +} + +.btn-secondary:hover:not(:disabled) { + background: var(--bg-hover); + border-color: var(--text-secondary); +} + +.btn-info { + background: var(--info-color); + border-color: var(--info-color); + color: #000; +} + +.btn-info:hover:not(:disabled) { + background: #4184e4; + border-color: #4184e4; +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Modal */ +.modal { + backdrop-filter: blur(4px); +} + +.modal-content { + background: var(--bg-secondary); + border: 1px solid var(--border-color); + color: var(--text-primary); +} + +.modal-header { + background: var(--bg-tertiary); + border-bottom: 1px solid var(--border-color); +} + +.modal-footer { + background: var(--bg-tertiary); + border-top: 1px solid var(--border-color); +} + +.btn-close { + filter: invert(1) grayscale(100%) brightness(200%); +} + +/* Input Groups */ +.input-group .form-control { + border-right: 1px solid var(--border-color); +} + +.input-group .btn { + border-left: none; +} + +.input-group-text { + background: var(--bg-tertiary); + border-color: var(--border-color); + color: var(--text-primary); +} + +/* Blazor Error UI */ +#blazor-error-ui { + background: linear-gradient(to right, #332600, #4d3900); + bottom: 0; + box-shadow: var(--shadow-md); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; + border-top: 3px solid var(--warning-color); + color: var(--warning-color); +} + +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; + font-weight: bold; + color: var(--warning-color); +} + +/* Responsive Design */ +@media (max-width: 1200px) { + .content-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 768px) { + .sidebar { + width: 100%; + height: auto; + position: relative; + border-right: none; + border-bottom: 1px solid var(--border-color); + } + + main { + margin-left: 0; + } + + .toolbar { + padding: 0.75rem; + } + + .toolbar .btn { + padding: 0.375rem 0.75rem; + font-size: 0.875rem; + } +} + +/* Utility Classes */ +.shadow-hover { + transition: box-shadow var(--transition-speed) ease; +} + +.shadow-hover:hover { + box-shadow: var(--shadow-lg) !important; +} + +.text-muted { + color: var(--text-muted) !important; +} + +.text-secondary { + color: var(--text-secondary) !important; +} + +.fw-semibold { + font-weight: 600 !important; +} + +/* Scrollbar Global */ +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-track { + background: var(--bg-primary); +} + +::-webkit-scrollbar-thumb { + background: var(--bg-hover); + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); +} diff --git a/Mimante/wwwroot/css/bootstrap/bootstrap.min.css b/Mimante/wwwroot/css/bootstrap/bootstrap.min.css new file mode 100644 index 0000000..10f2cc9 --- /dev/null +++ b/Mimante/wwwroot/css/bootstrap/bootstrap.min.css @@ -0,0 +1,47 @@ +/* Bootstrap is normally downloaded, but for Docker build we'll use CDN in _Layout.cshtml */ +/* Placeholder for custom Bootstrap overrides */ + +:root { + --primary-color: #3498db; + --success-color: #27ae60; + --warning-color: #f39c12; + --danger-color: #e74c3c; + --dark-color: #2c3e50; + --light-color: #ecf0f1; +} + +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); +} + +.btn-success { + background-color: var(--success-color); + border-color: var(--success-color); +} + +.btn-warning { + background-color: var(--warning-color); + border-color: var(--warning-color); +} + +.btn-danger { + background-color: var(--danger-color); + border-color: var(--danger-color); +} + +.bg-primary { + background-color: var(--primary-color) !important; +} + +.bg-success { + background-color: var(--success-color) !important; +} + +.bg-warning { + background-color: var(--warning-color) !important; +} + +.bg-danger { + background-color: var(--danger-color) !important; +} diff --git a/Mimante/wwwroot/js/browser-interop.js b/Mimante/wwwroot/js/browser-interop.js new file mode 100644 index 0000000..803db43 --- /dev/null +++ b/Mimante/wwwroot/js/browser-interop.js @@ -0,0 +1,161 @@ +// browser-interop.js - JavaScript per controllo iframe Browser + +window.initializeBrowserFrame = function () { + console.log('[Browser] Inizializzazione iframe...'); + + const iframe = document.getElementById('bidooFrame'); + if (!iframe) { + console.error('[Browser] Iframe non trovato!'); + return; + } + + // Listener per cambio URL (se accessibile) + iframe.addEventListener('load', function () { + console.log('[Browser] Iframe caricato'); + + try { + const iframeUrl = iframe.contentWindow.location.href; + console.log('[Browser] URL corrente:', iframeUrl); + } catch (e) { + console.warn('[Browser] Impossibile accedere a iframe URL (CORS):', e.message); + } + }); + + console.log('[Browser] Iframe inizializzato con successo'); +}; + +window.navigateBack = function () { + const iframe = document.getElementById('bidooFrame'); + if (iframe && iframe.contentWindow) { + try { + iframe.contentWindow.history.back(); + } catch (e) { + console.error('[Browser] Errore navigazione indietro:', e.message); + } + } +}; + +window.navigateForward = function () { + const iframe = document.getElementById('bidooFrame'); + if (iframe && iframe.contentWindow) { + try { + iframe.contentWindow.history.forward(); + } catch (e) { + console.error('[Browser] Errore navigazione avanti:', e.message); + } + } +}; + +window.refreshFrame = function () { + const iframe = document.getElementById('bidooFrame'); + if (iframe) { + iframe.src = iframe.src; // Force reload + console.log('[Browser] Frame ricaricato'); + } +}; + +window.canGoBack = function () { + // Non possiamo verificare history iframe cross-origin + return false; +}; + +window.canGoForward = function () { + // Non possiamo verificare history iframe cross-origin + return false; +}; + +window.extractCookie = function (domain) { + console.log('[Browser] Tentativo estrazione cookie per:', domain); + + try { + // Tenta di accedere ai cookie del documento corrente + const cookies = document.cookie; + console.log('[Browser] Cookie trovati:', cookies); + + // Cerca il cookie specifico di Bidoo + const cookieArray = cookies.split(';'); + for (let i = 0; i < cookieArray.length; i++) { + const cookie = cookieArray[i].trim(); + + // Cerca __stattrb o altri cookie Bidoo + if (cookie.startsWith('__stattrb=') || + cookie.startsWith('PHPSESSID=') || + cookie.startsWith('bidoo_session=')) { + console.log('[Browser] Cookie trovato:', cookie); + return cookie; + } + } + + // Se non trova cookie specifici, prova a leggere dall'iframe + const iframe = document.getElementById('bidooFrame'); + if (iframe && iframe.contentWindow) { + try { + const iframeCookies = iframe.contentWindow.document.cookie; + console.log('[Browser] Cookie iframe:', iframeCookies); + + if (iframeCookies) { + return iframeCookies; + } + } catch (e) { + console.warn('[Browser] CORS blocca accesso cookie iframe:', e.message); + } + } + + console.warn('[Browser] Nessun cookie trovato'); + return null; + } catch (e) { + console.error('[Browser] Errore estrazione cookie:', e.message); + return null; + } +}; + +window.getCookieFromDevTools = function () { + // Mostra istruzioni per estrazione manuale + const instructions = ` +???????????????????????????????????????????????????????????? +? ?? ESTRAZIONE COOKIE MANUALE - ISTRUZIONI ? +???????????????????????????????????????????????????????????? + +1?? Premi F12 per aprire gli strumenti sviluppatore + +2?? Vai alla tab "Application" o "Storage" + +3?? Nel menu a sinistra, espandi "Cookies" + +4?? Clicca su "https://it.bidoo.com" + +5?? Cerca il cookie "__stattrb" o "PHPSESSID" + +6?? Copia il valore del cookie + +7?? Incolla nelle Impostazioni di AutoBidder + +???????????????????????????????????????????????????????????? +? ?? NOTA: Questo necessario per le limitazioni CORS ? +???????????????????????????????????????????????????????????? + `; + + console.log(instructions); + return instructions; +}; + +// Debug helper +window.debugBrowserFrame = function () { + const iframe = document.getElementById('bidooFrame'); + + console.log('=== DEBUG BROWSER FRAME ==='); + console.log('Iframe element:', iframe); + console.log('Iframe src:', iframe?.src); + console.log('Document cookies:', document.cookie); + + try { + console.log('Iframe URL:', iframe?.contentWindow?.location?.href); + console.log('Iframe cookies:', iframe?.contentWindow?.document?.cookie); + } catch (e) { + console.log('CORS blocks iframe access:', e.message); + } + + console.log('=== END DEBUG ==='); +}; + +console.log('[Browser] JavaScript loaded successfully');