Compare commits

..

64 Commits

Author SHA1 Message Date
e18a09e1da Gestione massiva limiti prodotto e ottimizzazione ticker
Aggiunta barra azioni per gestione massiva limiti prodotto in Statistics.razor (applica, salva, attiva/disattiva, copia consigliati). Uniformati simboli euro e messaggi in italiano. Ottimizzata la logica del ticker: controllo puntata ora avviene prima del polling, gestione fine asta differita tramite PendingEndState. Introdotto controllo esplicito su MaxClicks per asta. Implementata cache delle impostazioni in SettingsManager per ridurre accessi disco. Vari fix minori e miglioramenti di robustezza.
2026-03-03 08:53:38 +01:00
f3262a0497 Log aste strutturato, limiti prodotto e UI statistiche
- Log per-asta ora strutturato con livelli, categorie e deduplicazione; motivi di blocco puntata tracciati in modo dettagliato e throttled
- Nuova visualizzazione log compatta e colorata nella UI
- Migliorate statistiche prodotto: aggiunta mediana prezzo, flag UseCustomLimits e editing limiti inline
- Impostazione priorità limiti nuove aste (globali vs personalizzati)
- Refactoring: rimossi limiti reset, UI statistiche rinnovata, ordinamenti e filtri avanzati
- Aggiornato schema DB (MedianFinalPrice, UseCustomLimits)
- Diagnostica periodica e log dettagliato su ticker/controlli
2026-02-16 23:10:04 +01:00
690f7e636a Ottimizzazione RAM, UI e sistema di timing aste
- Ridotto consumo RAM: limiti log, pulizia e compattazione dati aste, timer periodico di cleanup
- UI più fluida: cache locale aste, throttling aggiornamenti, refresh log solo se necessario
- Nuovo sistema Ticker Loop: timing configurabile, strategie solo vicino alla scadenza, feedback puntate tardive
- Migliorato layout e splitter, log visivo, gestione cache HTML
- Aggiornata UI impostazioni e fix vari per performance e thread-safety
2026-02-07 19:28:30 +01:00
5b95f18889 Restyling monitor aste: toolbar compatta, split panel, UX
- Nuova toolbar compatta con azioni rapide e indicatori stato aste
- Layout a pannelli ridimensionabili con splitter drag&drop
- Tabella aste compatta, ping colorato, azioni XS
- Pulsanti per rimozione aste per stato (attive, vinte, ecc.)
- Dettagli asta sempre visibili in pannello inferiore
- Statistiche prodotti: filtro, ordinamento, editing limiti default
- Limiti default prodotto salvati in DB, applicabili a tutte le aste
- Migliorata sidebar utente con info sessione sempre visibili
- Log motivi blocco puntata sempre visibili, suggerimenti timing
- Miglioramenti filtri, UX responsive, fix minori e feedback visivi
2026-02-06 15:35:53 +01:00
45dd205270 Miglioramento commenti e semplificazione logica puntata
Correzione della codifica dei caratteri speciali nei commenti e nei log, aggiunta dei namespace mancanti, semplificazione della condizione per la puntata automatica e aggiornamento dei simboli di valuta. Refactoring generale dei commenti per maggiore chiarezza e manutenzione, senza modifiche alla logica principale.
2026-02-05 09:36:40 +01:00
0764b0b625 Semplifica timing puntata, logging e controllo convenienza
- Timing di puntata ora gestito solo da offset fisso configurabile, rimosse strategie di compensazione latenza/jitter/offset dinamico
- Aggiunto controllo convenienza: blocca puntate se il costo supera il "Compra Subito" oltre una soglia configurabile
- Logging granulare: nuove opzioni per log selettivo (puntate, strategie, valore, competizione, timing, errori, stato, profiling avversari)
- Persistenza stato browser aste (categoria, ricerca) tramite ApplicationStateService
- Fix conteggio puntate per bidder, rimosso rilevamento "Last Second Sniper", aggiunta strategia "Price Momentum"
- Refactoring e pulizia: rimozione codice obsoleto, migliorata documentazione e thread-safety
2026-02-05 09:28:58 +01:00
8befcb8abf Rework UI, log e strategie; fix selezione aste
- Interfaccia impostazioni più compatta e responsive, rimosse animazioni popup su hover, evidenziazione con colore
- Ottimizzazione visualizzazione puntate e statistiche, evidenza puntate proprie
- Rework sistema di log: eliminazione duplicati e info inutili, maggiore leggibilità
- Aggiunti nuovi stati e motivazioni per cui il bot non punta (fuori range, strategia, ecc)
- Fix critico: selezione aste ora sempre aggiornata e salvata correttamente
- Migliorata logica aggiunta puntate mancanti, niente duplicati
- Rimossa logica errata "Entry Point": limiti utente ora rigidi, usato solo per suggerimenti
- Aggiornata documentazione e guide per riflettere le nuove funzionalità
2026-02-03 10:50:51 +01:00
89aed8a458 Migliorie UI, log aste, strategie e statistiche puntatori
- Ordinamento colonne griglia aste e indicatori visivi
- Nuovo pulsante per rimozione rapida aste terminate
- Log aste con deduplicazione e contatore
- Statistiche puntatori cumulative e più affidabili
- Cronologia puntate senza duplicati consecutivi
- Strategie di puntata semplificate: entry point, anti-bot, user exhaustion
- UI più compatta, hover moderni, evidenziazione puntate utente
- Correzioni internazionalizzazione e pulizia codice
2026-02-03 00:00:33 +01:00
ae861e78d2 Implementate strategie avanzate e tracking aste v1.3.0
- Aggiunto BidStrategyService: adaptive latency, jitter, offset dinamico, heat metric, soft retreat, probabilistic bidding, profiling avversari, bankroll manager.
- Esteso AuctionInfo con metriche avanzate: latenze, collisioni, heat, duello, tracking sessione, override strategie.
- Nuova sezione "Strategie Avanzate" in Settings (UI) con opzioni dettagliate e bulk update.
- Miglioramenti UX: auto-scroll log, filtri e dettagli avanzati in Statistics, gestione nomi prodotti, pulsanti sempre attivi.
- Fix bug Blazor (layout, redirect, log, conteggio puntate, entità HTML).
- Aggiornata documentazione, changelog, guide Docker/Gitea.
- Versione incrementata a 1.3.0. Migrazione database per nuove metriche e tracking completo.
2026-01-28 11:37:40 +01:00
77eb9943d0 Gestione avanzata database e rimozione MaxClicks
Aggiunta sezione impostazioni per manutenzione database (auto-salvataggio, pulizia duplicati/incompleti, retention, ottimizzazione). Implementati metodi asincroni in DatabaseService per pulizia e statistiche. Pulizia automatica all’avvio secondo impostazioni. Rimossa la proprietà MaxClicks da modello, UI e logica. Migliorata la sicurezza thread-safe e la trasparenza nella gestione dati. Spostato il badge versione nelle info applicazione.
2026-01-24 01:30:49 +01:00
a0ec72f6c0 Refactor: solo SQLite, limiti auto, UI statistiche nuova
Rimosso completamente il supporto a PostgreSQL: ora tutte le statistiche e i dati persistenti usano solo SQLite, con percorso configurabile tramite DATA_PATH per Docker/volumi. Aggiunta gestione avanzata delle statistiche per prodotto, limiti consigliati calcolati automaticamente e applicabili dalla UI. Rinnovata la pagina Statistiche con tabelle aste recenti e prodotti, rimosso il supporto a grafici legacy e a "Puntate Gratuite". Migliorata la ricerca e la gestione delle aste nel browser, aggiunta diagnostica avanzata e logging dettagliato per il database. Aggiornati Dockerfile e docker-compose: l'app è ora self-contained e pronta per l'uso senza database esterni.
2026-01-23 16:56:03 +01:00
21a1d57cab Migliora badge stato aste: nuovi colori, icone, animazioni
Rivisti i metodi di calcolo e visualizzazione dello stato delle aste in Index.razor.cs, distinguendo tra stati di sistema e controllati dall’utente. Aggiunte nuove classi CSS e animazioni in modern-pages.css per badge più chiari, compatti e animati. Mantenuta compatibilità con classi Bootstrap legacy. Migliorata la leggibilità e l’usabilità della tabella aste.
2026-01-22 15:28:05 +01:00
2833cd0487 Aggiornamento live aste, azioni rapide e scroll infinito
- Aggiornamento automatico degli stati delle aste ogni 500ms, rimosso il bottone manuale "Aggiorna Prezzi"
- Aggiunti pulsanti per copiare il link e aprire l'asta in nuova scheda
- Possibilità di rimuovere aste dal monitor direttamente dalla lista
- Caricamento aste ottimizzato: scroll infinito senza duplicati tramite nuova API get_auction_updates.php
- Migliorato il parsing dei dati e la precisione del countdown usando il timestamp del server
- Refactoring vari per migliorare la reattività e l'esperienza utente
2026-01-22 11:43:59 +01:00
865bfa2752 Aggiunta pagina "Esplora Aste" per browser pubblico
Introdotta la funzionalità di esplorazione delle aste pubbliche di Bidoo senza login, accessibile dal menu principale.
Aggiunti nuovi modelli (`BidooBrowserAuction`, `BidooCategoryInfo`) e servizio (`BidooBrowserService`) per scraping e polling delle aste e categorie.
Creata la pagina Blazor `AuctionBrowser.razor` con griglia responsive, badge, filtri per categoria, caricamento incrementale e aggiornamento automatico degli stati.
Aggiornati i servizi in `Program.cs` e aggiunti nuovi stili CSS per la UI moderna.
Le aste possono essere aggiunte rapidamente al monitor personale. Parsing robusto e fallback su categorie predefinite in caso di errori.
2026-01-22 00:08:16 +01:00
70ed8f0a61 Modernizzazione UI: nuovo tema dark e sidebar rivista
Aggiorna l’interfaccia Blazor con una palette dark moderna, font Inter, e una sidebar ridisegnata.
Riorganizza layout e navigazione, migliora la gestione errori e introduce nuovi stili per card, bottoni, input e badge.
Aggiunto `modern-pages.css` per header, griglie statistiche, alert e form più coerenti e attuali.
Migliora leggibilità, navigazione e user experience complessiva.
2026-01-21 17:39:15 +01:00
ed42a41bcd Autenticazione Identity: login sicuro, lockout, UI aggiornata
- Integra ASP.NET Core Identity: login/password, lockout brute-force, cookie sicuri, password policy forte
- Seed automatico utente admin da variabili ambiente (fallback password temporanea forte)
- Tutte le pagine principali ora protette con [Authorize] e redirect automatico a /login
- Nuovo layout login/logout pulito senza sidebar, spinner durante redirect
- NavMenu mostra utente autenticato e logout
- Rimosse credenziali Bidoo da env/Docker: ora solo cookie sessione da UI
- Aggiornata documentazione: sicurezza, deploy, backup, troubleshooting
- Fix NavigationException, SectionRegistry, errori header read-only
- Versione incrementata a 1.2.0, pronto per deploy production Tailscale/Unraid
2026-01-21 17:00:51 +01:00
6a3f931431 Fix definitivo porta 8080 + healthcheck e doc v1.1.2
Forzato UseUrls() su 8080 per evitare override e garantire che il container ascolti sempre sulla porta corretta. Migliorati i parametri del healthcheck Docker per Blazor Server (timeout 30s, start-period 90s, retries 5). Aggiornati metadati di versione a 1.1.2. Aggiunta documentazione dettagliata sul fix e corretti caratteri accentati nel changelog.
2026-01-21 12:42:34 +01:00
ef1bc92e67 fix: container ascolta su porta 8080 (non 5000)
Rimosso override esplicito porta HTTP in Program.cs: ora la porta è gestita solo da ASPNETCORE_URLS (default 8080), risolvendo il bug che impediva l’accesso web al container. Aggiornati Dockerfile, docker-compose.yml e documentazione per riflettere la nuova configurazione. Versione incrementata a 1.1.1 (PATCH). HTTPS resta disabilitato di default; configurazione centralizzata e override semplice via env. Aggiunti changelog, troubleshooting e script bump-version aggiornato.
2026-01-20 23:06:01 +01:00
343f171d6a Semplifica workflow Docker/Gitea, versionamento automatico
- Corretto path registry Docker: ora 3 livelli (owner/image)
- Aggiunto target post-build: tagging e push automatico su Gitea (latest + versione)
- Inclusi Dockerfile, .dockerignore e profilo pubblicazione nel progetto
- Kestrel: HTTPS configurabile, gestione certificati e log migliorati
- HSTS/HTTPS redirection ora condizionali
- Aggiornate guide e checklist: workflow, troubleshooting, best practice
- Unificato profilo di pubblicazione: versionamento da <Version> in .csproj
- Processo di build/push ora integrato, automatico e conforme a Gitea
2026-01-20 21:57:48 +01:00
61f0945db2 Supporto PostgreSQL, statistiche avanzate e nuova UI
Aggiornamento massivo: aggiunto backend PostgreSQL per statistiche aste con fallback SQLite, nuovi modelli e servizi, UI moderna con grafici interattivi, refactoring stato applicazione (ApplicationStateService), documentazione completa per deploy Docker/Unraid/Gitea, nuovi CSS e script JS per UX avanzata, template Unraid, test database, e workflow CI/CD estesi. Pronto per produzione e analisi avanzate.
2026-01-18 17:52:05 +01:00
29724f5baf Refactoring: Docker, CI/CD, tema WPF, DB avanzato, UX
- Aggiunto sistema completo di build/deploy Docker, Makefile, compose, .env, workflow CI/CD (Gitea, GitHub Actions)
- Nuovo servizio DatabaseService con migrations, healthcheck, backup, ottimizzazione, info
- Endpoint /health per healthcheck container
- Impostazioni avanzate di avvio aste (ricorda stato, auto-start, default nuove aste)
- Nuovo tema grafico WPF: palette, sidebar, layout griglia, log colorati, badge, cards, modali, responsività
- Migliorato calcolo valore prodotto, logica convenienza, blocco puntate non convenienti, log dettagliati
- Semplificate e migliorate pagine FreeBids, Settings, Statistics; rimossa Browser.razor
- Aggiornato .gitignore, documentazione, struttura progetto
- Base solida per future funzionalità avanzate e deploy professionale
2025-12-23 21:35:44 +01:00
009fa51155 Aggiunta UI Blazor moderna e animazioni per AutoBidder
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.
2025-12-12 09:32:30 +01:00
7b405ed78e Rimuovi export settings, aggiungi filtro livello log
- Rimossa la sezione "Impostazioni Export" dalla UI e dal code-behind, inclusi controlli, eventi e file legacy di export.
- Aggiunta configurazione del livello minimo di log (ErrorOnly, Normal, Informational, Debug, Trace) con guida e legenda colori.
- La funzione di log ora filtra i messaggi in base al livello selezionato.
- Aggiornati modelli di impostazioni e enum LogLevel per supportare i nuovi livelli.
- Refactoring commenti e uniformità sezioni impostazioni.
- Migliorata la chiarezza del log di avvio applicazione.
2025-12-11 14:20:05 +01:00
79756d878d Aggiornamento asset, UI e funzionalità per aste e player
Sono stati aggiunti numerosi nuovi file JavaScript, CSS, SVG e PNG per migliorare la grafica, la responsività e le funzionalità delle pagine di aste, login, notifiche e player video.
Introdotte nuove librerie (OneSignal, Bootstrap, Font Awesome, Vue.js, Slick Carousel, ProgressBar.js, CryptoJS, mCustomScrollbar, Switchery) e script per la gestione di notifiche push, tracciamento eventi (Facebook Pixel, TikTok Pixel, Google Ads, Smartech), pagamenti Ingenico, modali, banner promozionali, preferiti, auto-puntate, e gestione utente inattivo.
Ampliata la logica del player embedded YouTube con nuovi hook, logging avanzato, gestione ciclo di vita, storage e challenge di attestation.
Aggiunti nuovi stili CSS per layout responsive, componenti UI, modali, badge, bottoni, progress bar, e ottimizzazioni mobile.
Integrate nuove immagini e icone per arricchire l’interfaccia grafica.
Non sono state apportate modifiche al file `www-player.css` e ad altri file specificati.
Queste modifiche migliorano la sicurezza, la tracciabilità, l’esperienza utente e la flessibilità dell’applicazione.
2025-12-10 12:00:25 +01:00
551697d98d Aggiunta validazione robusta per campi numerici
Implementata una nuova funzionalità per garantire che tutti i campi numerici accettino solo input validi.
- Introdotta la classe helper `NumericTextBoxHelper` per configurare campi interi e decimali.
- Gestiti input non validi, campi vuoti e normalizzazione dei decimali.
- Applicata validazione a 13 campi numerici in tutta l'applicazione.
- Aggiunto supporto per tastiere internazionali (punto e virgola).
- Aggiornati `MainWindow.xaml.cs`, `CHANGELOG.md` e documentazione.
- Definiti test e casi d'uso per verificare il corretto funzionamento.
2025-11-27 17:29:09 +01:00
3db0d946b7 Aggiunti riordinamento e navigazione aste migliorati
- Introdotti pulsanti "Sposta Su" e "Sposta Giù" per il
  riordinamento manuale delle aste nella lista.
- Implementata navigazione con frecce direzionali nella griglia,
  con aggiornamento automatico dei dettagli e scroll.
- Salvato automaticamente l'ordine delle aste su disco.
- Risolto conflitto con GridSplitter per le frecce direzionali.
- Aggiunti log dettagliati per le operazioni di riordinamento.
- Gestiti casi limite (es. asta già in cima o in fondo).
- Migliorata UX con pulsanti chiari e tooltip informativi.
- Aggiornati documentazione e changelog per riflettere le
  modifiche.
2025-11-27 15:47:58 +01:00
d08e54657a Migliora gestione visualizzazione latenza asta
- Modificato il binding della colonna "Latenza" in `AuctionMonitorControl.xaml` per utilizzare la nuova proprietà `LatencyDisplay`.
- Aggiunta la proprietà `LatencyDisplay` in `AuctionViewModel.cs` per calcolare dinamicamente la latenza in base allo stato dell'asta.
- Aggiunte notifiche di cambiamento per `LatencyDisplay` per aggiornare correttamente l'interfaccia utente.
- Documentata la proprietà `LatencyDisplay` con commenti XML per migliorarne la comprensione.
2025-11-27 12:42:20 +01:00
b810c7f76b Rimuove colonna "Resets" da AuctionMonitorControl.xaml
La colonna "Resets" è stata rimossa dal `DataGrid` in
`AuctionMonitorControl.xaml`. Era legata alla proprietà
`ResetCount` e aveva una larghezza di 60. Questa modifica
semplifica l'interfaccia utente, eliminando un'informazione
non più necessaria.
2025-11-27 12:29:40 +01:00
95018e0d65 Aggiunto HtmlCacheService per caching e rate limiting
Introdotto un servizio centralizzato (`HtmlCacheService`) per gestire richieste HTTP con:
- Cache HTML (5 minuti) per ridurre richieste duplicate.
- Rate limiting (max 5 richieste/sec) e concorrenza limitata (3 richieste parallele).
- Retry automatico (max 2 tentativi) e timeout configurabile (15s).
- Logging dettagliato per cache hit, retry e richieste fallite.

Aggiornati i metodi di caricamento dei nomi e delle informazioni prodotto per utilizzare il nuovo servizio, migliorando caching, gestione degli errori e decodifica delle entità HTML.

Aggiunto supporto per il recupero automatico dei nomi generici delle aste e un timer per la pulizia periodica della cache.

Documentato il servizio in `FEATURE_HTML_CACHE_SERVICE.md`. Correzioni minori e miglioramenti alla leggibilità del codice.
2025-11-27 12:24:09 +01:00
df9b63dd41 Aggiunta opzione "Ricorda Stato" per le aste salvate
È stata introdotta l'opzione "Ricorda Stato" che consente di ripristinare lo stato esatto (attiva, in pausa, ferma) di ogni asta salvata al caricamento.

- Aggiunto il `RadioButton` "Ricorda Stato" in `SettingsControl.xaml`.
- Gestita la nuova opzione in `MainWindow.EventHandlers.Settings.cs`.
- Aggiornata la logica di caricamento in `AuctionManagement.cs` per supportare "Ricorda Stato".
- Introdotto il salvataggio automatico dello stato delle aste in `ButtonHandlers.cs` e `Commands.cs`.
- Migliorati i log per riflettere il comportamento del sistema.
- Aggiunta la proprietà `RememberAuctionStates` in `SettingsManager` con valore predefinito `false`.
- Migliorata la leggibilità e manutenibilità del codice.

Queste modifiche migliorano la flessibilità e l'esperienza utente, garantendo coerenza dei dati e maggiore chiarezza nei log.
2025-11-26 20:52:48 +01:00
7a01251258 Refactoring layout Header AuctionMonitorControl.xaml
È stato aggiornato il layout del `Header` per passare da una struttura compatta su 2 righe a una su 3 righe.

- Aggiunta una nuova `RowDefinition` per gestire la terza riga.
- Modificato il `Padding` del `Border` da `15,10` a `15,8`.
- Aggiornata `Riga 1` per mostrare solo le `Puntate` con margine ridotto.
- Aggiunta `Riga 2` per visualizzare il `Credito Shop` con margini e font ridotti.
- Aggiornata `Riga 3` per mostrare solo le `Aste vinte da confermare`.
- Esteso lo `StackPanel` dei pulsanti di controllo per coprire tutte e 3 le righe.
- Migliorata la leggibilità dei commenti relativi agli indicatori di limite minimo.
2025-11-26 11:58:20 +01:00
56484e0bec Aggiunto pulsante "Rimuovi Tutte" e miglioramenti UI
- Aggiunto il pulsante "Rimuovi Tutte" in `AuctionMonitorControl.xaml` per eliminare tutte le aste monitorate.
- Implementato il metodo `RemoveAllButton_Click` in `AuctionMonitorControl.xaml.cs` e registrato il nuovo evento routed `RemoveAllClickedEvent`.
- Aggiunto il gestore `AuctionMonitor_RemoveAllClicked` in `MainWindow.ControlEvents.cs` e collegato l'evento in `MainWindow.xaml`.
- Migliorata la gestione degli errori e aggiunti messaggi di conferma dettagliati.
- Introdotti nuovi metodi di utilità per resettare le impostazioni, pulire la lista utenti e il log di un'asta selezionata.
- Rimosso codice obsoleto per semplificare la base di codice.
2025-11-26 11:37:11 +01:00
c199e542ba Aggiunto limite configurabile storia puntate
Introdotta la possibilità di configurare un limite massimo di puntate visualizzabili nella scheda "Storia Puntate" tramite l'interfaccia utente. La nuova proprietà `MaxBidHistoryEntries` è stata aggiunta alle impostazioni e salvata in modo persistente.

- Aggiunti controlli UI per configurare il limite.
- Implementata persistenza della lista `RecentBids` con serializzazione JSON.
- Introdotto il metodo `MergeBidHistory` per unire puntate evitando duplicati e mantenendo ordine cronologico decrescente.
- Sincronizzate le statistiche utenti (`BidderStats`) con la lista `RecentBids`.
- Ripristinata la proprietà `IsMyBid` al caricamento delle aste salvate.
- Ottimizzate le performance con `HashSet` per deduplicazione e limite configurabile.
- Creato il file `FIX_BID_HISTORY_PERSISTENCE.md` per documentare il problema e la soluzione.
- Garantita compatibilità retroattiva con aste salvate.

Questi aggiornamenti migliorano la gestione, la visualizzazione e la persistenza della storia delle puntate, offrendo un'esperienza utente più robusta e intuitiva.
2025-11-26 10:44:04 +01:00
d99b5ec923 Aggiunta scheda "Storia Puntate" con aggiornamento live
Introdotta una nuova scheda "Storia Puntate" nel pannello
dell'asta selezionata, che mostra la cronologia delle ultime
puntate in tempo reale. La scheda utilizza un `TabControl`
con due `TabItem`: uno per gli utenti e uno per la storia
delle puntate.

- Creata la classe `BidHistoryEntry` per rappresentare una
  singola puntata, con proprietà come `Price`, `BidType`,
  `Timestamp`, e calcoli formattati.
- Aggiunte proprietà `RecentBids` in `AuctionInfo` e
  `RecentBidsHistory` in `AuctionState` per gestire i dati
  della cronologia.
- Modificato il parsing API in `BidooApiClient` per includere
  la cronologia delle puntate.
- Aggiornato il monitor delle aste (`AuctionMonitor.cs`) per
  sincronizzare i dati della cronologia con il backend.
- Aggiunta la proprietà `BidHistoryEntries` in
  `AuctionViewModel` per il binding della griglia.
- Modificata la UI (`AuctionMonitorControl.xaml`) per
  includere la nuova scheda e personalizzare gli stili.
- Aggiornata la logica di aggiornamento UI in
  `MainWindow.xaml.cs` per gestire i dati della cronologia.
- Documentata la funzionalità in `FEATURE_BID_HISTORY_TAB.md`.
- Aggiunto uno screenshot (`Screenshot 2025-11-25 113552.png`).

Questa funzionalità migliora la trasparenza e fornisce agli
utenti informazioni dettagliate sulle attività recenti,
aiutandoli a prendere decisioni strategiche durante le aste.
2025-11-25 14:35:09 +01:00
6795282993 Migliorato auto-login e gestione cookie WebView2
- Introdotto il pre-caricamento di WebView2 per ridurre i tempi di attesa.
- Implementato il pattern TaskCompletionSource per attendere l'inizializzazione di WebView2 (timeout 60s).
- Centralizzata la logica di verifica e importazione automatica dei cookie.
- Mostrate istruzioni di login solo se necessario, migliorando l'UX.
- Risolti problemi di timeout e threading durante l'inizializzazione di WebView2.
- Puliti e ottimizzati i log per maggiore chiarezza.
- Rimossa la gestione manuale dei cookie, ora automatizzata.
2025-11-25 11:33:50 +01:00
62d5cebf9c Refactoring gestione sessione e persistenza impostazioni
Introdotto `SessionService` per centralizzare la gestione della
sessione utente, migliorando la separazione delle responsabilità
e la testabilità. Risolto il problema del caricamento del cookie
di autenticazione all'avvio e garantita la persistenza delle
checkbox di esportazione (`IncludeMetadata`, `RemoveAfterExport`,
`OverwriteExisting`).

Ottimizzata la gestione della barra degli indirizzi del browser
con aggiornamenti locali immediati. Applicato il pattern "Load ?
Modify ? Save" per il salvataggio delle impostazioni, migliorando
la simmetria e la leggibilità del codice. Logging centralizzato
e semplificato per eventi rilevanti.

Aggiornata la documentazione per riflettere i cambiamenti e
verificati i test per garantire il corretto funzionamento.
2025-11-24 12:00:13 +01:00
ee67bedc31 Aggiunta calcolo valore prodotto e miglioramenti UI
Implementato il calcolo del valore reale dei prodotti in asta,
includendo il prezzo "Compra Subito", spese di spedizione e
risparmio stimato. Aggiunta una nuova sezione "Info Prodotto"
nella UI per visualizzare i dettagli estratti e i calcoli.

- **AuctionMonitorControl.xaml**: Aggiunta sezione fissa per
  mostrare informazioni prodotto e calcolo valore.
- **AuctionMonitorControl.xaml.cs**: Gestiti eventi per il
  caricamento e aggiornamento delle informazioni prodotto.
- **MainWindow**: Integrati handler per il calcolo e refresh
  delle informazioni prodotto.
- **AuctionInfo.cs**: Aggiunte proprietà per gestire prezzo
  "Compra Subito", spese di spedizione e limiti di vincita.
- **ProductValueCalculator.cs**: Nuova utility per calcolare
  il valore del prodotto e parsare informazioni dall'HTML.
- **AuctionViewModel.cs**: Binding per visualizzare risparmio,
  costo totale e convenienza nella UI.
- **Documentazione**: Aggiornata con dettagli sull'algoritmo
  di calcolo e layout UI.

Fix:
- Risolto problema di encoding UTF-8 per emoji nella UI.
- Migliorato parsing HTML per prezzi e limiti di vincita.

TODO:
- Testare parsing su più aste e gestire edge cases.
- Implementare caricamento automatico delle informazioni.
2025-11-21 16:55:21 +01:00
f124f2e4e8 Riorganizzazione pulsanti e miglioramenti usabilità
- Riorganizzati i pulsanti azione asta in layout 2x2:
  * Aggiunti pulsanti per Browser Interno, Browser Esterno,
    Copia URL ed Esporta (funzionalità in sviluppo).
  * Migliorati stile, tooltip e colori per maggiore chiarezza.
- Aggiunti nuovi RoutedEvent e gestori per le azioni.
- Migliorata gestione errori per "Copia URL":
  * Controllo asta selezionata e retry per clipboard occupato.
- Rimosse emoji non visualizzate per compatibilità universale.
- Arricchiti i log con messaggi dettagliati per ogni azione.
- Creata documentazione dettagliata delle modifiche e test.
- Migliorata compatibilità e robustezza generale.
2025-11-21 10:30:49 +01:00
570c2e53d6 Aggiunti limiti configurabili per i log
- Introdotta una nuova sezione "Limiti Log" nell'interfaccia utente per configurare:
  - Numero massimo di righe di log per asta (default: 500).
  - Numero massimo di righe di log globale (default: 1000).
- Aggiunte proprietà in `SettingsManager` per salvare/caricare i limiti.
- Applicati i limiti al log globale e ai log delle aste:
  - Log globale: rimozione automatica dei paragrafi più vecchi.
  - Log per asta: ottimizzato `AddLog` con `RemoveRange` per migliorare le performance.
- Documentazione dettagliata in `FEATURE_CONFIGURABLE_LOG_LIMITS.md` e `FEATURE_LOG_MAX_LINES.md`.
- Migliorata la gestione della memoria, riducendo il rischio di rallentamenti o crash.
- Test e checklist definiti per verificare il corretto funzionamento.
2025-11-21 09:41:08 +01:00
4bfcf147b4 Miglioramenti UI e gestione puntate server
- Implementato focus automatico sulla riga successiva dopo la
  cancellazione di un'asta, con scrolling e reset focus.
- Utilizzo dei dati ufficiali del server per il conteggio
  delle puntate residue e usate su asta, con fallback manuale.
- Corretto il parsing dei campi della risposta server
  (campo 2: puntate residue, campo 5: puntate usate).
- Risolto il mancato aggiornamento immediato della UI
  (colonna "Clicks" e banner "Puntate residue").
- Aggiunto logging dettagliato per il parsing della risposta
  server e il debugging di eventuali problemi.
- Documentate le modifiche in file dedicati con scenari di
  test e istruzioni per il troubleshooting.
2025-11-20 23:01:53 +01:00
c37b5b9f1e Aggiorna soluzione per Visual Studio 18 e rimuove Template
La soluzione `AutoBidder.sln` è stata aggiornata per supportare
Visual Studio 18 (18.0.11217.181), sostituendo la versione
precedente (17.14.36511.14).

Il progetto "Template" (`Template.wapproj`) è stato rimosso
insieme a tutte le configurazioni di build e deploy associate
per le piattaforme Any CPU, ARM, ARM64, x64 e x86 in modalità
Debug e Release.

Le configurazioni di build per il progetto "AutoBidder" sono
state mantenute, ma alcune configurazioni di Release sono state
modificate per utilizzare `Any CPU` invece di configurazioni
specifiche per piattaforma.
2025-11-20 14:48:21 +01:00
Alberto Balbo
29a567bb1d Miglioramenti UX e gestione impostazioni predefinite
* Rimosso il pulsante "Vai" e reso il campo URL non editabile.
* Introdotta persistenza delle impostazioni predefinite (es. anticipo).
* Aggiunto metodo `LoadDefaultSettings()` per caricare i defaults.
* Logging dettagliato per salvataggio e applicazione impostazioni.
* Ottimizzata gestione aste con valori predefiniti da configurazione.
* Fix per evitare puntate inutili quando l'utente è già vincitore.
* Logging migliorato per strategia di puntata e decisioni di skip.
* Aggiornata documentazione con dettagli sui fix implementati.
* Aggiornato `CHANGELOG.md` con le nuove funzionalità e correzioni.
2025-11-20 14:11:37 +01:00
Alberto Balbo
f017ec0364 Aggiornamento alla versione 4.0.0
* Aggiunto `BooleanToOpacityConverter` per gestire opacità dinamica.
* Introdotto nuovo sistema di timing con `BidBeforeDeadlineMs`.
* Aggiunta opzione `CheckAuctionOpenBeforeBid` per maggiore sicurezza.
* Implementato polling adattivo (10ms-1000ms) e cooldown di 800ms.
* Migliorata gestione pulsanti globali con supporto `AUTO-START`/`AUTO-STOP`.
* Fix per il tasto `Canc` e focus automatico sul `DataGrid`.
* Fix per avvio singola asta senza necessità di "Avvia Tutti".
* Aggiornati formati CSV/JSON/XML con nuovi campi.
* Migliorata gestione cookie con endpoint unico `buy_bids.php`.
* Miglioramenti UI/UX: tooltip, formattazione prezzi, feedback visivo.
* Aggiornata documentazione e changelog per la versione 4.0.0.
2025-11-19 18:43:40 +01:00
Alberto Balbo
6036896f7d Refactoring e nuove funzionalità per AutoBidder v4.0
* Aggiornamento alla versione 4.0.0
* Refactoring architetturale: introdotte partial classes e UserControls modulari per migliorare manutenibilità e leggibilità.
* Aggiunti nuovi UserControls: `AuctionMonitorControl`, `BrowserControl`, `SettingsControl`, `StatisticsControl`.
* Introdotto supporto per WebView2 per il browser integrato.
* Migliorata gestione delle aste: aggiunta/rimozione tramite URL o ID, configurazione predefinita.
* Nuove funzionalità di esportazione: supporto CSV, JSON, XML con opzioni configurabili.
* Logging avanzato: codifica colore per severità e auto-scroll.
* Tema scuro moderno e miglioramenti UI/UX: sidebar di navigazione, griglie virtualizzate, icone emoji.
* Persistenza dati: salvataggio automatico di aste e impostazioni in file JSON.
* Documentazione aggiornata: `README.md`, `CHANGELOG.md` e nuovi file di supporto.
* Miglioramenti alla sicurezza: cookie di sessione salvati in modo sicuro con DPAPI.
* Preparazione per future estensioni: placeholder per funzionalità avanzate e struttura modulare.
2025-11-17 16:01:22 +01:00
Alberto Balbo
8717a3b6ef Aggiornamento alla versione 4.0.0
- Aggiunta dipendenza per WebView2 per integrare un browser.
- Introdotto layout a schede (TabControl) per organizzare le funzionalità.
- Aggiunto browser WebView2 per navigazione e aggiunta aste.
- Implementata gestione delle impostazioni di esportazione (CSV, JSON, XML).
- Aggiunta funzionalità di caricamento e analisi delle aste chiuse.
- Introdotta gestione dei cookie di sessione tramite la scheda "Impostazioni".
- Creato controllo personalizzato `SimpleToolbar` per layout modulare.
- Migliorata gestione dello stato utente e fallback per dati mancanti.
- Rimossi stili e animazioni obsolete per semplificare il codice.
- Salvate le impostazioni utente in un file JSON locale.
- Correzioni di bug e miglioramenti di leggibilità del codice.
2025-11-04 23:05:49 +01:00
Alberto Balbo
967005b96a Supporto per aste chiuse e miglioramenti UI
- Aggiornamento alla versione Microsoft.EntityFrameworkCore.Sqlite 8.0.0.
- Aggiornamento alla versione Microsoft.Windows.SDK.BuildTools 10.0.26100.6584.
- Migliorata l'interfaccia per l'inserimento di più URL/ID di aste.
- Aggiunti pulsanti per "Aste Chiuse" e "Esporta" in MainWindow.
- Creata finestra "Aste Chiuse" per visualizzare e gestire aste chiuse.
- Implementato scraper per estrarre dati da aste chiuse.
- Aggiunto supporto per esportazione dati in CSV, JSON e XML.
- Introdotto contesto Entity Framework per statistiche delle aste.
- Aggiunto servizio per calcolo e gestione delle statistiche.
- Gestite preferenze di esportazione con salvataggio in file JSON.
2025-11-03 14:24:19 +01:00
Alberto Balbo
59d7e0c41f Aggiornamento alla versione 3.0.0
- Aggiornato il titolo e l'introduzione per riflettere le funzionalità.
- Aggiunti badge per la versione (3.0) e .NET (8.0).
- Riorganizzato il sommario e rinominato in "Indice".
- Espansa la sezione "Caratteristiche principali" con nuovi dettagli.
- Riformattati i requisiti di sistema per maggiore chiarezza.
- Riscritta la guida "Installazione e avvio" con istruzioni dettagliate.
- Aggiunta la sezione "Configurazione della sessione (cookie)".
- Ampliata la gestione delle aste con dettagli su operazioni e griglia.
- Inserite strategie consigliate per diversi scenari d'uso.
- Arricchita la sezione tecnica con dettagli su polling e puntate HTTP.
- Aggiunta descrizione su persistenza e diagnostica (es. esportazione CSV).
- Espansa la sezione FAQ con nuovi scenari di risoluzione problemi.
- Introdotte note su sicurezza e responsabilità nell'uso dell'app.
- Semplificata la sezione "Supporto" rimuovendo riferimenti privati.
- Aggiunte note tecniche per sviluppatori sui file principali del progetto.
- Rimossa la sezione "Changelog sintetico" e integrati i dettagli altrove.
- Riformattata la sezione "Licenza" per maggiore chiarezza.
2025-10-30 13:02:13 +01:00
Alberto Balbo
daf9ea31fc Miglioramenti logica e gestione attacco finale
- Aggiunta proprietà `FinalAttackThresholdSec` (0.8s) in `AuctionInfo.cs`.
- Implementata strategia di "quick re-poll" in `AuctionMonitor.cs` per confermare stato critico prima dell'attacco finale.
- Migliorata gestione delle eccezioni in `BidooApiClient.cs` con log dettagliati e tentativi alternativi.
- Registrazione del numero di offerte rimanenti dopo successo in `BidooApiClient.cs`.
- Ottimizzati messaggi di log per maggiore chiarezza e trasparenza.
- Rimossa logica obsoleta e aggiunti ritardi minimi tra tentativi di polling rapido.
2025-10-29 17:12:46 +01:00
Alberto Balbo
cb30e1fb08 Ottimizzazioni e introduzione protocollo final attack
- Rimosso binding di `MaxClicks` in `MainWindow.xaml` e aggiunto evento `TextChanged`.
- Migliorata leggibilità del codice in `MainWindow.xaml.cs` con rientri e ritorni a capo.
- Evitata duplicazione dei log per aste aggiunte in `MainWindow.xaml.cs`.
- Migliorata gestione della validità del cookie con fallback su scraping HTML.
- Aggiunta proprietà `IsAttackInProgress` in `AuctionInfo.cs` per gestire lo stato di attacco finale.
- Introdotto protocollo di "final attack" in `AuctionMonitor.cs` per puntate critiche sotto 0,5s.
- Migliorata gestione dei log e comportamento delle puntate normali in `AuctionMonitor.cs`.
- Aggiunto metodo `PlaceBidFinalAsync` in `BidooApiClient.cs` per puntate ottimizzate.
- Ridotti log ridondanti e migliorata gestione degli errori.
2025-10-28 23:27:53 +01:00
Alberto Balbo
717dc44b3b Aggiornamento alla versione 3.0.0
- Rimosse funzionalità legacy legate a WebView2.
- Introdotto uno stile globale per i pulsanti.
- Semplificata l'interfaccia con gestione tramite griglia unica.
- Aggiunti comandi per avviare, mettere in pausa e fermare aste.
- Introdotta gestione manuale dei cookie tramite dialog.
- Aggiunti dialog per configurare sessione e aggiungere aste.
- Migliorata la persistenza con salvataggio sicuro (DPAPI).
- Rifattorizzate statistiche per utilizzare `BidHistory` e `BidderStats`.
- Ottimizzato il polling per ridurre il carico di sistema.
- Aggiornata esportazione CSV con dati più dettagliati.
- Introdotti nuovi modelli dati per utente e banner aste.
- Rimossi file di test manuale e codice obsoleto.
- Aggiornata documentazione per riflettere le modifiche.
- Aggiunta nuova icona dell'applicazione.
- Migliorata la sicurezza eliminando il salvataggio in chiaro dei cookie.
2025-10-28 12:45:08 +01:00
Alberto Balbo
fef7b909e7 Aggiornamento alla versione 2.10.0
- Aggiornato il titolo e aggiunta una descrizione dettagliata.
- Rimosso l'indice originale e aggiunto un sommario sintetico.
- Introdotta una nuova sezione "Caratteristiche principali".
- Rivisti e semplificati i requisiti di sistema.
- Riorganizzata la sezione "Installazione e avvio" con istruzioni chiare.
- Aggiunta una guida rapida per il primo utilizzo.
- Dettagliate le modalità operative: Asta Singola e Multi-Asta.
- Inserite strategie consigliate per diversi scenari d'uso.
- Aggiunta una sezione tecnica su polling adattivo e click HTTP.
- Descritte persistenza dei dati e gestione file locali.
- Riviste e chiarite le impostazioni principali e per-asta.
- Aggiunti dettagli sull'interfaccia utente e i controlli.
- Introdotta una sezione per diagnostica ed esportazione.
- Aggiunte FAQ e risoluzione dei problemi comuni.
- Inserito un disclaimer sui rischi e responsabilità d'uso.
- Creato un changelog sintetico con focus sulle novità della v2.10.
- Fornite informazioni su supporto, contributi e note tecniche.
- Ribadita la licenza privata del progetto.
2025-10-24 16:52:24 +02:00
Alberto Balbo
139a9d62b7 Aggiornamento alla versione 4.0.0
- Aggiunta proprietà `MaxClicks` per limitare le puntate per asta.
- Migliorata gestione dei log con livelli di severità e colori.
- Sostituzione di `TextBox` con `RichTextBox` per log avanzati.
- Aggiunto pulsante per cancellare il log globale.
- Migliorata gestione dei pulsanti globali (Avvia, Pausa, Ferma).
- Ottimizzato il monitoraggio per aste in pausa e polling ridotto.
- Aggiunto controllo per mettere in pausa aste al raggiungimento di `MaxClicks`.
- Aggiunti nuovi stili per pulsanti e miglioramenti visivi in UI.
- Aggiunto convertitore `StartButtonOpacityConverter`.
- Aggiunta icona dell'applicazione (`app.ico`) come risorsa WPF.
2025-10-24 16:29:08 +02:00
Alberto Balbo
4e16f50aeb Aggiunta infrastruttura avanzata per gestione aste
- Introdotta la classe `BidooApiClient` per interagire con le API Bidoo.
- Aggiunto `SessionManager` per la gestione sicura delle sessioni.
- Creato `TestBidooApi` per test manuali delle API.
- Implementato `CsvExporter` per esportare dati e statistiche in CSV.
- Aggiunto `PersistenceManager` per salvare e caricare aste in JSON.
- Introdotto `AuctionViewModel` per supportare il pattern MVVM.
- Migliorata l'interfaccia utente con layout moderno e stili dinamici.
- Aggiornata la documentazione in `README.md` per riflettere le nuove funzionalità.
- Aggiunte classi per rappresentare informazioni, stato e storico delle aste.
- Ottimizzate le richieste HTTP per simulare un browser reale.
2025-10-23 23:10:46 +02:00
Alberto Balbo
db1d99d424 Aggiornamento alla versione 2.7.0
- Riorganizzato layout verticale per "Utenti" e "Log" con GridSplitter verticale e altezza minima garantita (80px).
- Resi simmetrici i margini tra "Utenti" e "Log" (8px sopra e sotto).
- Implementata navigazione automatica ai Preferiti all'avvio in modalità Multi-Asta, con controllo URL per evitare ricaricamenti inutili.
- Aggiunta griglia utenti per-asta con numero di puntate per utente, ordinata in modo decrescente e affiancata al log con GridSplitter.
- Aggiornata documentazione con riferimenti dettagliati alle modifiche (es. `v2.7_VERTICAL_LAYOUT.md`, `v2.6_UI_POLISH.md`).
2025-10-20 12:04:06 +02:00
Alberto Balbo
114697a1b2 Aggiornamento alla versione 2.7.0
- Riorganizzata la sezione "Utenti" e "Log" in layout verticale.
- Sostituiti `ColumnDefinitions` con `RowDefinitions` in XAML.
- Aggiunto `MinHeight=80` per evitare il collasso delle sezioni.
- Modificato il `GridSplitter` per supportare il resize verticale.
- Migliorata l'usabilità con margini simmetrici e layout coerente.
- Testata la funzionalità di ridimensionamento e aggiornamento dinamico.
2025-10-15 21:59:28 +02:00
Alberto Balbo
995732f379 Aggiornamento alla versione 2.6.0
- Introdotta la modalità Multi-Asta per monitorare più aste contemporaneamente.
- Aggiunta griglia Multi-Asta con timer, prezzo e dettagli per asta.
- Implementata gestione per-asta con impostazioni individuali e log dedicati.
- Aggiunti pulsanti separati per pausa/riprendi con feedback visivo.
- Introdotta griglia utenti per-asta con aggiornamento real-time e ordinamento.
- Resi simmetrici i margini e migliorata la leggibilità dell'interfaccia.
- Implementata navigazione automatica ai Preferiti all'avvio in modalità Multi-Asta.
- Ottimizzato il layout con GridSplitter ridimensionabile tra griglia e log.
- Rimosso il pulsante di pausa globale e semplificata la gestione UI.
- Evidenziate le aste in pausa e le puntate dell'utente con colori distintivi.
2025-10-14 21:30:01 +02:00
Alberto Balbo
28ef09d91f Ottimizzazioni UI e performance click handler
- Rimosse righe inutilizzate e semplificato layout in `MainWindow.xaml`.
- Aggiunti pulsanti di navigazione accanto alla barra indirizzi.
- Convertite operazioni UI in asincrone con `Dispatcher.BeginInvoke`.
- Introdotto aggiornamento griglia bidder ogni 2 secondi per ridurre lag.
- Migliorata gestione log con `AppendText` e controllo dimensione ottimizzato.
- Ridotto polling dinamico per timer bassi (minimo 20ms).
- Ottimizzato script di click con cache bottone e timeout ridotto (500ms).
- Implementato multi-click parallelo con delay minimo (20ms).
- Parsing JSON e lettura impostazioni resi più efficienti.
- Rimosso codice obsoleto e semplificata gestione eventi.
2025-10-14 12:26:51 +02:00
Alberto Balbo
b12b57be81 Miglioramenti al tracciamento e riorganizzazione progetto
- Rimosso codice obsoleto per il tracciamento dei bidder.
- Introdotto tracciamento in tempo reale del bidder corrente.
- Aggiunta variabile `lastKnownBidder` per monitorare cambiamenti.
- Migliorata gestione dei reset del timer e registrazione bidder.
- Aggiunta funzione `StopAutomation` per arresto centralizzato.
- Aggiornati log per riflettere il nuovo approccio in tempo reale.
- Rinominato progetto da `Mimante` a `AutoBidder`.
- Creato nuovo file `AutoBidder.csproj` e aggiornati riferimenti.
- Rimossi script e funzioni non più utilizzati.
- Migliorata leggibilità e aggiunti controlli sui dati.
2025-10-07 22:30:55 +02:00
Alberto Balbo
8bc123ff85 Aggiornamento alla versione 1.0.2.0
- Aggiornata la versione dell'applicazione nel file `Package.appxmanifest` da `1.0.1.0` a `1.0.2.0`.
2025-10-07 11:32:11 +02:00
Alberto Balbo
9b38adfd5f Miglioramenti reattività e gestione aste
- Rimosso codice obsoleto e migliorata leggibilità.
- Aggiornati log con messaggi più chiari e leggibili.
- Ottimizzato script JS per monitoraggio ultra-reattivo.
- Introdotto aggiornamento dinamico lista partecipanti (bidders).
- Migliorata gestione timer con polling adattivo.
- Ridotti ritardi e timeout per maggiore reattività.
- Aggiornata logica di clic con supporto a timer precisi.
- Migliorata gestione errori e casi limite.
- Reso thread-safe l'aggiornamento dell'interfaccia utente.
- Ottimizzata gestione reset e decisioni di clic.
- Introdotto triplo clic rapido per massima affidabilità.
- Aggiunti log per strategie e cronologia puntate.
- Migliorate prestazioni generali e ridotti tempi di risposta.
2025-10-07 11:26:37 +02:00
Alberto Balbo
6558ac6512 Miglioramenti UI/UX e ottimizzazioni prestazionali
- Aggiunti controlli per dimensioni minime della finestra.
- Introdotta barra degli indirizzi con pulsante di navigazione.
- Validazione URL per consentire solo domini Bidoo.
- Migliorata gestione log con limite di 500 righe e pulsante di pulizia.
- Ottimizzati script JavaScript per prestazioni e affidabilità.
- Ridotti tempi di attesa per maggiore reattività.
- Aggiunto supporto per multi-click con logica ottimizzata.
- Riorganizzate sezioni "Settings", "Log" e "Bidders" con pulsanti dedicati.
- Migliorata gestione degli errori e aggiunti messaggi di avviso.
- Rimossi script obsoleti e migliorata gestione delle eccezioni.
- Aggiunti stili personalizzati per pulsanti e caselle di testo.
2025-10-07 09:49:05 +02:00
Alberto Balbo
1a5611cc60 Miglioramenti UI e logica automazione, versione 1.0.1.0
- Aggiornamento alla versione 1.0.1.0.
- Migliorata la gestione del layout in `MainWindow.xaml`.
- Aggiunti controlli avanzati per timer e click multipli.
- Introdotte strategie multiple per click affidabili.
- Migliorata gestione di errori e timeout con log dettagliati.
- Aggiunto supporto per il recupero del nome utente dalla pagina.
- Aggiornati i metadati dell'app con nuovo nome e autore.
- Abilitata la firma del pacchetto e configurazioni di build.
- Ottimizzazioni generali per stabilità e responsività.
2025-10-02 09:34:35 +02:00
Alberto Balbo
c910117171 Miglioramenti UI e logica automazione aste
- Aggiunto stile personalizzato al `DataGrid` in `MainWindow.xaml`.
- Modificato il dizionario `_bidders` per tracciare ultima puntata.
- Aggiunta colonna "Ultima puntata" nella griglia `BiddersGrid`.
- Migliorata gestione degli errori negli script JavaScript.
- Implementata logica per rilevare pause programmate nelle aste.
- Migliorata gestione dei limiti di prezzo (minimo/massimo).
- Ottimizzata gestione dei click e aggiornamento degli offerenti.
- Rimossi metodi obsoleti e migliorata gestione delle eccezioni.
- Aggiunti log dettagliati per stato e operazioni dell'automazione.
2025-10-01 09:03:22 +02:00
Alberto Balbo
ded7d3882b Aggiunto pulsante "Pausa" e progetto Template
- Aggiunto pulsante "Pausa" con stile dedicato e logica.
- Riorganizzata la griglia in `MainWindow.xaml` per nuovi elementi.
- Aggiunta griglia per visualizzare gli offerenti (`BiddersGrid`).
- Introdotti limiti di prezzo e gestione dei reset nel ciclo.
- Aggiunto progetto `Template` per il packaging dell'app.
- Aggiunti file di risorse grafiche per loghi e icone.
- Aggiornato `Mimante.sln` per supportare nuove piattaforme.
- Ottimizzazioni e correzioni di stabilità.
2025-09-29 18:02:44 +02:00
459 changed files with 621561 additions and 752 deletions

87
Mimante/.dockerignore Normal file
View File

@@ -0,0 +1,87 @@
**Dockerignore file**
# Build artifacts
**/bin/
**/obj/
**/out/
**/publish/
# User-specific files
*.user
*.suo
*.userosscache
*.sln.docstates
# IDE files
.vs/
.vscode/
.idea/
*.swp
*.swo
*~
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# NuGet packages
*.nupkg
*.snupkg
**/packages/*
!**/packages/build/
# Test results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# Data and databases (exclude from image)
**/data/*.db
**/data/*.db-shm
**/data/*.db-wal
**/data/backups/
**/data/logs/
# Git files
.git
.gitignore
.gitattributes
.github/
# CI/CD files
.gitea/
# Documentation
*.md
!README.md
# Docker files
Dockerfile*
docker-compose*
.dockerignore
# Environment files
.env
.env.*
# Temporary files
*.tmp
*.temp
*.cache
*.bak
*.log
# OS files
.DS_Store
Thumbs.db

92
Mimante/.env.example Normal file
View File

@@ -0,0 +1,92 @@
# AutoBidder Environment Variables
# Copia questo file in .env e configura i valori
# === ASP.NET Core Configuration ===
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://+:8080
# === AUTENTICAZIONE APPLICAZIONE (SICUREZZA) ===
# Username amministratore
ADMIN_USERNAME=admin
# Password amministratore (OBBLIGATORIO in produzione!)
# REQUISITI: min 12 caratteri, maiuscole, minuscole, numeri, simboli
# Esempio: Admin@SecurePass2024!
ADMIN_PASSWORD=
# === NOTA: SESSIONE BIDOO ===
# Non servono credenziali Bidoo!
# Il cookie di sessione Bidoo viene configurato manualmente
# dall'interfaccia web in Settings ? Sessione Bidoo
# === PostgreSQL Database (Statistiche) ===
# Username PostgreSQL
POSTGRES_USER=autobidder
# Password PostgreSQL (CAMBIA IN PRODUZIONE!)
POSTGRES_PASSWORD=autobidder_password
# Database name
POSTGRES_DB=autobidder_stats
# Usa PostgreSQL per statistiche (true/false)
USE_POSTGRES=true
# === Application Settings ===
# Logging level (Debug, Information, Warning, Error)
LOG_LEVEL=Information
# Porta applicazione (default: 8080 container, mappata su host)
APP_PORT=5000
# === Database Configuration ===
# Path database SQLite locale (default: /app/data/autobidder.db in container)
# DATABASE_PATH=/app/data/autobidder.db
# Giorni di retention backup database (default: 30)
DB_BACKUP_RETENTION_DAYS=30
# Auto-ottimizzazione database (VACUUM automatico)
DB_AUTO_OPTIMIZE=true
# === Logging ===
# Livello log: Trace, Debug, Information, Warning, Error, Critical
LOG_LEVEL=Information
# Livello log Microsoft: Trace, Debug, Information, Warning, Error, Critical
LOG_LEVEL_MICROSOFT=Warning
# Livello log Entity Framework: Trace, Debug, Information, Warning, Error, Critical
LOG_LEVEL_EF=Warning
# === Application Settings ===
# Numero massimo connessioni concorrenti HTTP
# MAX_HTTP_CONNECTIONS=10
# Timeout richieste HTTP (secondi)
# HTTP_TIMEOUT=30
# === Backup Configuration ===
# Directory backup (default: /app/data/backups)
# BACKUP_DIR=/app/data/backups
# Numero giorni backup da mantenere
# BACKUP_RETENTION_DAYS=30
# === Security ===
# Chiave segreta per DataProtection (genera random se non specificato)
# DATA_PROTECTION_KEY=your-random-key-here
# === Monitoring ===
# Abilita metriche Prometheus (true/false)
# ENABLE_METRICS=false
# Porta metriche (se ENABLE_METRICS=true)
# METRICS_PORT=9090
# === Advanced ===
# Numero thread worker per polling aste
# AUCTION_WORKER_THREADS=4
# Intervallo pulizia cache (minuti)
# CACHE_CLEANUP_INTERVAL=60

View File

@@ -0,0 +1,71 @@
name: Database Backup
on:
schedule:
# Esegui backup ogni giorno alle 2:00 AM UTC
- cron: '0 2 * * *'
workflow_dispatch: # Permette trigger manuale
jobs:
backup-database:
runs-on: ubuntu-latest
steps:
- name: Execute remote backup
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
echo "??? Starting database backup..."
cd /opt/autobidder
# Directory backup
BACKUP_DIR="./data/backups"
mkdir -p $BACKUP_DIR
# Timestamp
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Backup database
if [ -f ./data/autobidder.db ]; then
echo "?? Backing up autobidder.db..."
cp ./data/autobidder.db $BACKUP_DIR/autobidder_backup_$TIMESTAMP.db
# Verifica backup
if [ -f $BACKUP_DIR/autobidder_backup_$TIMESTAMP.db ]; then
SIZE=$(du -h $BACKUP_DIR/autobidder_backup_$TIMESTAMP.db | cut -f1)
echo "? Backup created successfully: $SIZE"
else
echo "? Backup failed!"
exit 1
fi
else
echo "?? Database file not found!"
exit 1
fi
# Cleanup backup vecchi (mantieni ultimi 30 giorni)
echo "?? Cleaning up old backups..."
find $BACKUP_DIR -name "autobidder_backup_*.db" -mtime +30 -delete
# Conta backup rimanenti
BACKUP_COUNT=$(find $BACKUP_DIR -name "autobidder_backup_*.db" | wc -l)
echo "?? Total backups: $BACKUP_COUNT"
# Mostra dimensione totale backup
TOTAL_SIZE=$(du -sh $BACKUP_DIR | cut -f1)
echo "?? Total backup size: $TOTAL_SIZE"
echo "?? Backup completed successfully!"
- name: Backup summary
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "? Database backup SUCCESSFUL"
else
echo "? Database backup FAILED"
fi

View File

@@ -0,0 +1,222 @@
name: Build and Deploy AutoBidder
on:
push:
branches:
- main
- docker
pull_request:
branches:
- main
workflow_dispatch: # Permette trigger manuale
env:
DOTNET_VERSION: '8.0.x'
REGISTRY: ${{ secrets.GITEA_REGISTRY }}
jobs:
# Job 1: Build e Test .NET
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch completo per analisi
- name: Set up .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Cache NuGet packages
uses: actions/cache@v3
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Run tests
run: dotnet test --no-restore --verbosity normal --logger "console;verbosity=detailed"
continue-on-error: true
- name: Publish artifacts
run: dotnet publish --configuration Release --no-build --output ./publish
- name: Upload publish artifacts
uses: actions/upload-artifact@v3
with:
name: publish-artifacts
path: ./publish
retention-days: 7
# Job 2: Build e Push Docker Image
build-docker:
needs: build-and-test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to Gitea Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.GITEA_USERNAME }}
password: ${{ secrets.GITEA_PASSWORD }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/autobidder
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=,format=short
type=raw,value=latest,enable={{is_default_branch}}
labels: |
org.opencontainers.image.title=AutoBidder
org.opencontainers.image.description=Sistema automatizzato gestione aste Blazor
org.opencontainers.image.vendor=Alby96
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/autobidder:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/autobidder:buildcache,mode=max
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}
VERSION=${{ steps.meta.outputs.version }}
# Job 3: Security Scan (opzionale)
security-scan:
needs: build-docker
runs-on: ubuntu-latest
if: github.event_name == 'push'
continue-on-error: true
steps:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/autobidder:latest
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'
# Job 4: Deploy su Server
deploy:
needs: build-docker
runs-on: ubuntu-latest
if: (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/docker') && github.event_name == 'push'
environment:
name: production
url: https://${{ secrets.DEPLOY_HOST }}:5001
steps:
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
echo "?? Starting deployment..."
# Vai alla directory deploy
cd /opt/autobidder || exit 1
# Carica variabili ambiente
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | xargs)
fi
# Login al registry
echo "$GITEA_PASSWORD" | docker login $GITEA_REGISTRY -u $GITEA_USERNAME --password-stdin
# Backup database prima del deploy
echo "?? Creating database backup..."
if [ -f data/autobidder.db ]; then
mkdir -p data/backups
cp data/autobidder.db data/backups/autobidder_predeploy_$(date +%Y%m%d_%H%M%S).db
fi
# Pull nuova immagine
echo "?? Pulling latest image..."
docker-compose pull
# Stop vecchi container
echo "?? Stopping old containers..."
docker-compose down
# Start nuovi container
echo "?? Starting new containers..."
docker-compose up -d
# Attendi healthcheck
echo "?? Waiting for healthcheck..."
sleep 15
# Verifica status
echo "?? Container status:"
docker-compose ps
# Verifica healthcheck
if docker inspect --format='{{.State.Health.Status}}' autobidder | grep -q "healthy"; then
echo "? Deploy successful! Container is healthy."
else
echo "?? Warning: Container may not be healthy yet. Check logs."
fi
# Mostra ultimi log
echo "?? Recent logs:"
docker-compose logs --tail=30
echo "?? Deployment completed!"
- name: Notify deployment status
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "? Deployment SUCCESSFUL"
else
echo "? Deployment FAILED"
fi
# Job 5: Cleanup (rimuove vecchie immagini dal registry)
cleanup:
needs: deploy
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- name: Cleanup old images
run: |
echo "?? Cleanup task completed (manual cleanup required on Gitea)"

View File

@@ -0,0 +1,70 @@
name: Health Check Monitor
on:
schedule:
# Verifica ogni ora
- cron: '0 * * * *'
workflow_dispatch: # Permette trigger manuale
jobs:
health-check:
runs-on: ubuntu-latest
steps:
- name: Check application health
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
echo "?? Health Check Starting..."
# Verifica container running
if ! docker ps | grep -q "autobidder"; then
echo "? Container NOT running!"
exit 1
fi
# Verifica Docker healthcheck
HEALTH_STATUS=$(docker inspect --format='{{.State.Health.Status}}' autobidder 2>/dev/null || echo "unknown")
echo "Docker Health: $HEALTH_STATUS"
if [ "$HEALTH_STATUS" != "healthy" ]; then
echo "?? Container not healthy!"
echo "Recent logs:"
docker logs autobidder --tail=50
exit 1
fi
# Test HTTP endpoint
if curl -f -s http://localhost:5000/health > /dev/null; then
echo "? HTTP endpoint: OK"
else
echo "? HTTP endpoint: FAILED"
exit 1
fi
# Verifica database
cd /opt/autobidder
if [ -f ./data/autobidder.db ]; then
DB_SIZE=$(du -h ./data/autobidder.db | cut -f1)
echo "?? Database size: $DB_SIZE"
else
echo "?? Database file not found!"
fi
# Verifica risorse container
echo "?? Container resources:"
docker stats autobidder --no-stream --format " CPU: {{.CPUPerc}}\n Memory: {{.MemUsage}}"
echo "? All health checks passed!"
- name: Health check summary
if: always()
run: |
if [ "${{ job.status }}" == "success" ]; then
echo "? Health check PASSED"
else
echo "? Health check FAILED - Check server status!"
fi

97
Mimante/.github/workflows/ci-cd.yml vendored Normal file
View File

@@ -0,0 +1,97 @@
name: AutoBidder CI/CD
on:
push:
branches: [ main, docker ]
pull_request:
branches: [ main ]
env:
REGISTRY: 192.168.30.23/Alby96
IMAGE_NAME: autobidder
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --no-restore --verbosity normal
continue-on-error: true
- name: Publish
run: dotnet publish --configuration Release --no-build --output ./publish
docker-build-push:
needs: build-and-test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Gitea Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.GITEA_REGISTRY }}
username: ${{ secrets.GITEA_USERNAME }}
password: ${{ secrets.GITEA_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=sha
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
deploy:
needs: docker-build-push
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/docker' || github.ref == 'refs/heads/main'
steps:
- name: Deploy to server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
cd /opt/autobidder
source .env
echo "$GITEA_PASSWORD" | docker login $GITEA_REGISTRY -u $GITEA_USERNAME --password-stdin
docker-compose pull
docker-compose down
docker-compose up -d
sleep 10
docker-compose ps
docker-compose logs --tail=30

456
Mimante/.gitignore vendored Normal file
View File

@@ -0,0 +1,456 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
.idea/
# ============================================
# AutoBidder Specific
# ============================================
# Database files (local development)
*.db
*.db-shm
*.db-wal
data/*.db
data/*.db-*
# Backups (keep structure, ignore files)
data/backups/*.db
data/backups/*.json
# Logs
logs/*.log
logs/*.txt
*.log
# Environment files with secrets
.env
.env.local
.env.*.local
# Certificates and keys
*.pfx
*.key
*.crt
*.pem
cert/*
!cert/.gitkeep
# Docker volumes data
test-data/
# Published artifacts
publish/
PublishProfiles/
# Temp directories
temp/
tmp/
# OS files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Keep important empty directories
!data/.gitkeep
!data/backups/.gitkeep
!logs/.gitkeep
!cert/.gitkeep

36
Mimante/App.razor Normal file
View File

@@ -0,0 +1,36 @@
<CascadingAuthenticationState>
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@if (context.User.Identity?.IsAuthenticated != true)
{
<RedirectToLogin />
}
else
{
<p>Non sei autorizzato ad accedere a questa risorsa.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Non trovato</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<div style="padding: 2rem; text-align: center;">
<svg style="width: 64px; height: 64px; margin-bottom: 1rem; opacity: 0.5;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
<h1 style="font-size: 1.5rem; margin-bottom: 0.5rem;">Pagina non trovata</h1>
<p style="color: var(--text-muted);">Spiacenti, non c'è nulla a questo indirizzo.</p>
<a href="/" style="color: var(--primary-color); text-decoration: none; margin-top: 1rem; display: inline-block;">
?? Torna alla Home
</a>
</div>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState>

View File

@@ -4,6 +4,26 @@
xmlns:local="clr-namespace:Mimante"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<!-- Stile pulsanti globale -->
<Style x:Key="SmallButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="White" />
<Setter Property="FontWeight" Value="SemiBold" />
<Setter Property="FontSize" Value="12" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="12"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -1,4 +1,4 @@
using System.Configuration;
using System.Configuration;
using System.Data;
using System.Windows;

157
Mimante/AutoBidder.csproj Normal file
View File

@@ -0,0 +1,157 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>AutoBidder</AssemblyName>
<RootNamespace>AutoBidder</RootNamespace>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
<DockerfileFile>Dockerfile</DockerfileFile>
<!-- Versioning per Docker & Gitea Registry -->
<!-- v1.3.0: Database management + bug fixes (duplicates, race conditions, warnings) -->
<Version>1.3.0</Version>
<AssemblyVersion>1.3.0.0</AssemblyVersion>
<FileVersion>1.3.0.0</FileVersion>
<InformationalVersion>1.3.0</InformationalVersion>
<!-- Metadata immagine Docker -->
<ContainerImageName>autobidder</ContainerImageName>
<ContainerImageTag>$(Version)</ContainerImageTag>
<!-- CORRETTO: Convenzione Gitea {registro}/{proprietario}/{immagine} -->
<ContainerRegistry>gitea.encke-hake.ts.net/alby96</ContainerRegistry>
</PropertyGroup>
<ItemGroup>
<!-- Exclude WPF files from compilation -->
<Compile Remove=".github\**" />
<Compile Remove=".vscode\**" />
<Compile Remove="obj\**" />
<Compile Remove="Controls\**" />
<Compile Remove="Dialogs\**" />
<Compile Remove="Core\**" />
<Compile Remove="MainWindow.xaml.cs" />
<Compile Remove="App.xaml.cs" />
<Compile Remove="AssemblyInfo.cs" />
<Compile Remove="ViewModels\**" />
<Compile Remove="Utilities\NumericTextBoxHelper.cs" />
<Compile Remove="Utilities\BooleanToOpacityConverter.cs" />
<Compile Remove="Utilities\RelayCommand.cs" />
<Content Remove=".github\**" />
<Content Remove=".vscode\**" />
<Content Remove="obj\**" />
<Content Remove="Controls\**" />
<Content Remove="Dialogs\**" />
<Content Remove="**\*.xaml" />
<EmbeddedResource Remove=".github\**" />
<EmbeddedResource Remove=".vscode\**" />
<EmbeddedResource Remove="obj\**" />
<EmbeddedResource Remove="Controls\**" />
<EmbeddedResource Remove="Dialogs\**" />
<None Remove=".github\**" />
<None Remove=".vscode\**" />
<None Remove="obj\**" />
<None Remove="Controls\**" />
<None Remove="Dialogs\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Icon\favicon.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<Content Include="Icon\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include=".gitea\workflows\backup.yml" />
<None Include=".gitea\workflows\deploy.yml" />
<None Include=".gitea\workflows\health-check.yml" />
<None Include=".github\workflows\ci-cd.yml" />
<None Include="Dockerfile" />
<None Include=".dockerignore" />
<None Include="Properties\PublishProfiles\GiteaRegistry-Versioned.pubxml.user" />
</ItemGroup>
<!-- ============================================ -->
<!-- POST-BUILD TARGET: Push automatico su Gitea -->
<!-- con versionamento da <Version> della solution -->
<!-- ============================================ -->
<Target Name="PushDockerImageToGitea" AfterTargets="Publish" Condition="'$(PushToGiteaRegistry)' == 'true'">
<PropertyGroup>
<GiteaRegistry>gitea.encke-hake.ts.net/alby96</GiteaRegistry>
<LocalImageName>autobidder</LocalImageName>
<GiteaImageLatest>$(GiteaRegistry)/$(LocalImageName):latest</GiteaImageLatest>
<GiteaImageVersion>$(GiteaRegistry)/$(LocalImageName):$(Version)</GiteaImageVersion>
</PropertyGroup>
<Message Importance="high" Text="" />
<Message Importance="high" Text="+-------------------------------------------------------------------+" />
<Message Importance="high" Text="¦ POST-BUILD: Pubblicazione su Gitea Container Registry ¦" />
<Message Importance="high" Text="+-------------------------------------------------------------------+" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="?? Solution Version: $(Version)" />
<Message Importance="high" Text="?? Local Image: $(LocalImageName):latest" />
<Message Importance="high" Text="??? Target Tags:" />
<Message Importance="high" Text=" • $(GiteaImageLatest)" />
<Message Importance="high" Text=" • $(GiteaImageVersion)" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="-------------------------------------------------------------------" />
<Message Importance="high" Text="??? Tagging images..." />
<Message Importance="high" Text="-------------------------------------------------------------------" />
<!-- Tag immagine locale per Gitea (latest) -->
<Exec Command="docker tag $(LocalImageName):latest $(GiteaImageLatest)" />
<Message Importance="high" Text="? Tagged: $(GiteaImageLatest)" />
<!-- Tag immagine locale per Gitea (versione solution) -->
<Exec Command="docker tag $(LocalImageName):latest $(GiteaImageVersion)" />
<Message Importance="high" Text="? Tagged: $(GiteaImageVersion)" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="-------------------------------------------------------------------" />
<Message Importance="high" Text="?? Pushing to Gitea Registry..." />
<Message Importance="high" Text="-------------------------------------------------------------------" />
<!-- Push latest -->
<Exec Command="docker push $(GiteaImageLatest)" />
<Message Importance="high" Text="? Pushed: $(GiteaImageLatest)" />
<!-- Push version -->
<Exec Command="docker push $(GiteaImageVersion)" />
<Message Importance="high" Text="? Pushed: $(GiteaImageVersion)" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="+-------------------------------------------------------------------+" />
<Message Importance="high" Text="¦ ? PUBBLICAZIONE COMPLETATA CON SUCCESSO! ¦" />
<Message Importance="high" Text="+-------------------------------------------------------------------+" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="?? Visualizza su Gitea:" />
<Message Importance="high" Text=" https://gitea.encke-hake.ts.net/Alby96/-/packages/container/autobidder" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="?? Tag pubblicati:" />
<Message Importance="high" Text=" • latest (sempre aggiornato all'ultima versione)" />
<Message Importance="high" Text=" • $(Version) (versione solution corrente)" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="?? Pull command:" />
<Message Importance="high" Text=" docker pull $(GiteaImageLatest)" />
<Message Importance="high" Text=" docker pull $(GiteaImageVersion)" />
<Message Importance="high" Text="" />
<Message Importance="high" Text="-------------------------------------------------------------------" />
<Message Importance="high" Text="" />
</Target>
</Project>

49
Mimante/AutoBidder.sln Normal file
View File

@@ -0,0 +1,49 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.0.11217.181 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoBidder", "AutoBidder.csproj", "{9BBAEF93-DF66-432C-9349-459E272D6538}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|ARM.Build.0 = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|ARM64.Build.0 = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|x64.ActiveCfg = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|x64.Build.0 = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|x86.ActiveCfg = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Debug|x86.Build.0 = Debug|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|Any CPU.Build.0 = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|ARM.ActiveCfg = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|ARM.Build.0 = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|ARM64.ActiveCfg = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|ARM64.Build.0 = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|x64.ActiveCfg = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|x64.Build.0 = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|x86.ActiveCfg = Release|Any CPU
{9BBAEF93-DF66-432C-9349-459E272D6538}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1C55CA56-D270-4D9A-91DA-410BF131E905}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,964 @@
<UserControl x:Class="AutoBidder.Controls.AuctionMonitorControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:util="clr-namespace:AutoBidder.Utilities"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1200"
Background="#1E1E1E">
<UserControl.Resources>
<!-- Converters -->
<util:BooleanToOpacityConverter x:Key="BoolToOpacity"/>
<!-- Rounded Button Style -->
<Style x:Key="RoundedButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="8"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="15,10"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<!-- Small Rounded Button -->
<Style x:Key="SmallRoundedButton" TargetType="Button" BasedOn="{StaticResource RoundedButton}">
<Setter Property="Padding" Value="12,6"/>
<Setter Property="FontSize" Value="12"/>
</Style>
<!-- Card Style -->
<Style x:Key="CardBorder" TargetType="Border">
<Setter Property="Background" Value="#252526"/>
<Setter Property="BorderBrush" Value="#3E3E42"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="Margin" Value="5"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Header - COMPATTO SU 3 RIGHE -->
<Border Grid.Row="0" Background="#2D2D30" Padding="15,8" BorderBrush="#3E3E42" BorderThickness="0,0,0,1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Riga 1: Solo Puntate -->
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,3">
<TextBlock Text="Puntate: "
Foreground="#999999"
FontSize="13"
Margin="0,0,5,0"/>
<!-- 🎯 StackPanel per includere indicatore limite -->
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="RemainingBidsText"
Text="0"
Foreground="#00D800"
FontSize="13"
FontWeight="Bold"
Margin="0,0,0,0"/>
<!-- 🎯 Indicatore limite minimo puntate (solo numero tra parentesi) -->
<TextBlock x:Name="MinBidsLimitIndicator"
Text="(20)"
FontSize="13"
FontWeight="Bold"
Margin="5,0,0,0"
VerticalAlignment="Center"
Visibility="Collapsed"
ToolTip="Limite minimo puntate attivo"/>
</StackPanel>
</StackPanel>
<!-- Riga 2: Solo Credito Shop -->
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,3">
<TextBlock Text="Credito Shop: "
Foreground="#999999"
FontSize="12"
Margin="0,0,5,0"/>
<TextBlock x:Name="ShopCreditText"
Text="EUR 0.00"
Foreground="#00D800"
FontSize="12"
FontWeight="Bold"/>
</StackPanel>
<!-- Riga 3: Solo Aste vinte -->
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Text="Aste vinte da confermare: "
Foreground="#999999"
FontSize="12"
Margin="0,0,5,0"/>
<TextBlock x:Name="BannerAsteDaRiscattare"
Text="0"
Foreground="#FFB700"
FontSize="12"
FontWeight="Bold"/>
</StackPanel>
<!-- Control Buttons (Right) - Su tutte e 3 le righe -->
<StackPanel Grid.Row="0" Grid.RowSpan="3" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
<Button x:Name="StartButton"
Content="Avvia Tutti"
Background="#00D800"
Style="{StaticResource RoundedButton}"
Margin="5,0"
Click="StartButton_Click"/>
<Button x:Name="PauseAllButton"
Content="Pausa Tutti"
Background="#FFB700"
Style="{StaticResource RoundedButton}"
Margin="5,0"
Click="PauseAllButton_Click"/>
<Button x:Name="StopButton"
Content="Ferma Tutti"
Background="#E81123"
Style="{StaticResource RoundedButton}"
Margin="5,0"
Click="StopButton_Click"/>
<!-- Separator -->
<Border Width="1"
Background="#3E3E42"
Margin="10,5"/>
<!-- Export Button -->
<Button x:Name="ExportButton"
Content="Esporta"
Background="#007ACC"
Style="{StaticResource RoundedButton}"
Margin="5,0"
Click="ExportButton_Click"
ToolTip="Esporta dati aste monitorate"/>
</StackPanel>
</Grid>
</Border>
<!-- Main Layout: 2 rows -->
<Grid Grid.Row="1" Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="5"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- TOP ROW: Auction Grid (2/3) + Global Log (1/3) -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- TOP LEFT: Auction Grid -->
<Border Grid.Column="0" Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Grid Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10,8" CornerRadius="4,4,0,0">
<Grid>
<TextBlock x:Name="MonitorateTitle"
Text="Aste monitorate: 0"
Foreground="#00D800"
FontSize="14"
FontWeight="Bold"
VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Aggiungi"
x:Name="AddUrlButton"
Background="#007ACC"
Style="{StaticResource SmallRoundedButton}"
Padding="10,5"
FontSize="11"
Margin="3,0"
Click="AddUrlButton_Click"
ToolTip="Aggiungi nuova asta"/>
<!-- NUOVO: Pulsanti per riordinare le aste (senza emoji) -->
<Button Content="Sposta Su"
x:Name="MoveUpButton"
Background="#9B4F96"
Style="{StaticResource SmallRoundedButton}"
Padding="10,5"
FontSize="11"
Margin="3,0"
Click="MoveUpButton_Click"
ToolTip="Sposta l'asta selezionata verso l'alto"/>
<Button Content="Sposta Giù"
x:Name="MoveDownButton"
Background="#9B4F96"
Style="{StaticResource SmallRoundedButton}"
Padding="10,5"
FontSize="11"
Margin="3,0"
Click="MoveDownButton_Click"
ToolTip="Sposta l'asta selezionata verso il basso"/>
<Button Content="Rimuovi"
x:Name="RemoveUrlButton"
Background="#3E3E42"
Style="{StaticResource SmallRoundedButton}"
Padding="10,5"
FontSize="11"
Margin="3,0"
Click="RemoveUrlButton_Click"
ToolTip="Rimuovi asta selezionata"/>
<Button Content="Rimuovi Tutte"
x:Name="RemoveAllButton"
Background="#E81123"
Style="{StaticResource SmallRoundedButton}"
Padding="10,5"
FontSize="11"
Margin="3,0"
Click="RemoveAllButton_Click"
ToolTip="Rimuovi tutte le aste monitorate"/>
</StackPanel>
</Grid>
</Border>
<!-- Auction DataGrid -->
<DataGrid Grid.Row="1"
x:Name="MultiAuctionsGrid"
AutoGenerateColumns="False"
SelectionMode="Single"
CanUserAddRows="False"
IsReadOnly="True"
GridLinesVisibility="Horizontal"
HeadersVisibility="Column"
Background="#1E1E1E"
Foreground="#CCCCCC"
RowBackground="#1E1E1E"
AlternatingRowBackground="#252526"
BorderThickness="0"
SelectionChanged="MultiAuctionsGrid_SelectionChanged"
PreviewKeyDown="MultiAuctionsGrid_PreviewKeyDown"
Focusable="True"
FocusVisualStyle="{x:Null}">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#2D2D30"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Padding" Value="8,6"/>
<Setter Property="BorderThickness" Value="0,0,1,1"/>
<Setter Property="BorderBrush" Value="#3E3E42"/>
<Setter Property="FontSize" Value="11"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="FontSize" Value="11"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#094771"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding AuctionId}" Width="90"/>
<DataGridTextColumn Header="Asta" Binding="{Binding Name}" Width="2*"/>
<DataGridTextColumn Header="Latenza" Binding="{Binding LatencyDisplay}" Width="70"/>
<DataGridTextColumn Header="Stato" Binding="{Binding StatusDisplay}" Width="100"/>
<DataGridTextColumn Header="Timer" Binding="{Binding TimerDisplay}" Width="90"/>
<DataGridTextColumn Header="Prezzo" Binding="{Binding PriceDisplay}" Width="70"/>
<DataGridTextColumn Header="Ultimo" Binding="{Binding LastBidder}" Width="110"/>
<DataGridTextColumn Header="Clicks" Binding="{Binding MyClicks}" Width="60"/>
<DataGridTemplateColumn Header="Azioni" Width="260">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="Avvia"
Command="{Binding DataContext.GridStartCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
IsEnabled="{Binding CanStart}"
Opacity="{Binding CanStart, Converter={StaticResource BoolToOpacity}}"
Background="#00D800"
Style="{StaticResource SmallRoundedButton}"
Padding="6,3"
FontSize="10"
Margin="1"/>
<Button Content="Pausa"
Command="{Binding DataContext.GridPauseCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
IsEnabled="{Binding CanPause}"
Opacity="{Binding CanPause, Converter={StaticResource BoolToOpacity}}"
Background="#FFB700"
Style="{StaticResource SmallRoundedButton}"
Padding="6,3"
FontSize="10"
Margin="1"/>
<Button Content="Ferma"
Command="{Binding DataContext.GridStopCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
IsEnabled="{Binding CanStop}"
Opacity="{Binding CanStop, Converter={StaticResource BoolToOpacity}}"
Background="#E81123"
Style="{StaticResource SmallRoundedButton}"
Padding="6,3"
FontSize="10"
Margin="1"/>
<Button Content="Punta"
Command="{Binding DataContext.GridBidCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
IsEnabled="{Binding CanBid}"
Opacity="{Binding CanBid, Converter={StaticResource BoolToOpacity}}"
Background="#9B4F96"
Style="{StaticResource SmallRoundedButton}"
Padding="6,3"
FontSize="10"
Margin="1"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Border>
<!-- Vertical Splitter -->
<GridSplitter Grid.Column="1"
Width="5"
HorizontalAlignment="Stretch"
Background="#3E3E42"
ResizeBehavior="PreviousAndNext"/>
<!-- TOP RIGHT: Global Log -->
<Border Grid.Column="2" Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10,8" CornerRadius="4,4,0,0">
<Grid>
<TextBlock Text="Log Globale"
Foreground="#00D800"
FontSize="13"
FontWeight="Bold"
VerticalAlignment="Center"/>
<Button x:Name="ClearGlobalLogButton"
Content="Pulisci"
HorizontalAlignment="Right"
Background="#3E3E42"
Style="{StaticResource SmallRoundedButton}"
Padding="8,4"
FontSize="10"
Click="ClearGlobalLogButton_Click"/>
</Grid>
</Border>
<!-- Log Box -->
<RichTextBox Grid.Row="1"
x:Name="LogBox"
IsReadOnly="True"
VerticalScrollBarVisibility="Auto"
Background="#1E1E1E"
Foreground="#00D800"
BorderThickness="0"
FontFamily="Consolas"
FontSize="10"
Padding="8"/>
</Grid>
</Border>
</Grid>
<!-- Horizontal Splitter -->
<GridSplitter Grid.Row="1"
Height="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="#3E3E42"
ResizeBehavior="PreviousAndNext"/>
<!-- BOTTOM ROW: Settings (1/3) + Bidders (1/3) + Auction Log (1/3) -->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- BOTTOM LEFT: Settings (Impostazioni) -->
<Border Grid.Column="0" Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10,8" CornerRadius="4,4,0,0">
<TextBlock Text="Impostazioni"
Foreground="#00D800"
FontSize="13"
FontWeight="Bold"/>
</Border>
<!-- Settings Content -->
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="10">
<TextBlock x:Name="SelectedAuctionName"
Text="Seleziona un'asta"
Foreground="White"
FontSize="13"
FontWeight="Bold"
Margin="0,0,0,8"/>
<TextBox x:Name="SelectedAuctionUrl"
IsReadOnly="True"
Background="#1E1E1E"
Foreground="#999999"
BorderBrush="#3E3E42"
BorderThickness="1"
Padding="6"
FontSize="10"
Margin="0,0,0,8"
TextWrapping="Wrap"
MaxHeight="50"/>
<!-- Pulsanti azione asta - RIORDINATI E FUNZIONANTI -->
<Grid Margin="0,0,0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Riga 1: Browser -->
<Button Grid.Row="0" Grid.Column="0"
x:Name="OpenAuctionInternalButton"
Content="Browser Interno"
Background="#007ACC"
Style="{StaticResource SmallRoundedButton}"
Padding="8,5"
FontSize="10"
Margin="0,0,2,3"
ToolTip="Apri asta nel browser integrato"
Click="OpenAuctionInternalButton_Click"/>
<Button Grid.Row="0" Grid.Column="1"
x:Name="OpenAuctionExternalButton"
Content="Browser Esterno"
Background="#0078D7"
Style="{StaticResource SmallRoundedButton}"
Padding="8,5"
FontSize="10"
Margin="2,0,0,3"
ToolTip="Apri asta nel browser predefinito di sistema"
Click="OpenAuctionExternalButton_Click"/>
<!-- Riga 2: Azioni -->
<Button Grid.Row="1" Grid.Column="0"
x:Name="CopyAuctionUrlButton"
Content="Copia URL"
Background="#9B4F96"
Style="{StaticResource SmallRoundedButton}"
Padding="8,5"
FontSize="10"
Margin="0,0,2,0"
ToolTip="Copia URL negli appunti"
Click="CopyAuctionUrlButton_Click"/>
<Button Grid.Row="1" Grid.Column="1"
x:Name="ExportAuctionButton"
Content="Esporta"
Background="#106EBE"
Style="{StaticResource SmallRoundedButton}"
Padding="8,5"
FontSize="10"
Margin="2,0,0,0"
ToolTip="Esporta dati asta"
Click="ExportAuctionButton_Click"/>
</Grid>
<!-- NUOVA SEZIONE: Info Prodotto - SEZIONE FISSA -->
<Border BorderBrush="#3E3E42"
BorderThickness="1"
Background="#2D2D30"
Padding="10"
CornerRadius="4"
Margin="0,0,0,10">
<StackPanel>
<!-- Header fisso -->
<TextBlock Text="Informazioni Prodotto"
FontWeight="Bold"
FontSize="12"
Foreground="#CCCCCC"
Margin="0,0,0,10"/>
<!-- Dati Prodotto -->
<Grid x:Name="ProductInfoGrid" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Valore -->
<TextBlock Grid.Row="0" Grid.Column="0"
Text="Valore:"
FontWeight="Bold"
Foreground="#CCCCCC"
FontSize="11"
Margin="0,3"/>
<TextBlock Grid.Row="0" Grid.Column="1"
x:Name="ProductBuyNowPriceText"
Text="-"
Foreground="#007ACC"
FontSize="11"
FontWeight="Bold"
Margin="5,3"/>
<!-- Extra (Spedizione/Transazione) -->
<TextBlock Grid.Row="1" Grid.Column="0"
Text="Extra:"
FontWeight="Bold"
Foreground="#CCCCCC"
FontSize="11"
Margin="0,3"
ToolTip="Spese di spedizione o transazione"/>
<TextBlock Grid.Row="1" Grid.Column="1"
x:Name="ProductShippingCostText"
Text="-"
Foreground="#FFB700"
FontSize="11"
Margin="5,3"/>
<!-- Limite Vincita -->
<TextBlock Grid.Row="2" Grid.Column="0"
Text="Limite:"
FontWeight="Bold"
Foreground="#CCCCCC"
FontSize="11"
Margin="0,3"/>
<TextBlock Grid.Row="2" Grid.Column="1"
x:Name="ProductWinLimitText"
Text="-"
Foreground="#999999"
FontSize="11"
TextWrapping="Wrap"
Margin="5,3"/>
</Grid>
<!-- Pulsante Applica Limiti -->
<Button x:Name="RefreshProductInfoButton"
Content="Applica Limiti Suggeriti"
Background="#007ACC"
Style="{StaticResource SmallRoundedButton}"
HorizontalAlignment="Stretch"
Padding="10,6"
FontSize="11"
Margin="0,0,0,0"
Click="RefreshProductInfoButton_Click"
ToolTip="Calcola e applica limiti Max EUR e Max Clicks basati sul valore del prodotto"/>
</StackPanel>
</Border>
<!-- Settings Grid - Campi aggiornati -->
<Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="15"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Row 1: Anticipo ms -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="Anticipo (ms):" Foreground="#CCCCCC" FontSize="11" Margin="0,6" VerticalAlignment="Center" ToolTip="Millisecondi prima della scadenza per puntare"/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="SelectedBidBeforeDeadlineMs" Background="#1E1E1E" Foreground="White" BorderBrush="#3E3E42" Padding="6" Margin="5,6" FontSize="11" TextChanged="SelectedBidBeforeDeadlineMs_TextChanged"/>
<TextBlock Grid.Row="0" Grid.Column="3" Text="Min EUR:" Foreground="#CCCCCC" FontSize="11" Margin="0,6" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="4" x:Name="SelectedMinPrice" Background="#1E1E1E" Foreground="White" BorderBrush="#3E3E42" Padding="6" Margin="5,6" FontSize="11" TextChanged="SelectedMinPrice_TextChanged"/>
<!-- Row 2 -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="Max EUR:" Foreground="#CCCCCC" FontSize="11" Margin="0,6" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" x:Name="SelectedMaxPrice" Background="#1E1E1E" Foreground="White" BorderBrush="#3E3E42" Padding="6" Margin="5,6" FontSize="11" TextChanged="SelectedMaxPrice_TextChanged"/>
<TextBlock Grid.Row="1" Grid.Column="3" Text="Max Clicks:" Foreground="#CCCCCC" FontSize="11" Margin="0,6" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="4" x:Name="SelectedMaxClicks" Background="#1E1E1E" Foreground="White" BorderBrush="#3E3E42" Padding="6" Margin="5,6" FontSize="11" TextChanged="SelectedMaxClicks_TextChanged"/>
<!-- Row 3: Check Auction Open -->
<CheckBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="5"
x:Name="SelectedCheckAuctionOpen"
Content="Verifica stato asta prima di puntare"
Foreground="#CCCCCC"
FontSize="11"
Margin="0,10,0,0"
Checked="SelectedCheckAuctionOpen_Changed"
Unchecked="SelectedCheckAuctionOpen_Changed"
ToolTip="Aggiunge una chiamata API extra per verificare che l'asta sia ancora aperta"/>
</Grid>
</StackPanel>
</ScrollViewer>
<!-- Footer Button (bottom like other panels) -->
<Button Grid.Row="2"
x:Name="ResetSettingsButton"
Content="Reset"
Background="#3E3E42"
Style="{StaticResource SmallRoundedButton}"
HorizontalAlignment="Stretch"
Margin="5"
Click="ResetSettingsButton_Click"/>
</Grid>
</Border>
<!-- Vertical Splitter 1 -->
<GridSplitter Grid.Column="1"
Width="5"
HorizontalAlignment="Stretch"
Background="#3E3E42"
ResizeBehavior="PreviousAndNext"/>
<!-- BOTTOM CENTER: Tab Control (Utenti + Storia Puntate) -->
<Border Grid.Column="2" Style="{StaticResource CardBorder}">
<TabControl Background="#252526" BorderThickness="0">
<TabControl.Resources>
<!-- Tab Header Style -->
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border"
Background="#2D2D30"
BorderBrush="#3E3E42"
BorderThickness="0,0,1,0"
Padding="15,8">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#094771"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="#3E3E42"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
</TabControl.Resources>
<!-- Tab 1: Utenti -->
<TabItem Header="Utenti">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10,8">
<TextBlock x:Name="SelectedAuctionBiddersCount"
Text="Utenti: 0"
Foreground="#00D800"
FontSize="13"
FontWeight="Bold"/>
</Border>
<!-- Bidders Grid -->
<DataGrid Grid.Row="1"
x:Name="SelectedAuctionBiddersGrid"
AutoGenerateColumns="False"
IsReadOnly="True"
Background="#1E1E1E"
Foreground="#CCCCCC"
RowBackground="#1E1E1E"
AlternatingRowBackground="#252526"
GridLinesVisibility="None"
HeadersVisibility="Column"
BorderThickness="0"
FontSize="11">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#2D2D30"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Padding" Value="8,5"/>
<Setter Property="FontSize" Value="11"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Utente" Binding="{Binding Username}" Width="*"/>
<DataGridTextColumn Header="Punt." Binding="{Binding BidCount}" Width="50"/>
<DataGridTextColumn Header="Ultima" Binding="{Binding LastBidTimeDisplay}" Width="70"/>
</DataGrid.Columns>
</DataGrid>
<!-- Footer Button -->
<Button Grid.Row="2"
x:Name="ClearBiddersButton"
Content="Pulisci"
Background="#3E3E42"
Style="{StaticResource SmallRoundedButton}"
HorizontalAlignment="Stretch"
Margin="5"
Click="ClearBiddersButton_Click"/>
</Grid>
</TabItem>
<!-- Tab 2: Storia Puntate -->
<TabItem Header="Storia Puntate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10,8">
<TextBlock x:Name="BidHistoryCount"
Text="Ultime puntate: 0"
Foreground="#00D800"
FontSize="13"
FontWeight="Bold"/>
</Border>
<!-- Storia Puntate Grid -->
<DataGrid Grid.Row="1"
x:Name="BidHistoryGrid"
ItemsSource="{Binding ElementName=MultiAuctionsGrid, Path=SelectedItem.BidHistoryEntries}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeRows="False"
HeadersVisibility="Column"
GridLinesVisibility="Horizontal"
HorizontalGridLinesBrush="#3E3E42"
Background="#1E1E1E"
Foreground="#CCCCCC"
BorderThickness="0"
RowHeight="28">
<DataGrid.Columns>
<!-- Colonna Prezzo -->
<DataGridTextColumn Header="PREZZO"
Binding="{Binding PriceFormatted}"
Width="70">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#00D800"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="11"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<!-- Colonna Modalita' -->
<DataGridTextColumn Header="TIPO"
Binding="{Binding BidType}"
Width="65">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Style.Triggers>
<DataTrigger Binding="{Binding BidType}" Value="Auto">
<Setter Property="Foreground" Value="#FFC107"/>
</DataTrigger>
<DataTrigger Binding="{Binding BidType}" Value="Manuale">
<Setter Property="Foreground" Value="#03A9F4"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<!-- Colonna Orario -->
<DataGridTextColumn Header="ORARIO"
Binding="{Binding TimeFormatted}"
Width="70">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#9E9E9E"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="10"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<!-- Colonna Utente -->
<DataGridTextColumn Header="UTENTE"
Binding="{Binding Username}"
Width="*">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="Margin" Value="8,0,0,0"/>
<Setter Property="FontSize" Value="11"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMyBid}" Value="True">
<Setter Property="Foreground" Value="#00D800"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
<!-- Stili righe -->
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="#1E1E1E"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#3E3E42"/>
</Trigger>
<DataTrigger Binding="{Binding IsMyBid}" Value="True">
<Setter Property="Background" Value="#1A4D1A"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<!-- Stile header -->
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#252526"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="Padding" Value="8,6"/>
<Setter Property="BorderThickness" Value="0,0,1,1"/>
<Setter Property="BorderBrush" Value="#3E3E42"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
</Grid>
</TabItem>
</TabControl>
</Border>
<!-- Vertical Splitter 2 -->
<GridSplitter Grid.Column="3"
Width="5"
HorizontalAlignment="Stretch"
Background="#3E3E42"
ResizeBehavior="PreviousAndNext"/>
<!-- BOTTOM RIGHT: Auction Log -->
<Border Grid.Column="4" Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10,8" CornerRadius="4,4,0,0">
<Grid>
<TextBlock Text="Log Asta"
Foreground="#00D800"
FontSize="13"
FontWeight="Bold"
VerticalAlignment="Center"/>
<Button x:Name="ClearLogButton"
Content="Pulisci"
HorizontalAlignment="Right"
Background="#3E3E42"
Style="{StaticResource SmallRoundedButton}"
Padding="8,4"
FontSize="10"
Click="ClearLogButton_Click"/>
</Grid>
</Border>
<!-- Auction Log Box -->
<RichTextBox Grid.Row="1"
x:Name="SelectedAuctionLog"
IsReadOnly="True"
VerticalScrollBarVisibility="Auto"
Background="#1E1E1E"
Foreground="#CCCCCC"
BorderThickness="0"
FontFamily="Consolas"
FontSize="10"
Padding="8"/>
</Grid>
</Border>
</Grid>
</Grid>
<!-- Hidden user info panel for compatibility -->
<Border x:Name="UserInfoPanel"
Visibility="Collapsed">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="UsernameText" Text=""/>
<TextBlock x:Name="UserIdText" Text=""/>
</StackPanel>
<TextBlock x:Name="UserEmailText" Text=""/>
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,461 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace AutoBidder.Controls
{
/// <summary>
/// Interaction logic for AuctionMonitorControl.xaml
/// </summary>
public partial class AuctionMonitorControl : UserControl
{
public AuctionMonitorControl()
{
InitializeComponent();
}
// Dependency Properties per Commands (da bindare al MainWindow)
public static readonly DependencyProperty GridStartCommandProperty =
DependencyProperty.Register(nameof(GridStartCommand), typeof(ICommand), typeof(AuctionMonitorControl));
public static readonly DependencyProperty GridPauseCommandProperty =
DependencyProperty.Register(nameof(GridPauseCommand), typeof(ICommand), typeof(AuctionMonitorControl));
public static readonly DependencyProperty GridStopCommandProperty =
DependencyProperty.Register(nameof(GridStopCommand), typeof(ICommand), typeof(AuctionMonitorControl));
public static readonly DependencyProperty GridBidCommandProperty =
DependencyProperty.Register(nameof(GridBidCommand), typeof(ICommand), typeof(AuctionMonitorControl));
public ICommand? GridStartCommand
{
get => (ICommand?)GetValue(GridStartCommandProperty);
set => SetValue(GridStartCommandProperty, value);
}
public ICommand? GridPauseCommand
{
get => (ICommand?)GetValue(GridPauseCommandProperty);
set => SetValue(GridPauseCommandProperty, value);
}
public ICommand? GridStopCommand
{
get => (ICommand?)GetValue(GridStopCommandProperty);
set => SetValue(GridStopCommandProperty, value);
}
public ICommand? GridBidCommand
{
get => (ICommand?)GetValue(GridBidCommandProperty);
set => SetValue(GridBidCommandProperty, value);
}
// Event handlers - these will bubble up to MainWindow
private void StartButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(StartClickedEvent, this));
}
private void PauseAllButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(PauseAllClickedEvent, this));
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(StopClickedEvent, this));
}
private void AddUrlButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(AddUrlClickedEvent, this));
}
private void RemoveUrlButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(RemoveUrlClickedEvent, this));
}
private void RemoveAllButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(RemoveAllClickedEvent, this));
}
private void ExportButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ExportClickedEvent, this));
}
private void MultiAuctionsGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Forza il focus sul DataGrid quando viene selezionata una riga
// Questo assicura che il tasto Canc venga catturato
if (sender is DataGrid grid && grid.SelectedItem != null)
{
// Attende che il rendering sia completo prima di dare il focus
grid.Dispatcher.BeginInvoke(new Action(() =>
{
if (!grid.IsFocused)
{
grid.Focus();
System.Diagnostics.Debug.WriteLine("[FOCUS] DataGrid ora ha il focus keyboard");
}
}), System.Windows.Threading.DispatcherPriority.Background);
}
RaiseEvent(new RoutedEventArgs(AuctionSelectionChangedEvent, this));
}
// Usato PreviewKeyDown invece di KeyDown per catturare l'evento prima che venga consumato
private void MultiAuctionsGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete && MultiAuctionsGrid.SelectedItem != null)
{
System.Diagnostics.Debug.WriteLine("[DELETE KEY] Tasto Canc premuto su asta selezionata");
// Lancia direttamente l'evento senza chiedere conferma
// La conferma verrà mostrata dal gestore RemoveUrlButton_Click
System.Diagnostics.Debug.WriteLine("[DELETE KEY] Lancio evento RemoveUrlClicked");
RaiseEvent(new RoutedEventArgs(RemoveUrlClickedEvent, this));
// Previeni che l'evento venga gestito da altri controlli
e.Handled = true;
}
// NUOVO: Gestione esplicita frecce Su/Giù per navigazione
else if (e.Key == Key.Up && MultiAuctionsGrid.Items.Count > 0)
{
int currentIndex = MultiAuctionsGrid.SelectedIndex;
if (currentIndex > 0)
{
MultiAuctionsGrid.SelectedIndex = currentIndex - 1;
MultiAuctionsGrid.ScrollIntoView(MultiAuctionsGrid.SelectedItem);
e.Handled = true; // Previeni ridimensionamento pannelli
}
}
else if (e.Key == Key.Down && MultiAuctionsGrid.Items.Count > 0)
{
int currentIndex = MultiAuctionsGrid.SelectedIndex;
if (currentIndex < MultiAuctionsGrid.Items.Count - 1)
{
MultiAuctionsGrid.SelectedIndex = currentIndex + 1;
MultiAuctionsGrid.ScrollIntoView(MultiAuctionsGrid.SelectedItem);
e.Handled = true; // Previeni ridimensionamento pannelli
}
}
}
private void MoveUpButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(MoveUpClickedEvent, this));
}
private void MoveDownButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(MoveDownClickedEvent, this));
}
private void CopyAuctionUrlButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(CopyUrlClickedEvent, this));
}
private void ResetSettingsButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ResetSettingsClickedEvent, this));
}
private void ClearBiddersButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ClearBiddersClickedEvent, this));
}
private void ClearLogButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ClearLogClickedEvent, this));
}
private void ClearGlobalLogButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ClearGlobalLogClickedEvent, this));
}
private void OpenAuctionInternalButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(OpenAuctionInternalClickedEvent, this));
}
private void OpenAuctionExternalButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(OpenAuctionExternalClickedEvent, this));
}
private void ExportAuctionButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ExportAuctionClickedEvent, this));
}
private void RefreshProductInfoButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(RefreshProductInfoClickedEvent, this));
}
private void ConnectionStatusButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ConnectionStatusClickedEvent, this));
}
private void SelectedBidBeforeDeadlineMs_TextChanged(object sender, TextChangedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(BidBeforeDeadlineMsChangedEvent, this));
}
private void SelectedCheckAuctionOpen_Changed(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(CheckAuctionOpenChangedEvent, this));
}
private void SelectedMinPrice_TextChanged(object sender, TextChangedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(MinPriceChangedEvent, this));
}
private void SelectedMaxPrice_TextChanged(object sender, TextChangedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(MaxPriceChangedEvent, this));
}
private void SelectedMaxClicks_TextChanged(object sender, TextChangedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(MaxClicksChangedEvent, this));
}
// Routed Events
public static readonly RoutedEvent StartClickedEvent = EventManager.RegisterRoutedEvent(
"StartClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent PauseAllClickedEvent = EventManager.RegisterRoutedEvent(
"PauseAllClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent StopClickedEvent = EventManager.RegisterRoutedEvent(
"StopClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent AddUrlClickedEvent = EventManager.RegisterRoutedEvent(
"AddUrlClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent RemoveUrlClickedEvent = EventManager.RegisterRoutedEvent(
"RemoveUrlClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent RemoveAllClickedEvent = EventManager.RegisterRoutedEvent(
"RemoveAllClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ExportClickedEvent = EventManager.RegisterRoutedEvent(
"ExportClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent AuctionSelectionChangedEvent = EventManager.RegisterRoutedEvent(
"AuctionSelectionChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent CopyUrlClickedEvent = EventManager.RegisterRoutedEvent(
"CopyUrlClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ResetSettingsClickedEvent = EventManager.RegisterRoutedEvent(
"ResetSettingsClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ClearBiddersClickedEvent = EventManager.RegisterRoutedEvent(
"ClearBiddersClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ClearLogClickedEvent = EventManager.RegisterRoutedEvent(
"ClearLogClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ClearGlobalLogClickedEvent = EventManager.RegisterRoutedEvent(
"ClearGlobalLogClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent BidBeforeDeadlineMsChangedEvent = EventManager.RegisterRoutedEvent(
"BidBeforeDeadlineMsChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent CheckAuctionOpenChangedEvent = EventManager.RegisterRoutedEvent(
"CheckAuctionOpenChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent MinPriceChangedEvent = EventManager.RegisterRoutedEvent(
"MinPriceChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent MaxPriceChangedEvent = EventManager.RegisterRoutedEvent(
"MaxPriceChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent MaxClicksChangedEvent = EventManager.RegisterRoutedEvent(
"MaxClicksChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent OpenAuctionInternalClickedEvent = EventManager.RegisterRoutedEvent(
"OpenAuctionInternalClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent OpenAuctionExternalClickedEvent = EventManager.RegisterRoutedEvent(
"OpenAuctionExternalClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ExportAuctionClickedEvent = EventManager.RegisterRoutedEvent(
"ExportAuctionClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent RefreshProductInfoClickedEvent = EventManager.RegisterRoutedEvent(
"RefreshProductInfoClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent ConnectionStatusClickedEvent = EventManager.RegisterRoutedEvent(
"ConnectionStatusClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
// NUOVO: Eventi per riordinamento aste
public static readonly RoutedEvent MoveUpClickedEvent = EventManager.RegisterRoutedEvent(
"MoveUpClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public static readonly RoutedEvent MoveDownClickedEvent = EventManager.RegisterRoutedEvent(
"MoveDownClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(AuctionMonitorControl));
public event RoutedEventHandler StartClicked
{
add { AddHandler(StartClickedEvent, value); }
remove { RemoveHandler(StartClickedEvent, value); }
}
public event RoutedEventHandler PauseAllClicked
{
add { AddHandler(PauseAllClickedEvent, value); }
remove { RemoveHandler(PauseAllClickedEvent, value); }
}
public event RoutedEventHandler StopClicked
{
add { AddHandler(StopClickedEvent, value); }
remove { RemoveHandler(StopClickedEvent, value); }
}
public event RoutedEventHandler AddUrlClicked
{
add { AddHandler(AddUrlClickedEvent, value); }
remove { RemoveHandler(AddUrlClickedEvent, value); }
}
public event RoutedEventHandler RemoveUrlClicked
{
add { AddHandler(RemoveUrlClickedEvent, value); }
remove { RemoveHandler(RemoveUrlClickedEvent, value); }
}
public event RoutedEventHandler RemoveAllClicked
{
add { AddHandler(RemoveAllClickedEvent, value); }
remove { RemoveHandler(RemoveAllClickedEvent, value); }
}
public event RoutedEventHandler ExportClicked
{
add { AddHandler(ExportClickedEvent, value); }
remove { RemoveHandler(ExportClickedEvent, value); }
}
public event RoutedEventHandler AuctionSelectionChanged
{
add { AddHandler(AuctionSelectionChangedEvent, value); }
remove { RemoveHandler(AuctionSelectionChangedEvent, value); }
}
public event RoutedEventHandler CopyUrlClicked
{
add { AddHandler(CopyUrlClickedEvent, value); }
remove { RemoveHandler(CopyUrlClickedEvent, value); }
}
public event RoutedEventHandler ResetSettingsClicked
{
add { AddHandler(ResetSettingsClickedEvent, value); }
remove { RemoveHandler(ResetSettingsClickedEvent, value); }
}
public event RoutedEventHandler ClearBiddersClicked
{
add { AddHandler(ClearBiddersClickedEvent, value); }
remove { RemoveHandler(ClearBiddersClickedEvent, value); }
}
public event RoutedEventHandler ClearLogClicked
{
add { AddHandler(ClearLogClickedEvent, value); }
remove { RemoveHandler(ClearLogClickedEvent, value); }
}
public event RoutedEventHandler ClearGlobalLogClicked
{
add { AddHandler(ClearGlobalLogClickedEvent, value); }
remove { RemoveHandler(ClearGlobalLogClickedEvent, value); }
}
public event RoutedEventHandler BidBeforeDeadlineMsChanged
{
add { AddHandler(BidBeforeDeadlineMsChangedEvent, value); }
remove { RemoveHandler(BidBeforeDeadlineMsChangedEvent, value); }
}
public event RoutedEventHandler CheckAuctionOpenChanged
{
add { AddHandler(CheckAuctionOpenChangedEvent, value); }
remove { RemoveHandler(CheckAuctionOpenChangedEvent, value); }
}
public event RoutedEventHandler MinPriceChanged
{
add { AddHandler(MinPriceChangedEvent, value); }
remove { RemoveHandler(MinPriceChangedEvent, value); }
}
public event RoutedEventHandler MaxPriceChanged
{
add { AddHandler(MaxPriceChangedEvent, value); }
remove { RemoveHandler(MaxPriceChangedEvent, value); }
}
public event RoutedEventHandler MaxClicksChanged
{
add { AddHandler(MaxClicksChangedEvent, value); }
remove { RemoveHandler(MaxClicksChangedEvent, value); }
}
public event RoutedEventHandler OpenAuctionInternalClicked
{
add { AddHandler(OpenAuctionInternalClickedEvent, value); }
remove { RemoveHandler(OpenAuctionInternalClickedEvent, value); }
}
public event RoutedEventHandler OpenAuctionExternalClicked
{
add { AddHandler(OpenAuctionExternalClickedEvent, value); }
remove { RemoveHandler(OpenAuctionExternalClickedEvent, value); }
}
public event RoutedEventHandler ExportAuctionClicked
{
add { AddHandler(ExportAuctionClickedEvent, value); }
remove { RemoveHandler(ExportAuctionClickedEvent, value); }
}
public event RoutedEventHandler RefreshProductInfoClicked
{
add { AddHandler(RefreshProductInfoClickedEvent, value); }
remove { RemoveHandler(RefreshProductInfoClickedEvent, value); }
}
public event RoutedEventHandler ConnectionStatusClicked
{
add { AddHandler(ConnectionStatusClickedEvent, value); }
remove { RemoveHandler(ConnectionStatusClickedEvent, value); }
}
// NUOVO: Handler per eventi riordinamento
public event RoutedEventHandler MoveUpClicked
{
add { AddHandler(MoveUpClickedEvent, value); }
remove { RemoveHandler(MoveUpClickedEvent, value); }
}
public event RoutedEventHandler MoveDownClicked
{
add { AddHandler(MoveDownClickedEvent, value); }
remove { RemoveHandler(MoveDownClickedEvent, value); }
}
}
}

View File

@@ -0,0 +1,128 @@
<UserControl x:Class="AutoBidder.Controls.BrowserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1200"
Background="#1E1E1E">
<UserControl.Resources>
<Style x:Key="RoundedButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
</Style>
<!-- Nav Button Style (text only) -->
<Style x:Key="NavButton" TargetType="Button" BasedOn="{StaticResource RoundedButton}">
<Setter Property="MinWidth" Value="50"/>
<Setter Property="Height" Value="30"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="Padding" Value="8,0"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Browser Toolbar -->
<Border Grid.Row="0" Background="#2D2D30" Padding="10" BorderBrush="#3E3E42" BorderThickness="0,0,0,1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Navigation Buttons (TEXT ONLY - NO SYMBOLS) -->
<StackPanel Grid.Column="0" Orientation="Horizontal">
<Button x:Name="BrowserBackButton"
Content="Indietro"
Margin="0,0,5,0"
Background="#3E3E42"
Style="{StaticResource NavButton}"
Click="BrowserBackButton_Click"
ToolTip="Torna alla pagina precedente"/>
<Button x:Name="BrowserForwardButton"
Content="Avanti"
Margin="0,0,5,0"
Background="#3E3E42"
Style="{StaticResource NavButton}"
Click="BrowserForwardButton_Click"
ToolTip="Vai alla pagina successiva"/>
<Button x:Name="BrowserRefreshButton"
Content="Ricarica"
Margin="0,0,5,0"
Background="#3E3E42"
Style="{StaticResource NavButton}"
Click="BrowserRefreshButton_Click"
ToolTip="Ricarica la pagina corrente"/>
<Button x:Name="BrowserHomeButton"
Content="Home"
Margin="0,0,10,0"
Background="#3E3E42"
Style="{StaticResource NavButton}"
Click="BrowserHomeButton_Click"
ToolTip="Vai alla homepage Bidoo"/>
</StackPanel>
<!-- Address Bar -->
<Border Grid.Column="1"
Background="#1E1E1E"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Margin="10,0">
<TextBox x:Name="BrowserAddress"
VerticalAlignment="Center"
BorderThickness="0"
Background="Transparent"
Foreground="#CCCCCC"
Padding="10,0"
FontSize="13"
IsReadOnly="True"
Cursor="Arrow"
ToolTip="Indirizzo della pagina corrente (non editabile)"/>
</Border>
<!-- Action Buttons -->
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="10,0,0,0">
<Button x:Name="BrowserAddAuctionButton"
Content="Aggiungi Asta"
Padding="20,7"
FontSize="13"
Background="#00D800"
Style="{StaticResource RoundedButton}"
Click="BrowserAddAuctionButton_Click"
ToolTip="Aggiungi l'asta corrente al monitoraggio"/>
</StackPanel>
</Grid>
</Border>
<!-- WebView2 -->
<Border Grid.Row="1" Background="#1E1E1E">
<wv2:WebView2 x:Name="EmbeddedWebView"
PreviewMouseRightButtonUp="EmbeddedWebView_PreviewMouseRightButtonUp"/>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,157 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Web.WebView2.Core;
namespace AutoBidder.Controls
{
/// <summary>
/// Interaction logic for BrowserControl.xaml
/// REFACTORED: Gestione semplificata e diretta degli eventi WebView2
/// </summary>
public partial class BrowserControl : UserControl
{
public BrowserControl()
{
InitializeComponent();
// ? NUOVO: Collega eventi NavigationStarting e NavigationCompleted direttamente qui
EmbeddedWebView.NavigationStarting += WebView_NavigationStarting;
EmbeddedWebView.NavigationCompleted += WebView_NavigationCompleted;
}
/// <summary>
/// ? NUOVO: Aggiorna address bar quando inizia la navigazione
/// </summary>
private void WebView_NavigationStarting(object? sender, CoreWebView2NavigationStartingEventArgs e)
{
try
{
// Aggiorna immediatamente l'address bar con l'URL di destinazione
if (!string.IsNullOrEmpty(e.Uri))
{
BrowserAddress.Text = e.Uri;
}
// Propaga l'evento al MainWindow
var args = new BrowserNavigationEventArgs(BrowserNavigationStartingEvent, this)
{
Uri = e.Uri
};
RaiseEvent(args);
}
catch { }
}
/// <summary>
/// ? NUOVO: Aggiorna address bar quando la navigazione è completata
/// </summary>
private void WebView_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
{
try
{
// 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
RaiseEvent(new RoutedEventArgs(BrowserNavigationCompletedEvent, this));
}
catch { }
}
private void BrowserBackButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(BrowserBackClickedEvent, this));
}
private void BrowserForwardButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(BrowserForwardClickedEvent, this));
}
private void BrowserRefreshButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(BrowserRefreshClickedEvent, this));
}
private void BrowserHomeButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(BrowserHomeClickedEvent, this));
}
private void BrowserAddAuctionButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(BrowserAddAuctionClickedEvent, this));
}
private void EmbeddedWebView_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
// Routed Events
public static readonly RoutedEvent BrowserBackClickedEvent = EventManager.RegisterRoutedEvent(
"BrowserBackClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public static readonly RoutedEvent BrowserForwardClickedEvent = EventManager.RegisterRoutedEvent(
"BrowserForwardClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public static readonly RoutedEvent BrowserRefreshClickedEvent = EventManager.RegisterRoutedEvent(
"BrowserRefreshClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public static readonly RoutedEvent BrowserHomeClickedEvent = EventManager.RegisterRoutedEvent(
"BrowserHomeClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public static readonly RoutedEvent BrowserAddAuctionClickedEvent = EventManager.RegisterRoutedEvent(
"BrowserAddAuctionClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public static readonly RoutedEvent BrowserNavigationStartingEvent = EventManager.RegisterRoutedEvent(
"BrowserNavigationStarting", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public static readonly RoutedEvent BrowserNavigationCompletedEvent = EventManager.RegisterRoutedEvent(
"BrowserNavigationCompleted", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BrowserControl));
public event RoutedEventHandler BrowserBackClicked
{
add { AddHandler(BrowserBackClickedEvent, value); }
remove { RemoveHandler(BrowserBackClickedEvent, value); }
}
public event RoutedEventHandler BrowserForwardClicked
{
add { AddHandler(BrowserForwardClickedEvent, value); }
remove { RemoveHandler(BrowserForwardClickedEvent, value); }
}
public event RoutedEventHandler BrowserRefreshClicked
{
add { AddHandler(BrowserRefreshClickedEvent, value); }
remove { RemoveHandler(BrowserRefreshClickedEvent, value); }
}
public event RoutedEventHandler BrowserHomeClicked
{
add { AddHandler(BrowserHomeClickedEvent, value); }
remove { RemoveHandler(BrowserHomeClickedEvent, value); }
}
public event RoutedEventHandler BrowserAddAuctionClicked
{
add { AddHandler(BrowserAddAuctionClickedEvent, value); }
remove { RemoveHandler(BrowserAddAuctionClickedEvent, value); }
}
}
public class BrowserNavigationEventArgs : RoutedEventArgs
{
public string? Uri { get; set; }
public BrowserNavigationEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
{
}
}
}

View File

@@ -0,0 +1,520 @@
<UserControl x:Class="AutoBidder.Controls.SettingsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1200"
Background="#1E1E1E">
<UserControl.Resources>
<!-- Modern Button Style -->
<Style x:Key="ModernButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="20,10"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<!-- Section Header Style -->
<Style x:Key="SectionHeader" TargetType="TextBlock">
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="0,0,0,15"/>
</Style>
<!-- Label Style -->
<Style x:Key="FieldLabel" TargetType="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="Margin" Value="0,0,0,5"/>
</Style>
<!-- TextBox Style -->
<Style TargetType="TextBox">
<Setter Property="Background" Value="#252526"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#3E3E42"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="10"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<!-- CheckBox Style -->
<Style TargetType="CheckBox">
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="Margin" Value="0,6"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<!-- RadioButton Style -->
<Style TargetType="RadioButton">
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="Margin" Value="0,0,20,0"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<!-- Info Box Style -->
<Style x:Key="InfoBox" TargetType="Border">
<Setter Property="Background" Value="#2D2D30"/>
<Setter Property="BorderBrush" Value="#3E3E42"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="Padding" Value="15"/>
<Setter Property="Margin" Value="0,10,0,0"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Scrollable Content -->
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="30,20">
<!-- SEZIONE 1: Impostazioni Predefinite Aste -->
<Border Background="#252526"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Padding="20"
Margin="0,0,0,20">
<StackPanel>
<TextBlock Text="Impostazioni Predefinite Aste"
Style="{StaticResource SectionHeader}"/>
<TextBlock Text="Queste impostazioni verranno applicate automaticamente alle nuove aste."
Foreground="#999999"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,20"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Anticipo Puntata (millisecondi)" Foreground="#CCCCCC" Margin="0,10" VerticalAlignment="Center" ToolTip="Millisecondi prima della scadenza per puntare"/>
<TextBox Grid.Row="0" Grid.Column="1" x:Name="DefaultBidBeforeDeadlineMsTextBox" Text="200" Margin="10,10"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Verifica Stato Prima Di Puntare" Foreground="#CCCCCC" Margin="0,10" VerticalAlignment="Center" ToolTip="Controlla che l'asta sia ancora aperta prima di puntare"/>
<CheckBox Grid.Row="1" Grid.Column="1" x:Name="DefaultCheckAuctionOpenCheckBox" Margin="10,10" VerticalAlignment="Center"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Prezzo Minimo (€)" Foreground="#CCCCCC" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" x:Name="DefaultMinPriceTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Prezzo Massimo (€)" Foreground="#CCCCCC" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="3" Grid.Column="1" x:Name="DefaultMaxPriceTextBox" Text="0" Margin="10,10"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="Max Click" Foreground="#CCCCCC" Margin="0,10" VerticalAlignment="Center"/>
<TextBox Grid.Row="4" Grid.Column="1" x:Name="DefaultMaxClicksTextBox" Text="0" Margin="10,10"/>
</Grid>
</StackPanel>
</Border>
<!-- SEZIONE 2: Stato Iniziale Aste -->
<Border Background="#252526"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Padding="20"
Margin="0,0,0,20">
<StackPanel>
<TextBlock Text="Stato Iniziale Aste"
Style="{StaticResource SectionHeader}"/>
<TextBlock Text="Configura come devono comportarsi le aste quando vengono caricate o aggiunte."
Foreground="#999999"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,20"/>
<!-- Stato all'apertura applicazione -->
<TextBlock Text="Stato aste al caricamento dell'applicazione"
Style="{StaticResource FieldLabel}"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,20">
<RadioButton x:Name="LoadAuctionsStopped"
Content="Fermate"
GroupName="LoadState"
IsChecked="True"
ToolTip="Le aste salvate verranno caricate in stato fermo"/>
<RadioButton x:Name="LoadAuctionsPaused"
Content="In Pausa"
GroupName="LoadState"
ToolTip="Le aste salvate verranno caricate in pausa (pronte ad essere avviate)"/>
<RadioButton x:Name="LoadAuctionsActive"
Content="Attive"
GroupName="LoadState"
ToolTip="Le aste salvate verranno avviate automaticamente all'apertura"/>
<RadioButton x:Name="LoadAuctionsRemember"
Content="Ricorda Stato"
GroupName="LoadState"
ToolTip="Ogni asta ripristina lo stato che aveva alla chiusura (attiva/pausa/ferma)"/>
</StackPanel>
<!-- Stato nuove aste -->
<TextBlock Text="Stato iniziale di una nuova asta aggiunta"
Style="{StaticResource FieldLabel}"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<RadioButton x:Name="NewAuctionStopped"
Content="Fermata"
GroupName="NewAuctionState"
IsChecked="True"
ToolTip="Le nuove aste verranno aggiunte in stato fermo"/>
<RadioButton x:Name="NewAuctionPaused"
Content="In Pausa"
GroupName="NewAuctionState"
ToolTip="Le nuove aste verranno aggiunte in pausa"/>
<RadioButton x:Name="NewAuctionActive"
Content="Attiva"
GroupName="NewAuctionState"
ToolTip="Le nuove aste verranno avviate automaticamente"/>
</StackPanel>
<!-- Info Box -->
<Border Style="{StaticResource InfoBox}" Margin="0,15,0,0">
<StackPanel>
<TextBlock Text="Informazioni"
FontWeight="Bold"
Foreground="#007ACC"
Margin="0,0,0,10"/>
<TextBlock TextWrapping="Wrap"
Foreground="#CCCCCC"
FontSize="12"
LineHeight="18">
• <Bold>Fermata:</Bold> L'asta non viene monitorata fino all'avvio manuale.<LineBreak/>
• <Bold>In Pausa:</Bold> L'asta è pronta ma non punta automaticamente (utile per preparare le aste).<LineBreak/>
• <Bold>Attiva:</Bold> L'asta viene monitorata e punta automaticamente quando necessario.<LineBreak/>
• <Bold>Ricorda Stato:</Bold> Ogni asta ripristina lo stato esatto che aveva alla chiusura (SOVRASCRIVE le altre opzioni).<LineBreak/>
<LineBreak/>
<Bold>Consiglio:</Bold> Usa "Fermata" per caricare le aste senza avviarle, poi avvia manualmente quelle desiderate.<LineBreak/>
Usa "Ricorda Stato" per riprendere esattamente da dove avevi lasciato.
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
</Border>
<!-- SEZIONE 3: Protezione Account -->
<Border Background="#252526"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Padding="20"
Margin="0,0,0,20">
<StackPanel>
<TextBlock Text="Protezione Account"
Style="{StaticResource SectionHeader}"/>
<TextBlock Text="Impostazioni di sicurezza per proteggere il tuo account dalle puntate eccessive."
Foreground="#999999"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,20"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Puntate Minime da Mantenere -->
<TextBlock Grid.Row="0" Grid.Column="0"
Text="Puntate Minime da Mantenere"
Foreground="#CCCCCC"
Margin="0,10"
VerticalAlignment="Center"
ToolTip="Numero minimo di puntate residue da mantenere sull'account. Se > 0, non punterà se scende sotto questa soglia (0 = nessun limite)"/>
<TextBox Grid.Row="0" Grid.Column="1"
x:Name="MinimumRemainingBidsTextBox"
Text="0"
Margin="10,10"/>
</Grid>
<!-- Info Box -->
<Border Style="{StaticResource InfoBox}" Margin="0,15,0,0">
<StackPanel>
<TextBlock Text="🛡️ Protezione Puntate"
FontWeight="Bold"
Foreground="#00D800"
Margin="0,0,0,10"/>
<TextBlock TextWrapping="Wrap"
Foreground="#CCCCCC"
FontSize="12"
LineHeight="18">
• Se impostato > 0, il sistema non punterà se le puntate residue scenderebbero sotto questa soglia.<LineBreak/>
• Utile per mantenere sempre un "cuscinetto" di sicurezza sull'account.<LineBreak/>
• Nel banner principale apparirà un indicatore colorato: <LineBreak/>
- <Bold>Verde:</Bold> Puntate abbondanti (oltre +10 dal limite)<LineBreak/>
- <Bold>Giallo:</Bold> Vicino al limite (entro 10 puntate)<LineBreak/>
- <Bold>Rosso:</Bold> Al limite o sotto (puntate bloccate)<LineBreak/>
• Valore 0 = nessun limite (comportamento default).
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
</Border>
<!-- SEZIONE 4: Limiti Log -->
<Border Background="#252526"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Padding="20">
<StackPanel>
<TextBlock Text="Limiti Log"
Style="{StaticResource SectionHeader}"/>
<TextBlock Text="Configura il numero massimo di righe di log da mantenere in memoria per ottimizzare le performance."
Foreground="#999999"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,20"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Text="Max Righe Log per Asta"
Foreground="#CCCCCC"
Margin="0,10"
VerticalAlignment="Center"
ToolTip="Numero massimo di righe di log da mantenere per ogni singola asta (raccomandato: 500-1000)"/>
<TextBox Grid.Row="0" Grid.Column="1"
x:Name="MaxLogLinesPerAuctionTextBox"
Text="500"
Margin="10,10"/>
<TextBlock Grid.Row="1" Grid.Column="0"
Text="Max Righe Log Globale"
Foreground="#CCCCCC"
Margin="0,10"
VerticalAlignment="Center"
ToolTip="Numero massimo di righe di log da mantenere nel log globale dell'applicazione (raccomandato: 1000-2000)"/>
<TextBox Grid.Row="1" Grid.Column="1"
x:Name="MaxGlobalLogLinesTextBox"
Text="1000"
Margin="10,10"/>
<!-- 📊 NUOVO: Max Storia Puntate -->
<TextBlock Grid.Row="2" Grid.Column="0"
Text="Max Puntate da Visualizzare"
Foreground="#CCCCCC"
Margin="0,10"
VerticalAlignment="Center"
ToolTip="Numero massimo di puntate da mostrare nella scheda Storia Puntate (raccomandato: 20-50, 0 = tutte)"/>
<TextBox Grid.Row="2" Grid.Column="1"
x:Name="MaxBidHistoryEntriesTextBox"
Text="20"
Margin="10,10"/>
</Grid>
<!-- Info Box -->
<Border Style="{StaticResource InfoBox}" Margin="0,15,0,0">
<StackPanel>
<TextBlock Text="Informazioni"
FontWeight="Bold"
Foreground="#007ACC"
Margin="0,0,0,10"/>
<TextBlock TextWrapping="Wrap"
Foreground="#CCCCCC"
FontSize="12"
LineHeight="18">
• I log più vecchi verranno automaticamente rimossi quando si raggiunge il limite.<LineBreak/>
• Valori più bassi = meno memoria utilizzata, ma meno storico disponibile.<LineBreak/>
• Valori più alti = più storico disponibile, ma maggiore uso di memoria.<LineBreak/>
• Valori consigliati: 500-1000 per asta, 1000-2000 per log globale.
</TextBlock>
</StackPanel>
</Border>
</StackPanel>
</Border>
<!-- SEZIONE 5: Livello di Dettaglio Log -->
<Border Background="#252526"
BorderBrush="#3E3E42"
BorderThickness="1"
CornerRadius="4"
Padding="20"
Margin="0,20,0,0">
<StackPanel>
<TextBlock Text="Livello di Dettaglio Log"
Style="{StaticResource SectionHeader}"/>
<TextBlock Text="Configura il livello minimo dei messaggi da visualizzare nel log. Livelli più bassi mostrano solo messaggi critici, livelli più alti mostrano tutti i dettagli (utile per debug)."
Foreground="#999999"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,20"/>
<!-- Radio Buttons per livello log -->
<StackPanel>
<RadioButton x:Name="LogLevelErrorOnly"
Content="Solo Errori"
GroupName="LogLevel"
Margin="0,5"
ToolTip="Mostra solo errori critici (uso minimo per produzione)"/>
<RadioButton x:Name="LogLevelNormal"
Content="Normale (Errori + Avvisi)"
GroupName="LogLevel"
IsChecked="True"
Margin="0,5"
ToolTip="Mostra errori e avvisi (uso giornaliero raccomandato)"/>
<RadioButton x:Name="LogLevelInformational"
Content="Informativo (Include operazioni completate)"
GroupName="LogLevel"
Margin="0,5"
ToolTip="Mostra anche messaggi informativi e conferme (uso dettagliato)"/>
<RadioButton x:Name="LogLevelDebug"
Content="Debug (Include dettagli tecnici)"
GroupName="LogLevel"
Margin="0,5"
ToolTip="Mostra anche messaggi di debug per sviluppo"/>
<RadioButton x:Name="LogLevelTrace"
Content="Trace (Tutto - molto verboso)"
GroupName="LogLevel"
Margin="0,5"
ToolTip="Mostra ogni singola operazione (debug avanzato)"/>
</StackPanel>
<!-- Info Box -->
<Border Style="{StaticResource InfoBox}" Margin="0,15,0,0">
<StackPanel>
<TextBlock Text="🔍 Guida alla Scelta"
FontWeight="Bold"
Foreground="#FFB700"
Margin="0,0,0,10"/>
<TextBlock Foreground="#CCCCCC"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,5">
<Run>Solo Errori: Usa in produzione per vedere solo problemi critici.</Run>
</TextBlock>
<TextBlock Foreground="#CCCCCC"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,5">
<Run>Normale: Raccomandato per uso giornaliero. Mostra errori e avvisi importanti.</Run>
</TextBlock>
<TextBlock Foreground="#CCCCCC"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,5">
<Run>Informativo: Utile per seguire le operazioni principali (aggiunte aste, puntate).</Run>
</TextBlock>
<TextBlock Foreground="#CCCCCC"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,5">
<Run>Debug: Per sviluppo. Mostra parametri chiamate API e valori interni.</Run>
</TextBlock>
<TextBlock Foreground="#CCCCCC"
FontSize="12"
TextWrapping="Wrap"
Margin="0,0,0,10">
<Run>Trace: Debug avanzato. Mostra ogni singola chiamata (molto verboso).</Run>
</TextBlock>
<TextBlock Foreground="#CCCCCC"
FontSize="12"
FontWeight="Bold"
Margin="0,5,0,5">Legenda colori log:</TextBlock>
<StackPanel>
<TextBlock FontSize="11" Margin="0,2">
<Run Foreground="#E81123">■ ROSSO</Run>
<Run Foreground="#CCCCCC"> = Errori critici</Run>
</TextBlock>
<TextBlock FontSize="11" Margin="0,2">
<Run Foreground="#FFB700">■ ARANCIONE</Run>
<Run Foreground="#CCCCCC"> = Avvisi</Run>
</TextBlock>
<TextBlock FontSize="11" Margin="0,2">
<Run Foreground="#64B4FF">■ BLU</Run>
<Run Foreground="#CCCCCC"> = Informazioni</Run>
</TextBlock>
<TextBlock FontSize="11" Margin="0,2">
<Run Foreground="#00D800">■ VERDE</Run>
<Run Foreground="#CCCCCC"> = Operazioni riuscite</Run>
</TextBlock>
<TextBlock FontSize="11" Margin="0,2">
<Run Foreground="#FF8CFF">■ MAGENTA</Run>
<Run Foreground="#CCCCCC"> = Debug</Run>
</TextBlock>
<TextBlock FontSize="11" Margin="0,2">
<Run Foreground="#A0A0A0">■ GRIGIO</Run>
<Run Foreground="#CCCCCC"> = Trace</Run>
</TextBlock>
</StackPanel>
</StackPanel>
</Border>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<!-- Fixed Bottom Bar with Save/Cancel -->
<Border Grid.Row="1"
Background="#2D2D30"
BorderBrush="#3E3E42"
BorderThickness="0,1,0,0"
Padding="30,15">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Salva"
Background="#00D800"
Style="{StaticResource ModernButton}"
Margin="0,0,10,0"
Padding="40,10"
Click="SaveAllSettings_Click"/>
<Button Content="Annulla"
Background="#3E3E42"
Style="{StaticResource ModernButton}"
Padding="40,10"
Click="CancelAllSettings_Click"/>
</StackPanel>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,90 @@
using System.Windows;
using System.Windows.Controls;
namespace AutoBidder.Controls
{
/// <summary>
/// Interaction logic for SettingsControl.xaml
/// </summary>
public partial class SettingsControl : UserControl
{
public SettingsControl()
{
InitializeComponent();
}
// Non servono proprietà wrapper - MainWindow.xaml.cs accede direttamente ai controlli tramite:
// Settings.DefaultBidBeforeDeadlineMsTextBox (definito nel XAML con x:Name)
// Settings.MaxLogLinesPerAuctionTextBox (definito nel XAML con x:Name)
// etc.
// Proprietà per limiti log
public TextBox MaxLogLinesPerAuction => MaxLogLinesPerAuctionTextBox;
public TextBox MaxGlobalLogLines => MaxGlobalLogLinesTextBox;
// ?? NUOVO: Proprietà per limite storia puntate
public TextBox MaxBidHistoryEntries => MaxBidHistoryEntriesTextBox;
private void SaveDefaultsButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(SaveDefaultsClickedEvent, this));
}
private void CancelDefaultsButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(CancelDefaultsClickedEvent, this));
}
// Nuovo evento unificato - SALVA TUTTE LE IMPOSTAZIONI
private void SaveAllSettings_Click(object sender, RoutedEventArgs e)
{
try
{
// Salva impostazioni predefinite aste (export rimosso)
RaiseEvent(new RoutedEventArgs(SaveDefaultsClickedEvent, this));
// UNICO MessageBox di conferma
MessageBox.Show(
"Tutte le impostazioni sono state salvate con successo.\n\nLe nuove impostazioni verranno applicate alle aste future.",
"Impostazioni Salvate",
MessageBoxButton.OK,
MessageBoxImage.Information
);
}
catch (System.Exception ex)
{
MessageBox.Show(
"Errore durante il salvataggio: " + ex.Message,
"Errore",
MessageBoxButton.OK,
MessageBoxImage.Error
);
}
}
private void CancelAllSettings_Click(object sender, RoutedEventArgs e)
{
// Annulla tutte le modifiche
RaiseEvent(new RoutedEventArgs(CancelDefaultsClickedEvent, this));
}
// Routed Events
public static readonly RoutedEvent SaveDefaultsClickedEvent = EventManager.RegisterRoutedEvent(
"SaveDefaultsClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SettingsControl));
public static readonly RoutedEvent CancelDefaultsClickedEvent = EventManager.RegisterRoutedEvent(
"CancelDefaultsClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SettingsControl));
public event RoutedEventHandler SaveDefaultsClicked
{
add { AddHandler(SaveDefaultsClickedEvent, value); }
remove { RemoveHandler(SaveDefaultsClickedEvent, value); }
}
public event RoutedEventHandler CancelDefaultsClicked
{
add { AddHandler(CancelDefaultsClickedEvent, value); }
remove { RemoveHandler(CancelDefaultsClickedEvent, value); }
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,135 @@
<UserControl x:Class="AutoBidder.Controls.StatisticsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1200"
Background="#1E1E1E">
<UserControl.Resources>
<Style x:Key="RoundedButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="8"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="15,10"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<Border Grid.Row="0" Background="#2D2D30" Padding="15" BorderBrush="#3E3E42" BorderThickness="0,0,0,1">
<Grid>
<TextBlock Text="📊 Dati Statistici - Analisi Aste Chiuse"
Foreground="#00D800"
FontSize="16"
FontWeight="Bold"
VerticalAlignment="Center"/>
<Button x:Name="LoadClosedAuctionsButton"
Content="🔄 Carica Statistiche"
HorizontalAlignment="Right"
Background="#007ACC"
Style="{StaticResource RoundedButton}"
Click="LoadClosedAuctionsButton_Click"/>
</Grid>
</Border>
<!-- DataGrid Statistiche -->
<DataGrid Grid.Row="1"
x:Name="StatsDataGrid"
AutoGenerateColumns="False"
IsReadOnly="True"
Background="#1E1E1E"
Foreground="#CCCCCC"
RowBackground="#1E1E1E"
AlternatingRowBackground="#252526"
GridLinesVisibility="Horizontal"
HeadersVisibility="Column"
BorderThickness="0"
Margin="15">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#2D2D30"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Padding" Value="10,8"/>
<Setter Property="BorderThickness" Value="0,0,1,1"/>
<Setter Property="BorderBrush" Value="#3E3E42"/>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#CCCCCC"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Prodotto" Binding="{Binding ProductName}" Width="3*"/>
<DataGridTextColumn Header="Prezzo Medio" Binding="{Binding AverageFinalPrice, StringFormat=€{0:F2}}" Width="120"/>
<DataGridTextColumn Header="Click Medi" Binding="{Binding AverageBidsUsed, StringFormat={}{0:F0}}" Width="100"/>
<DataGridTextColumn Header="Vincitore Frequente" Binding="{Binding Winner}" Width="150"/>
<DataGridTextColumn Header="# Aste" Binding="{Binding Count}" Width="80"/>
</DataGrid.Columns>
</DataGrid>
<!-- Footer: Status -->
<Border Grid.Row="2"
Background="#252526"
Padding="15"
BorderBrush="#3E3E42"
BorderThickness="0,1,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock x:Name="StatsStatusText"
Text="Pronto per caricare statistiche"
FontSize="13"
Foreground="#CCCCCC"
VerticalAlignment="Center"/>
<TextBlock x:Name="ExportProgressText"
Text=""
FontSize="11"
Foreground="#999999"
Margin="0,5,0,0"
Visibility="Collapsed"/>
</StackPanel>
<ProgressBar Grid.Column="1"
x:Name="ExportProgressBar"
Width="200"
Height="20"
IsIndeterminate="True"
Foreground="#007ACC"
Background="#1E1E1E"
BorderBrush="#3E3E42"
Visibility="Collapsed"/>
</Grid>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,31 @@
using System.Windows;
using System.Windows.Controls;
namespace AutoBidder.Controls
{
/// <summary>
/// Interaction logic for StatisticsControl.xaml
/// </summary>
public partial class StatisticsControl : UserControl
{
public StatisticsControl()
{
InitializeComponent();
}
private void LoadClosedAuctionsButton_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(LoadClosedAuctionsClickedEvent, this));
}
// Routed Events
public static readonly RoutedEvent LoadClosedAuctionsClickedEvent = EventManager.RegisterRoutedEvent(
"LoadClosedAuctionsClicked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(StatisticsControl));
public event RoutedEventHandler LoadClosedAuctionsClicked
{
add { AddHandler(LoadClosedAuctionsClickedEvent, value); }
remove { RemoveHandler(LoadClosedAuctionsClickedEvent, value); }
}
}
}

View File

@@ -0,0 +1,163 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Web.WebView2.Core;
namespace AutoBidder
{
/// <summary>
/// Browser event handlers and navigation
/// </summary>
public partial class MainWindow
{
private void BrowserBackButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (EmbeddedWebView?.CoreWebView2 != null && EmbeddedWebView.CoreWebView2.CanGoBack)
EmbeddedWebView.CoreWebView2.GoBack();
}
catch { }
}
private void BrowserForwardButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (EmbeddedWebView?.CoreWebView2 != null && EmbeddedWebView.CoreWebView2.CanGoForward)
EmbeddedWebView.CoreWebView2.GoForward();
}
catch { }
}
private void BrowserRefreshButton_Click(object sender, RoutedEventArgs e)
{
try
{
EmbeddedWebView?.Reload();
}
catch { }
}
private void BrowserHomeButton_Click(object sender, RoutedEventArgs e)
{
try
{
EmbeddedWebView?.CoreWebView2?.Navigate("https://it.bidoo.com/");
BrowserAddress.Text = "https://it.bidoo.com/";
}
catch { }
}
private void BrowserAddAuctionButton_Click(object sender, RoutedEventArgs e)
{
try
{
var url = BrowserAddress.Text?.Trim() ?? EmbeddedWebView?.Source?.ToString();
if (!string.IsNullOrEmpty(url))
_ = AddAuctionFromUrl(url);
}
catch { }
}
private void EmbeddedWebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e)
{
try
{
BrowserAddress.Text = e.Uri ?? string.Empty;
var btn = this.FindName("BrowserAddAuctionButton") as Button;
if (btn != null)
btn.IsEnabled = IsValidAuctionUrl(e.Uri ?? string.Empty);
}
catch { }
}
private void EmbeddedWebView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
{
try
{
var uri = EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text;
BrowserAddress.Text = uri;
var btn = this.FindName("BrowserAddAuctionButton") as Button;
if (btn != null)
btn.IsEnabled = IsValidAuctionUrl(uri);
}
catch { }
}
private void EmbeddedWebView_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
try
{
e.Handled = true;
}
catch { }
}
private void CoreWebView2_ContextMenuRequested(object? sender, CoreWebView2ContextMenuRequestedEventArgs e)
{
try
{
// Prevent default native menu
e.Handled = true;
var target = e.ContextMenuTarget;
string? link = null;
try
{
link = target?.LinkUri;
if (string.IsNullOrEmpty(link)) link = target?.PageUri;
}
catch { }
// Show WPF ContextMenu on UI thread
Dispatcher.BeginInvoke(new Action(() =>
{
try
{
var menu = new ContextMenu();
var canAdd = !string.IsNullOrEmpty(link) || IsValidAuctionUrl(EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text);
var addItem = new MenuItem { Header = "Aggiungi Asta", IsEnabled = canAdd };
addItem.Click += async (s, args) =>
{
try
{
string? urlToAdd = link;
if (string.IsNullOrEmpty(urlToAdd))
urlToAdd = EmbeddedWebView?.Source?.ToString() ?? BrowserAddress.Text;
if (!string.IsNullOrEmpty(urlToAdd))
{
await AddAuctionFromUrl(urlToAdd);
}
}
catch (Exception ex)
{
Log($"[ERRORE] Aggiungi Asta dal menu: {ex.Message}");
}
};
menu.Items.Add(addItem);
var copyLink = new MenuItem { Header = "Copia link", IsEnabled = !string.IsNullOrEmpty(link) };
copyLink.Click += (s, args) =>
{
try { if (!string.IsNullOrEmpty(link)) Clipboard.SetText(link); }
catch { }
};
menu.Items.Add(copyLink);
menu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
menu.IsOpen = true;
}
catch { }
}));
}
catch { }
}
}
}

View File

@@ -0,0 +1,321 @@
using System;
using System.Linq;
using System.Windows;
using AutoBidder.Utilities;
namespace AutoBidder
{
/// <summary>
/// Settings and configuration event handlers - REFACTORED
/// </summary>
public partial class MainWindow
{
/// <summary>
/// Carica TUTTE le impostazioni salvate nei controlli UI
/// </summary>
private void LoadDefaultSettings()
{
try
{
var settings = Utilities.SettingsManager.Load();
// Carica impostazioni predefinite aste
DefaultBidBeforeDeadlineMs.Text = settings.DefaultBidBeforeDeadlineMs.ToString();
DefaultCheckAuctionOpen.IsChecked = settings.DefaultCheckAuctionOpenBeforeBid;
DefaultMinPrice.Text = settings.DefaultMinPrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
DefaultMaxPrice.Text = settings.DefaultMaxPrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
DefaultMaxClicks.Text = settings.DefaultMaxClicks.ToString();
// Carica limiti log
Settings.MaxLogLinesPerAuctionTextBox.Text = settings.MaxLogLinesPerAuction.ToString();
Settings.MaxGlobalLogLinesTextBox.Text = settings.MaxGlobalLogLines.ToString();
// ?? NUOVO: Carica limite storia puntate
Settings.MaxBidHistoryEntriesTextBox.Text = settings.MaxBidHistoryEntries.ToString();
// ?? NUOVO: Carica limite minimo puntate
MinimumRemainingBidsTextBox.Text = settings.MinimumRemainingBids.ToString();
// ?? NUOVO: Carica livello log
var logLevelErrorOnly = Settings.FindName("LogLevelErrorOnly") as System.Windows.Controls.RadioButton;
var logLevelNormal = Settings.FindName("LogLevelNormal") as System.Windows.Controls.RadioButton;
var logLevelInformational = Settings.FindName("LogLevelInformational") as System.Windows.Controls.RadioButton;
var logLevelDebug = Settings.FindName("LogLevelDebug") as System.Windows.Controls.RadioButton;
var logLevelTrace = Settings.FindName("LogLevelTrace") as System.Windows.Controls.RadioButton;
switch (settings.MinLogLevel)
{
case "ErrorOnly":
if (logLevelErrorOnly != null) logLevelErrorOnly.IsChecked = true;
break;
case "Informational":
if (logLevelInformational != null) logLevelInformational.IsChecked = true;
break;
case "Debug":
if (logLevelDebug != null) logLevelDebug.IsChecked = true;
break;
case "Trace":
if (logLevelTrace != null) logLevelTrace.IsChecked = true;
break;
case "Normal":
default:
if (logLevelNormal != null) logLevelNormal.IsChecked = true;
break;
}
// Aggiorna indicatore visivo
UpdateMinBidsIndicator(settings.MinimumRemainingBids);
// Carica stato iniziale aste
// ? NUOVO: Se RememberAuctionStates è attivo, seleziona "Ricorda Stato"
if (settings.RememberAuctionStates)
{
Settings.LoadAuctionsRemember.IsChecked = true;
}
else
{
// Altrimenti usa DefaultStartAuctionsOnLoad
switch (settings.DefaultStartAuctionsOnLoad)
{
case "Active":
Settings.LoadAuctionsActive.IsChecked = true;
break;
case "Paused":
Settings.LoadAuctionsPaused.IsChecked = true;
break;
case "Stopped":
default:
Settings.LoadAuctionsStopped.IsChecked = true;
break;
}
}
switch (settings.DefaultNewAuctionState)
{
case "Active":
Settings.NewAuctionActive.IsChecked = true;
break;
case "Paused":
Settings.NewAuctionPaused.IsChecked = true;
break;
case "Stopped":
default:
Settings.NewAuctionStopped.IsChecked = true;
break;
}
Log($"[OK] Impostazioni caricate: Anticipo={settings.DefaultBidBeforeDeadlineMs}ms, LogAsta={settings.MaxLogLinesPerAuction}, LogGlobale={settings.MaxGlobalLogLines}, MinBids={settings.MinimumRemainingBids}", Utilities.LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Caricamento impostazioni predefinite: {ex.Message}", Utilities.LogLevel.Error);
}
}
private void SaveDefaultsButton_Click(object sender, RoutedEventArgs e)
{
try
{
// ? Carica le impostazioni esistenti per non perdere gli altri valori
var settings = Utilities.SettingsManager.Load() ?? new Utilities.AppSettings();
// === SEZIONE DEFAULTS: Validazione e Salvataggio ===
if (int.TryParse(DefaultBidBeforeDeadlineMs.Text, out var bidMs) && bidMs >= 0 && bidMs <= 5000)
{
settings.DefaultBidBeforeDeadlineMs = bidMs;
}
else
{
Log("[ERRORE] Valore anticipo puntata non valido (deve essere 0-5000ms)", LogLevel.Error);
return;
}
settings.DefaultCheckAuctionOpenBeforeBid = DefaultCheckAuctionOpen.IsChecked ?? false;
if (double.TryParse(DefaultMinPrice.Text.Replace(',', '.'), System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out var minPrice))
{
settings.DefaultMinPrice = minPrice;
}
if (double.TryParse(DefaultMaxPrice.Text.Replace(',', '.'), System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out var maxPrice))
{
settings.DefaultMaxPrice = maxPrice;
}
if (int.TryParse(DefaultMaxClicks.Text, out var maxClicks))
{
settings.DefaultMaxClicks = maxClicks;
}
// === SEZIONE DEFAULTS: Limiti Log ===
if (int.TryParse(Settings.MaxLogLinesPerAuctionTextBox.Text, out var maxLogPerAuction) && maxLogPerAuction > 0)
{
settings.MaxLogLinesPerAuction = maxLogPerAuction;
}
else
{
Log("[ERRORE] Valore max log per asta non valido (deve essere > 0)", LogLevel.Error);
}
if (int.TryParse(Settings.MaxGlobalLogLinesTextBox.Text, out var maxGlobalLog) && maxGlobalLog > 0)
{
settings.MaxGlobalLogLines = maxGlobalLog;
}
else
{
Log("[ERRORE] Valore max log globale non valido (deve essere > 0)", LogLevel.Error);
}
// ?? NUOVO: Salva limite storia puntate
if (int.TryParse(Settings.MaxBidHistoryEntriesTextBox.Text, out var maxBidHistory) && maxBidHistory >= 0)
{
settings.MaxBidHistoryEntries = maxBidHistory;
if (maxBidHistory > 0)
{
Log($"[HISTORY] Impostato limite storia puntate: {maxBidHistory}", LogLevel.Info);
}
else
{
Log("[HISTORY] Limite storia puntate disabilitato (mostra tutte)", LogLevel.Info);
}
}
else
{
Log("[ERRORE] Valore limite storia puntate non valido (deve essere >= 0)", LogLevel.Error);
}
// ?? NUOVO: Salva limite minimo puntate
if (int.TryParse(MinimumRemainingBidsTextBox.Text, out var minBids) && minBids >= 0)
{
settings.MinimumRemainingBids = minBids;
// Aggiorna indicatore visivo
UpdateMinBidsIndicator(minBids);
if (minBids > 0)
{
Log($"[LIMIT] Impostato limite minimo puntate: {minBids}", LogLevel.Info);
}
}
else
{
Log("[ERRORE] Valore limite minimo puntate non valido (deve essere >= 0)", LogLevel.Error);
}
// ?? NUOVO: Salva livello log
var logLevelErrorOnly = Settings.FindName("LogLevelErrorOnly") as System.Windows.Controls.RadioButton;
var logLevelNormal = Settings.FindName("LogLevelNormal") as System.Windows.Controls.RadioButton;
var logLevelInformational = Settings.FindName("LogLevelInformational") as System.Windows.Controls.RadioButton;
var logLevelDebug = Settings.FindName("LogLevelDebug") as System.Windows.Controls.RadioButton;
var logLevelTrace = Settings.FindName("LogLevelTrace") as System.Windows.Controls.RadioButton;
string selectedLogLevel = "Normal"; // Default
if (logLevelErrorOnly?.IsChecked == true)
selectedLogLevel = "ErrorOnly";
else if (logLevelInformational?.IsChecked == true)
selectedLogLevel = "Informational";
else if (logLevelDebug?.IsChecked == true)
selectedLogLevel = "Debug";
else if (logLevelTrace?.IsChecked == true)
selectedLogLevel = "Trace";
else if (logLevelNormal?.IsChecked == true)
selectedLogLevel = "Normal";
settings.MinLogLevel = selectedLogLevel;
Log($"[LOG] Livello log impostato: {selectedLogLevel}", LogLevel.Info);
// === SEZIONE DEFAULTS: Stati Iniziali Aste ===
var loadAuctionsRemember = Settings.FindName("LoadAuctionsRemember") as System.Windows.Controls.RadioButton;
var loadAuctionsActive = Settings.FindName("LoadAuctionsActive") as System.Windows.Controls.RadioButton;
var loadAuctionsPaused = Settings.FindName("LoadAuctionsPaused") as System.Windows.Controls.RadioButton;
// ? NUOVO: Gestione "Ricorda Stato"
if (loadAuctionsRemember?.IsChecked == true)
{
// Attiva RememberAuctionStates
settings.RememberAuctionStates = true;
// DefaultStartAuctionsOnLoad diventa irrilevante, ma lo lasciamo a "Stopped" per compatibilità
settings.DefaultStartAuctionsOnLoad = "Stopped";
}
else
{
// Disattiva RememberAuctionStates e usa DefaultStartAuctionsOnLoad
settings.RememberAuctionStates = false;
settings.DefaultStartAuctionsOnLoad = loadAuctionsActive?.IsChecked == true ? "Active" :
loadAuctionsPaused?.IsChecked == true ? "Paused" :
"Stopped";
}
var newAuctionActive = Settings.FindName("NewAuctionActive") as System.Windows.Controls.RadioButton;
var newAuctionPaused = Settings.FindName("NewAuctionPaused") as System.Windows.Controls.RadioButton;
settings.DefaultNewAuctionState = newAuctionActive?.IsChecked == true ? "Active" :
newAuctionPaused?.IsChecked == true ? "Paused" :
"Stopped";
Utilities.SettingsManager.Save(settings);
}
catch (Exception ex)
{
Log($"[ERRORE] Salvataggio impostazioni: {ex.Message}", LogLevel.Error);
}
}
private void CancelDefaultsButton_Click(object sender, RoutedEventArgs e)
{
try
{
// Ricarica defaults salvati
LoadDefaultSettings();
MessageBox.Show(this, "Impostazioni predefinite ripristinate.", "Annulla", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
Log($"[ERRORE] Ripristino impostazioni: {ex.Message}", LogLevel.Error);
MessageBox.Show(this, "Errore durante ripristino: " + ex.Message, "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// === HANDLER PER PULSANTI UNIFICATI ===
private void SaveAllSettings_Click(object sender, RoutedEventArgs e)
{
try
{
// Salva tutte le impostazioni (ora solo defaults, export rimosso)
SaveDefaultsButton_Click(sender, e);
MessageBox.Show(
"Tutte le impostazioni sono state salvate con successo.\n\nLe nuove impostazioni verranno applicate alle aste future.",
"Impostazioni Salvate",
MessageBoxButton.OK,
MessageBoxImage.Information
);
}
catch (Exception ex)
{
Log($"[ERRORE] Salvataggio impostazioni: {ex.Message}", LogLevel.Error);
MessageBox.Show(this, "Errore durante salvataggio: " + ex.Message, "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void CancelAllSettings_Click(object sender, RoutedEventArgs e)
{
try
{
// Annulla tutte le modifiche
LoadDefaultSettings();
MessageBox.Show(this, "Impostazioni ripristinate alle ultime salvate.", "Annulla", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
Log($"[ERRORE] Ripristino impostazioni: {ex.Message}", LogLevel.Error);
MessageBox.Show(this, "Errore durante ripristino: " + ex.Message, "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}

View File

@@ -0,0 +1,271 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Xml.Linq;
using AutoBidder.Models;
using AutoBidder.Utilities;
using Microsoft.EntityFrameworkCore;
namespace AutoBidder
{
/// <summary>
/// Statistics and closed auctions event handlers
/// NOTA: Funzionalità statistiche temporaneamente disabilitate - in sviluppo
/// </summary>
public partial class MainWindow
{
private void ExportStatsButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this, "Funzionalità statistiche in sviluppo", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
}
private async void LoadClosedAuctionsButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this, "Funzionalità statistiche in sviluppo", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
/* CODICE TEMPORANEAMENTE DISABILITATO - Statistiche in sviluppo
try
{
StatsStatusText.Text = "Avvio caricamento statistiche...";
var settings = Utilities.SettingsManager.Load();
if (settings == null || string.IsNullOrWhiteSpace(settings.ExportPath) || !Directory.Exists(settings.ExportPath))
{
MessageBox.Show(this, "Percorso export non configurato o non valido. Configuralo nelle impostazioni.", "Carica Statistiche", MessageBoxButton.OK, MessageBoxImage.Warning);
StatsStatusText.Text = "Percorso export non valido";
return;
}
ExportProgressBar.Visibility = Visibility.Visible;
ExportProgressText.Visibility = Visibility.Visible;
ExportProgressText.Text = "Caricamento statistiche...";
var folder = settings.ExportPath!;
var files = Directory.GetFiles(folder, "auction_*.*");
if (files.Length == 0)
{
MessageBox.Show(this, "Nessun file di aste trovato nella cartella di export.", "Carica Statistiche", MessageBoxButton.OK, MessageBoxImage.Information);
StatsStatusText.Text = "Nessun file trovato";
ExportProgressBar.Visibility = Visibility.Collapsed;
ExportProgressText.Visibility = Visibility.Collapsed;
return;
}
var aggregated = new Dictionary<string, List<ClosedAuctionRecord>>(StringComparer.OrdinalIgnoreCase);
await Task.Run(() =>
{
foreach (var f in files)
{
try
{
var ext = Path.GetExtension(f).ToLowerInvariant();
if (ext == ".json")
{
var txt = File.ReadAllText(f, Encoding.UTF8);
try
{
var rec = System.Text.Json.JsonSerializer.Deserialize<ClosedAuctionRecord>(txt);
if (rec != null)
{
var key = (rec.ProductName ?? ExtractProductFromFilename(f) ?? "<unknown>").Trim();
if (!aggregated.ContainsKey(key)) aggregated[key] = new List<ClosedAuctionRecord>();
aggregated[key].Add(rec);
continue;
}
}
catch { }
try
{
var arr = System.Text.Json.JsonSerializer.Deserialize<List<ClosedAuctionRecord>>(txt);
if (arr != null)
{
foreach (var r in arr)
{
var key = (r.ProductName ?? ExtractProductFromFilename(f) ?? "<unknown>").Trim();
if (!aggregated.ContainsKey(key)) aggregated[key] = new List<ClosedAuctionRecord>();
aggregated[key].Add(r);
}
}
}
catch { }
}
else if (ext == ".xml")
{
try
{
var doc = XDocument.Load(f);
var auctionElems = doc.Descendants("Auction");
if (!auctionElems.Any()) auctionElems = doc.Descendants("AuctionExport");
foreach (var n in auctionElems)
{
var name = n.Descendants("Name").FirstOrDefault()?.Value ?? n.Descendants("ProductName").FirstOrDefault()?.Value;
double d = 0; double.TryParse(n.Descendants("FinalPrice").FirstOrDefault()?.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out d);
int bids = 0; int.TryParse(n.Descendants("TotalBids").FirstOrDefault()?.Value, out bids);
var winner = n.Descendants("Winner").FirstOrDefault()?.Value ?? string.Empty;
var url = n.Descendants("OriginalUrl").FirstOrDefault()?.Value ?? string.Empty;
var rec = new ClosedAuctionRecord { ProductName = name, FinalPrice = d == 0 ? null : (double?)d, Winner = winner, BidsUsed = bids, AuctionUrl = url };
var key = (rec.ProductName ?? ExtractProductFromFilename(f) ?? "<unknown>").Trim();
if (!aggregated.ContainsKey(key)) aggregated[key] = new List<ClosedAuctionRecord>();
aggregated[key].Add(rec);
}
}
catch { }
}
else // CSV or text
{
try
{
var lines = File.ReadAllLines(f, Encoding.UTF8);
string product = ExtractProductFromFilename(f) ?? "<unknown>";
double? price = null; int? bids = null; string winner = string.Empty; string url = string.Empty;
foreach (var l in lines)
{
var line = l.Trim();
if (line.StartsWith("Name,") || line.StartsWith("ProductName,"))
{
var parts = line.Split(',', 2);
if (parts.Length == 2) product = parts[1].Trim('"');
}
else if (line.StartsWith("FinalPrice", StringComparison.OrdinalIgnoreCase) || line.StartsWith("Price,"))
{
var parts = line.Split(',', 2);
if (parts.Length == 2 && double.TryParse(parts[1].Trim('"').Replace('€', ' ').Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var p)) price = p;
}
else if (line.StartsWith("TotalBids", StringComparison.OrdinalIgnoreCase) || line.StartsWith("BidsUsed", StringComparison.OrdinalIgnoreCase))
{
var parts = line.Split(',', 2);
if (parts.Length == 2 && int.TryParse(parts[1].Trim('"'), out var b)) bids = b;
}
else if (line.StartsWith("Winner", StringComparison.OrdinalIgnoreCase))
{
var parts = line.Split(',', 2);
if (parts.Length == 2) winner = parts[1].Trim('"');
}
else if (line.StartsWith("OriginalUrl", StringComparison.OrdinalIgnoreCase) || line.StartsWith("AuctionUrl", StringComparison.OrdinalIgnoreCase))
{
var parts = line.Split(',', 2);
if (parts.Length == 2) url = parts[1].Trim('"');
}
}
var rec = new ClosedAuctionRecord { ProductName = product, FinalPrice = price, BidsUsed = bids, Winner = winner, AuctionUrl = url };
var key = (rec.ProductName ?? ExtractProductFromFilename(f) ?? "<unknown>").Trim();
if (!aggregated.ContainsKey(key)) aggregated[key] = new List<ClosedAuctionRecord>();
aggregated[key].Add(rec);
}
catch { }
}
}
catch { }
}
});
var stats = new List<object>();
foreach (var kv in aggregated)
{
var list = kv.Value.Where(x => x.FinalPrice.HasValue || x.BidsUsed.HasValue).ToList();
if (list.Count == 0) continue;
var avgPrice = list.Where(x => x.FinalPrice.HasValue).Select(x => x.FinalPrice!.Value).DefaultIfEmpty(0).Average();
var avgBids = list.Where(x => x.BidsUsed.HasValue).Select(x => x.BidsUsed!.Value).DefaultIfEmpty(0).Average();
var winner = list.Where(x => !string.IsNullOrEmpty(x.Winner)).GroupBy(x => x.Winner).OrderByDescending(g => g.Count()).Select(g => g.Key).FirstOrDefault() ?? string.Empty;
var example = list.FirstOrDefault(x => !string.IsNullOrEmpty(x.AuctionUrl))?.AuctionUrl ?? string.Empty;
stats.Add(new
{
ProductName = kv.Key,
FinalPrice = avgPrice,
Winner = winner,
BidsUsed = (int)Math.Round(avgBids),
AuctionUrl = example,
Count = list.Count,
AverageFinalPrice = avgPrice,
AverageBidsUsed = avgBids
});
}
Dispatcher.Invoke(() =>
{
StatsDataGrid.ItemsSource = stats.OrderByDescending(s => (int)s.GetType().GetProperty("Count")!.GetValue(s)).ToList();
StatsStatusText.Text = $"Caricati {stats.Count} prodotti ({files.Length} file analizzati)";
ExportProgressBar.Visibility = Visibility.Collapsed;
ExportProgressText.Visibility = Visibility.Collapsed;
});
}
catch (Exception ex)
{
StatsStatusText.Text = "Errore caricamento statistiche";
Log($"[ERRORE] Carica statistiche: {ex.Message}", LogLevel.Error);
MessageBox.Show(this, "Errore durante caricamento statistiche: " + ex.Message, "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
ExportProgressBar.Visibility = Visibility.Collapsed;
ExportProgressText.Visibility = Visibility.Collapsed;
}
*/
}
private static string? ExtractProductFromFilename(string path)
{
try
{
var name = Path.GetFileNameWithoutExtension(path);
var m = Regex.Match(name, @"auction_(.+)");
if (m.Success)
{
var v = m.Groups[1].Value;
if (Regex.IsMatch(v, "^\\d+$")) return null;
return v.Replace('_', ' ');
}
return null;
}
catch { return null; }
}
private async void ApplyInsightsButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this, "Funzionalità statistiche in sviluppo", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
/* CODICE TEMPORANEAMENTE DISABILITATO
try
{
if (_selectedAuction == null)
{
MessageBox.Show(this, "Seleziona un'asta prima di applicare le raccomandazioni.", "Applica Raccomandazioni", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var optionsBuilder = new Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<Data.StatisticsContext>();
var dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "stats.db");
optionsBuilder.UseSqlite($"Data Source={dbPath}");
using var ctx = new Data.StatisticsContext(optionsBuilder.Options);
var svc = new Services.StatsService(ctx);
var (recBids, recPrice) = await svc.GetRecommendationAsync(_selectedAuction.AuctionInfo.Name, _selectedAuction.AuctionInfo.OriginalUrl);
_selectedAuction.MaxClicks = Math.Max(_selectedAuction.MaxClicks, recBids);
_selectedAuction.MaxPrice = Math.Max(_selectedAuction.MaxPrice, recPrice);
Log($"[OK] Raccomandazioni: MaxClicks={recBids}, MaxPrice={recPrice:F2} applicate a {_selectedAuction.Name}", LogLevel.Success);
UpdateSelectedAuctionDetails(_selectedAuction);
}
catch (Exception ex)
{
Log($"[ERRORE] ApplyInsights: {ex.Message}", LogLevel.Error);
MessageBox.Show(this, "Errore applicazione raccomandazioni: " + ex.Message, "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
*/
}
private void FreeBidsStart_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this, "Funzionalità non ancora implementata", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
}
private void FreeBidsStop_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this, "Funzionalità non ancora implementata", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Windows;
using System.Windows.Input;
using Microsoft.Web.WebView2.Core;
namespace AutoBidder
{
/// <summary>
/// Stub event handlers for XAML binding - actual implementations are in dedicated partial files
/// </summary>
public partial class MainWindow
{
// These methods exist only to satisfy XAML event bindings
// The actual implementations are in the appropriate partial class files:
// - MainWindow.ButtonHandlers.cs for button clicks
// - MainWindow.EventHandlers.Browser.cs for browser events
// - MainWindow.EventHandlers.Export.cs for export events
// - MainWindow.EventHandlers.Settings.cs for settings events
// - MainWindow.EventHandlers.Stats.cs for statistics events
private void MultiAuctionsGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
// Optional: Add keyboard shortcuts for grid navigation
}
}
}

View File

@@ -0,0 +1,657 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using AutoBidder.Models;
using AutoBidder.ViewModels;
using AutoBidder.Utilities;
using AutoBidder.Services; // ? AGGIUNTO per RequestPriority e HtmlResponse
namespace AutoBidder
{
/// <summary>
/// Auction management: Add, Remove, Update
/// </summary>
public partial class MainWindow
{
private async Task AddAuctionById(string input)
{
try
{
if (string.IsNullOrWhiteSpace(input))
{
MessageBox.Show("Input non valido!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
string auctionId;
string? productName = null;
string originalUrl;
// Verifica se è un URL o solo un ID
if (input.Contains("bidoo.com") || input.Contains("http"))
{
// È un URL - estrai ID e nome prodotto dall'URL stesso
originalUrl = input.Trim();
auctionId = ExtractAuctionId(originalUrl);
if (string.IsNullOrEmpty(auctionId))
{
MessageBox.Show("Impossibile estrarre ID dall'URL!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
productName = ExtractProductName(originalUrl);
}
else
{
// È solo un ID numerico - costruisci URL generico
auctionId = input.Trim();
originalUrl = $"https://it.bidoo.com/auction.php?a=asta_{auctionId}";
}
// Verifica duplicati
if (_auctionViewModels.Any(a => a.AuctionId == auctionId))
{
MessageBox.Show("Asta già monitorata!", "Duplicato", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// ? MODIFICATO: Nome senza ID (già nella colonna separata)
var displayName = string.IsNullOrEmpty(productName)
? $"Asta {auctionId}"
: DecodeAllHtmlEntities(productName);
// CARICA IMPOSTAZIONI PREDEFINITE SALVATE
var settings = Utilities.SettingsManager.Load();
// ? Determina stato iniziale dalla configurazione
bool isActive = false;
bool isPaused = false;
switch (settings.DefaultNewAuctionState)
{
case "Active":
isActive = true;
isPaused = false;
break;
case "Paused":
isActive = true;
isPaused = true;
break;
case "Stopped":
default:
isActive = false;
isPaused = false;
break;
}
// Crea model con valori dalle impostazioni salvate e stato configurato
var auction = new AuctionInfo
{
AuctionId = auctionId,
Name = DecodeAllHtmlEntities(displayName),
OriginalUrl = originalUrl,
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs,
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
IsActive = isActive,
IsPaused = isPaused
};
// Aggiungi al monitor
_auctionMonitor.AddAuction(auction);
// Crea ViewModel con valori dalle impostazioni
var vm = new AuctionViewModel(auction)
{
MinPrice = settings.DefaultMinPrice,
MaxPrice = settings.DefaultMaxPrice,
MaxClicks = settings.DefaultMaxClicks
};
_auctionViewModels.Add(vm);
// ? Auto-start del monitoraggio se l'asta è attiva e il monitoraggio è fermo
if (isActive && !_isAutomationActive)
{
_auctionMonitor.Start();
_isAutomationActive = true;
Log($"[AUTO-START] Monitoraggio avviato automaticamente per nuova asta: {vm.Name}", LogLevel.Info);
}
SaveAuctions();
UpdateTotalCount();
UpdateGlobalControlButtons();
var stateText = isActive ? (isPaused ? "Paused" : "Active") : "Stopped";
Log($"[ADD] Asta aggiunta con stato={stateText}, Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", Utilities.LogLevel.Info);
// ? NUOVO: Se il nome non è stato estratto, recuperalo in background DOPO l'aggiunta
if (string.IsNullOrEmpty(productName))
{
_ = FetchAuctionNameInBackgroundAsync(auction, vm);
}
}
catch (Exception ex)
{
Log($"Errore aggiunta asta: {ex.Message}");
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Recupera il nome dell'asta in background e aggiorna l'UI quando completa
/// </summary>
private async Task FetchAuctionNameInBackgroundAsync(AuctionInfo auction, AuctionViewModel vm)
{
try
{
// ? USA IL SERVIZIO CENTRALIZZATO invece di HttpClient diretto
var response = await _htmlCacheService.GetHtmlAsync(
auction.OriginalUrl,
RequestPriority.Normal,
bypassCache: false // Usa cache se disponibile
);
if (!response.Success)
{
Log($"[WARN] Impossibile recuperare nome per asta {auction.AuctionId}: {response.Error}", LogLevel.Warning);
return;
}
// Estrai nome dal <title>
var match = System.Text.RegularExpressions.Regex.Match(response.Html, @"<title>([^<]+)</title>");
if (match.Success)
{
var productName = match.Groups[1].Value.Trim().Replace(" - Bidoo", "");
// ? Decodifica entity HTML (incluse quelle non standard)
productName = DecodeAllHtmlEntities(productName);
// ? MODIFICATO: Nome senza ID
var newName = productName;
// Aggiorna il nome su thread UI
Dispatcher.Invoke(() =>
{
auction.Name = newName;
// Forza refresh della griglia per mostrare il nuovo nome
var tempSource = MultiAuctionsGrid.ItemsSource;
MultiAuctionsGrid.ItemsSource = null;
MultiAuctionsGrid.ItemsSource = tempSource;
SaveAuctions(); // Salva il nome aggiornato
Log($"[NAME] Nome recuperato per asta {auction.AuctionId}: {productName}{(response.FromCache ? " (cached)" : "")}", LogLevel.Info);
});
}
else
{
Log($"[WARN] Nome non trovato nell'HTML per asta {auction.AuctionId}", LogLevel.Warning);
}
}
catch (Exception ex)
{
Log($"[WARN] Errore recupero nome per asta {auction.AuctionId}: {ex.Message}", LogLevel.Warning);
}
}
/// <summary>
/// Decodifica tutte le entity HTML, incluse quelle non standard come &plus;
/// </summary>
private string DecodeAllHtmlEntities(string text)
{
if (string.IsNullOrEmpty(text))
return text;
// Prima decodifica entity standard
var decoded = System.Net.WebUtility.HtmlDecode(text);
// ? Poi sostituisci entity non standard che WebUtility.HtmlDecode non gestisce
decoded = decoded.Replace("&plus;", "+");
decoded = decoded.Replace("&equals;", "=");
decoded = decoded.Replace("&minus;", "-");
decoded = decoded.Replace("&times;", "×");
decoded = decoded.Replace("&divide;", "÷");
decoded = decoded.Replace("&percnt;", "%");
decoded = decoded.Replace("&dollar;", "$");
decoded = decoded.Replace("&euro;", "€");
decoded = decoded.Replace("&pound;", "£");
return decoded;
}
private async Task AddAuctionFromUrl(string url)
{
try
{
if (!IsValidAuctionUrl(url))
{
MessageBox.Show("URL asta non valido!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var auctionId = ExtractAuctionId(url);
if (string.IsNullOrEmpty(auctionId))
{
MessageBox.Show("Impossibile estrarre ID asta!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// Verifica duplicati
if (_auctionViewModels.Any(a => a.AuctionId == auctionId))
{
MessageBox.Show("Asta già monitorata!", "Duplicato", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// Fetch nome (opzionale)
var name = $"Asta {auctionId}";
try
{
// ? USA IL SERVIZIO CENTRALIZZATO
var response = await _htmlCacheService.GetHtmlAsync(url, RequestPriority.Normal);
if (response.Success)
{
var match2 = System.Text.RegularExpressions.Regex.Match(response.Html, @"<title>([^<]+)</title>");
if (match2.Success)
{
name = DecodeAllHtmlEntities(match2.Groups[1].Value.Trim().Replace(" - Bidoo", ""));
}
}
}
catch { }
// CARICA IMPOSTAZIONI PREDEFINITE SALVATE
var settings = Utilities.SettingsManager.Load();
// ? Determina stato iniziale dalla configurazione
bool isActive = false;
bool isPaused = false;
switch (settings.DefaultNewAuctionState)
{
case "Active":
isActive = true;
isPaused = false;
break;
case "Paused":
isActive = true;
isPaused = true;
break;
case "Stopped":
default:
isActive = false;
isPaused = false;
break;
}
// Crea model con valori dalle impostazioni salvate e stato configurato
var auction = new AuctionInfo
{
AuctionId = auctionId,
Name = DecodeAllHtmlEntities(name),
OriginalUrl = url,
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs,
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
IsActive = isActive,
IsPaused = isPaused
};
// Aggiungi al monitor
_auctionMonitor.AddAuction(auction);
// Crea ViewModel con valori dalle impostazioni
var vm = new AuctionViewModel(auction)
{
MinPrice = settings.DefaultMinPrice,
MaxPrice = settings.DefaultMaxPrice,
MaxClicks = settings.DefaultMaxClicks
};
_auctionViewModels.Add(vm);
// ? Auto-start del monitoraggio se l'asta è attiva e il monitoraggio è fermo
if (isActive && !_isAutomationActive)
{
_auctionMonitor.Start();
_isAutomationActive = true;
Log($"[AUTO-START] Monitoraggio avviato automaticamente per nuova asta: {vm.Name}", LogLevel.Info);
}
SaveAuctions();
UpdateTotalCount();
UpdateGlobalControlButtons();
var stateText = isActive ? (isPaused ? "Paused" : "Active") : "Stopped";
Log($"[ADD] Asta aggiunta con stato={stateText}, Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", Utilities.LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Errore aggiunta asta: {ex.Message}");
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Aggiorna manualmente il nome di un'asta recuperandolo dall'HTML
/// </summary>
public async Task RefreshAuctionNameAsync(AuctionViewModel vm)
{
if (vm == null) return;
try
{
Log($"[NAME REFRESH] Aggiornamento nome per: {vm.Name}", LogLevel.Info);
await FetchAuctionNameInBackgroundAsync(vm.AuctionInfo, vm);
}
catch (Exception ex)
{
Log($"[ERRORE] Refresh nome asta: {ex.Message}", LogLevel.Error);
}
}
/// <summary>
/// Controlla se ci sono aste con nomi generici e prova a recuperarli dopo un delay
/// </summary>
private async Task RetryFailedAuctionNamesAsync()
{
try
{
// Aspetta 30 secondi prima di ritentare (dà tempo alle altre richieste di completare)
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(30));
// Trova aste con nomi generici "Asta XXXX"
var auctionsWithGenericNames = _auctionViewModels
.Where(vm => vm.Name.StartsWith("Asta ") && !vm.Name.Contains("Shop") && !vm.Name.Contains("€"))
.ToList();
if (auctionsWithGenericNames.Count > 0)
{
Log($"[NAME RETRY] Trovate {auctionsWithGenericNames.Count} aste con nomi generici. Ritento recupero...", LogLevel.Info);
// Ritenta il recupero per ognuna (con delay tra una e l'altra per non sovraccaricare)
foreach (var vm in auctionsWithGenericNames)
{
await FetchAuctionNameInBackgroundAsync(vm.AuctionInfo, vm);
await System.Threading.Tasks.Task.Delay(2000); // 2 secondi tra una richiesta e l'altra
}
}
}
catch (Exception ex)
{
Log($"[WARN] Errore retry nomi aste: {ex.Message}", LogLevel.Warning);
}
}
private void SaveAuctions()
{
try
{
var auctions = _auctionMonitor.GetAuctions();
Utilities.PersistenceManager.SaveAuctions(auctions);
}
catch (Exception ex)
{
Log($"[ERRORE] Errore salvataggio: {ex.Message}");
}
}
private void LoadSavedAuctions()
{
try
{
// ? Carica impostazioni
var settings = Utilities.SettingsManager.Load();
// Ottieni username corrente dalla sessione per ripristinare IsMyBid
var session = _auctionMonitor.GetSession();
var currentUsername = session?.Username ?? string.Empty;
var auctions = Utilities.PersistenceManager.LoadAuctions();
foreach (var auction in auctions)
{
// Protezione: rimuovi eventuali BidHistory null
auction.BidHistory = auction.BidHistory?.Where(b => b != null).ToList() ?? new System.Collections.Generic.List<BidHistory>();
// ? Decode HTML entities (incluse quelle non standard)
try { auction.Name = DecodeAllHtmlEntities(auction.Name ?? string.Empty); } catch { }
// ? Ripristina IsMyBid per tutte le puntate in RecentBids
if (auction.RecentBids != null && auction.RecentBids.Count > 0 && !string.IsNullOrEmpty(currentUsername))
{
foreach (var bid in auction.RecentBids)
{
bid.IsMyBid = bid.Username.Equals(currentUsername, StringComparison.OrdinalIgnoreCase);
}
}
// ? NUOVO: Gestione stato in base a RememberAuctionStates
if (settings.RememberAuctionStates)
{
// MODO 1: Ripristina lo stato salvato di ogni asta (IsActive e IsPaused vengono dal file salvato)
// Non serve fare nulla, lo stato è già quello salvato nel file
}
else
{
// MODO 2: Applica DefaultStartAuctionsOnLoad a tutte le aste
var loadState = settings.DefaultStartAuctionsOnLoad;
switch (loadState)
{
case "Active":
auction.IsActive = true;
auction.IsPaused = false;
break;
case "Paused":
auction.IsActive = true;
auction.IsPaused = true;
break;
case "Stopped":
default:
auction.IsActive = false;
auction.IsPaused = false;
break;
}
}
_auctionMonitor.AddAuction(auction);
var vm = new AuctionViewModel(auction);
_auctionViewModels.Add(vm);
}
// ? Avvia monitoraggio se ci sono aste in stato Active O Paused
bool hasActiveOrPausedAuctions = auctions.Any(a => a.IsActive);
if (hasActiveOrPausedAuctions && auctions.Count > 0)
{
_auctionMonitor.Start();
_isAutomationActive = true;
if (settings.RememberAuctionStates)
{
var activeCount = auctions.Count(a => a.IsActive && !a.IsPaused);
var pausedCount = auctions.Count(a => a.IsActive && a.IsPaused);
Log($"[AUTO-START] Monitoraggio avviato: {activeCount} attive, {pausedCount} in pausa (stati ripristinati)", LogLevel.Info);
}
else
{
var loadState = settings.DefaultStartAuctionsOnLoad;
if (loadState == "Active")
{
Log($"[AUTO-START] Monitoraggio avviato automaticamente per {auctions.Count} aste caricate in stato attivo", LogLevel.Info);
}
else if (loadState == "Paused")
{
Log($"[AUTO-START] Monitoraggio avviato automaticamente per {auctions.Count} aste caricate in pausa", LogLevel.Info);
}
}
}
UpdateTotalCount();
UpdateGlobalControlButtons();
// Log sempre mostrato (anche con 0 aste)
if (auctions.Count > 0)
{
if (settings.RememberAuctionStates)
{
Log($"[LOAD] {auctions.Count} aste caricate con stati individuali ripristinati", LogLevel.Info);
}
else
{
Log($"[LOAD] {auctions.Count} aste caricate con stato iniziale: {settings.DefaultStartAuctionsOnLoad}", LogLevel.Info);
}
}
else
{
Log("[LOAD] Nessuna asta salvata", LogLevel.Info);
}
}
catch (Exception ex)
{
Log($"[ERRORE] Caricamento aste: {ex.Message}", LogLevel.Error);
}
}
/// <summary>
/// Aggiorna i dettagli dell'asta selezionata nel pannello Info Prodotto
/// </summary>
private void UpdateSelectedAuctionDetails(AuctionViewModel? vm)
{
if (vm == null || vm.AuctionInfo == null)
{
// Resetta campi se nessuna asta selezionata
AuctionMonitor.ProductBuyNowPriceText.Text = "-";
AuctionMonitor.ProductShippingCostText.Text = "-";
AuctionMonitor.ProductWinLimitText.Text = "-";
return;
}
var auction = vm.AuctionInfo;
// CARICA AUTOMATICAMENTE INFO PRODOTTO SE NON PRESENTI
if (!auction.BuyNowPrice.HasValue && !auction.ShippingCost.HasValue)
{
// Carica in background senza bloccare l'UI
_ = LoadProductInfoInBackgroundAsync(auction);
}
// Aggiorna i campi delle impostazioni
UpdateAuctionSettingsDisplay(vm);
// Aggiorna Valore (Compra Subito)
if (auction.BuyNowPrice.HasValue)
{
AuctionMonitor.ProductBuyNowPriceText.Text = $"{auction.BuyNowPrice.Value:F2}€";
}
else
{
AuctionMonitor.ProductBuyNowPriceText.Text = "-";
}
// Aggiorna Spese di Spedizione
if (auction.ShippingCost.HasValue)
{
AuctionMonitor.ProductShippingCostText.Text = $"{auction.ShippingCost.Value:F2}€";
}
else
{
AuctionMonitor.ProductShippingCostText.Text = "-";
}
// Aggiorna Limiti di Vincita
if (auction.HasWinLimit && !string.IsNullOrWhiteSpace(auction.WinLimitDescription))
{
AuctionMonitor.ProductWinLimitText.Text = auction.WinLimitDescription;
}
else if (!auction.HasWinLimit)
{
AuctionMonitor.ProductWinLimitText.Text = "Nessun limite";
}
else
{
AuctionMonitor.ProductWinLimitText.Text = "-";
}
}
/// <summary>
/// Carica le informazioni del prodotto (e nome se generico) in background quando selezioni un'asta
/// </summary>
private async System.Threading.Tasks.Task LoadProductInfoInBackgroundAsync(AuctionInfo auction)
{
try
{
bool hasGenericName = auction.Name.StartsWith("Asta ") &&
!auction.Name.Contains("Shop") &&
!auction.Name.Contains("€") &&
!auction.Name.Contains("Buono") &&
!auction.Name.Contains("Carburante");
Log($"[PRODUCT INFO] Caricamento automatico per: {auction.Name}{(hasGenericName ? " (+ nome generico)" : "")}", Utilities.LogLevel.Info);
// ? USA IL SERVIZIO CENTRALIZZATO
var response = await _htmlCacheService.GetHtmlAsync(
auction.OriginalUrl,
RequestPriority.High, // Priorità alta per info prodotto
bypassCache: false
);
if (!response.Success)
{
Log($"[PRODUCT INFO] Errore caricamento: {response.Error}", Utilities.LogLevel.Warning);
return;
}
bool updated = false;
// 1. ? Se nome generico, estrai nome reale dal <title>
if (hasGenericName)
{
var matchTitle = System.Text.RegularExpressions.Regex.Match(response.Html, @"<title>([^<]+)</title>");
if (matchTitle.Success)
{
var productName = matchTitle.Groups[1].Value.Trim().Replace(" - Bidoo", "");
productName = DecodeAllHtmlEntities(productName);
// ? MODIFICATO: Nome senza ID
var newName = productName;
auction.Name = newName;
updated = true;
Log($"[NAME] Nome recuperato: {productName}{(response.FromCache ? " (cached)" : "")}", LogLevel.Info);
}
}
// 2. ? Estrai informazioni prodotto (prezzo, spedizione, limiti)
var extracted = Utilities.ProductValueCalculator.ExtractProductInfo(response.Html, auction);
if (extracted)
{
updated = true;
Log($"[PRODUCT INFO] Valore={auction.BuyNowPrice:F2}€, Spedizione={auction.ShippingCost:F2}€{(response.FromCache ? " (cached)" : "")}", Utilities.LogLevel.Success);
}
// 3. ? Salva e aggiorna UI solo se qualcosa è cambiato
if (updated)
{
SaveAuctions();
Dispatcher.Invoke(() =>
{
// Refresh griglia per mostrare nome aggiornato
if (hasGenericName)
{
var tempSource = MultiAuctionsGrid.ItemsSource;
MultiAuctionsGrid.ItemsSource = null;
MultiAuctionsGrid.ItemsSource = tempSource;
}
// Refresh dettagli se ancora selezionata
if (_selectedAuction != null && _selectedAuction.AuctionId == auction.AuctionId)
{
UpdateSelectedAuctionDetails(_selectedAuction);
}
});
}
}
catch (Exception ex)
{
Log($"[PRODUCT INFO] Errore caricamento: {ex.Message}", Utilities.LogLevel.Warning);
}
}
}
}

View File

@@ -0,0 +1,642 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using AutoBidder.Dialogs;
using AutoBidder.Utilities;
using AutoBidder.ViewModels;
namespace AutoBidder
{
/// <summary>
/// Button click event handlers for auction operations
/// </summary>
public partial class MainWindow
{
private void StartButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (!_isAutomationActive)
{
// Avvia il monitoraggio globale
_auctionMonitor.Start();
_isAutomationActive = true;
Log("[START] Monitoraggio avviato!", LogLevel.Success);
}
// Attiva e riprendi tutte le aste
foreach (var vm in _auctionViewModels)
{
if (!vm.IsActive)
{
vm.IsActive = true;
}
vm.IsPaused = false;
}
if (sender != null) // Solo se chiamato dall'utente, non internamente
{
Log("[START ALL] Tutte le aste avviate/riprese", LogLevel.Info);
}
// ? Salva gli stati aggiornati su disco
SaveAuctions();
UpdateGlobalControlButtons();
}
catch (Exception ex)
{
Log($"[ERRORE] Avvio: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
try
{
// Ferma tutte le aste
foreach (var vm in _auctionViewModels)
{
vm.IsActive = false;
}
// Ferma il monitoraggio globale
if (_isAutomationActive)
{
_auctionMonitor.Stop();
_isAutomationActive = false;
}
// ? Salva gli stati aggiornati su disco
SaveAuctions();
UpdateGlobalControlButtons();
if (sender != null) // Solo se chiamato dall'utente
{
Log("[STOP ALL] Monitoraggio fermato e tutte le aste arrestate", LogLevel.Warning);
}
}
catch (Exception ex)
{
Log($"[ERRORE STOP] {ex.Message}", LogLevel.Error);
}
}
private async void PauseAllButton_Click(object sender, RoutedEventArgs e)
{
try
{
foreach (var vm in _auctionViewModels.Where(a => a.IsActive))
{
vm.IsPaused = true;
}
// ? Salva gli stati aggiornati su disco
SaveAuctions();
UpdateGlobalControlButtons();
if (sender != null) // Solo se chiamato dall'utente
{
Log("[PAUSE ALL] Tutte le aste in pausa", LogLevel.Warning);
}
}
catch (Exception ex)
{
Log($"[ERRORE] Pausa globale: {ex.Message}", LogLevel.Error);
}
}
private async void AddUrlButton_Click(object sender, RoutedEventArgs e)
{
var dialog = new AddAuctionSimpleDialog();
if (dialog.ShowDialog() == true)
{
var raw = dialog.AuctionId ?? string.Empty;
var parts = Regex.Split(raw, "[\r\n;]+|\\s+")
.Select(p => p.Trim())
.Where(p => !string.IsNullOrWhiteSpace(p))
.ToList();
if (parts.Count == 0)
{
MessageBox.Show("Nessun URL/ID valido trovato.", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var added = 0;
var skipped = new System.Collections.Generic.List<string>();
foreach (var part in parts)
{
try
{
var input = part;
string? aid = null;
if (input.Contains("bidoo.com") || input.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
aid = ExtractAuctionId(input);
}
else
{
aid = input;
}
if (!string.IsNullOrEmpty(aid) && _auctionViewModels.Any(a => a.AuctionId == aid))
{
skipped.Add(part + " (duplicato)");
continue;
}
await AddAuctionById(input);
added++;
}
catch (Exception ex)
{
skipped.Add(part + " (errore: " + ex.Message + ")");
}
}
UpdateGlobalControlButtons();
var summary = $"Aggiunte: {added}. Skipped: {skipped.Count}.";
if (skipped.Count > 0)
summary += "\nDettagli: " + string.Join("; ", skipped.Take(10));
MessageBox.Show(summary, "Aggiunta aste", MessageBoxButton.OK, MessageBoxImage.Information);
// ? RIMOSSO: Retry automatico ora avviene alla selezione on-demand
// Le aste con nome generico vengono aggiornate automaticamente quando l'utente le seleziona
}
}
private void RemoveUrlButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var auctionName = _selectedAuction.Name;
var auctionId = _selectedAuction.AuctionId;
// Salva l'indice corrente prima di rimuovere
var currentIndex = _auctionViewModels.IndexOf(_selectedAuction);
// Conferma rimozione
var result = MessageBox.Show(
$"Rimuovere l'asta dal monitoraggio?\n\n{auctionName}\n(ID: {auctionId})\n\nL'asta verrà eliminata dalla lista e non sarà più monitorata.",
"Conferma Rimozione",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result != MessageBoxResult.Yes)
{
Log($"[REMOVE] Rimozione annullata: {auctionName}", LogLevel.Info);
return;
}
try
{
// Rimuove dal monitor
_auctionMonitor.RemoveAuction(auctionId);
// Rimuove dal ViewModel
_auctionViewModels.Remove(_selectedAuction);
// Salva modifiche
SaveAuctions();
UpdateTotalCount();
UpdateGlobalControlButtons();
Log($"[REMOVE] Asta rimossa: {auctionName} (ID: {auctionId})", LogLevel.Success);
// ? NUOVO: Sposta il focus sulla riga successiva
if (_auctionViewModels.Count > 0)
{
// Se c'è ancora almeno un'asta nella lista
int newIndex;
if (currentIndex >= _auctionViewModels.Count)
{
// L'asta rimossa era l'ultima, seleziona la nuova ultima
newIndex = _auctionViewModels.Count - 1;
}
else
{
// Seleziona l'asta che ora si trova nella stessa posizione
newIndex = currentIndex;
}
// Seleziona l'asta
MultiAuctionsGrid.SelectedIndex = newIndex;
_selectedAuction = _auctionViewModels[newIndex];
// ? FIX: Salva il nome della NUOVA asta selezionata per il log
var newAuctionName = _selectedAuction?.Name ?? "Sconosciuta";
// Forza il focus sulla griglia dopo un breve delay per permettere alla UI di aggiornarsi
Dispatcher.BeginInvoke(new Action(() =>
{
MultiAuctionsGrid.Focus();
// Scroll fino alla riga selezionata per assicurarsi che sia visibile
if (MultiAuctionsGrid.SelectedItem != null)
{
MultiAuctionsGrid.ScrollIntoView(MultiAuctionsGrid.SelectedItem);
}
// ? FIX: Usa la variabile locale invece di _selectedAuction.Name
Log($"[FOCUS] Focus spostato su: {newAuctionName}", LogLevel.Info);
}), System.Windows.Threading.DispatcherPriority.Background);
}
else
{
// Nessuna asta rimasta, reset selezione
_selectedAuction = null;
Log($"[REMOVE] Nessuna asta rimasta nella lista", LogLevel.Info);
}
}
catch (Exception ex)
{
Log($"[ERROR] Errore rimozione asta: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante la rimozione:\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void RemoveAllButton_Click(object sender, RoutedEventArgs e)
{
if (_auctionViewModels.Count == 0)
{
MessageBox.Show("Non ci sono aste da rimuovere", "Lista Vuota", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var count = _auctionViewModels.Count;
// Conferma rimozione
var result = MessageBox.Show(
$"Rimuovere TUTTE le aste dal monitoraggio?\n\nSono presenti {count} aste monitorate.\n\nTutte le aste verranno eliminate dalla lista e non saranno più monitorate.",
"Conferma Rimozione Totale",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result != MessageBoxResult.Yes)
{
Log($"[REMOVE ALL] Rimozione annullata", LogLevel.Info);
return;
}
try
{
// Ferma il monitoraggio se attivo
if (_isAutomationActive)
{
_auctionMonitor.Stop();
_isAutomationActive = false;
Log("[STOP] Monitoraggio fermato prima della rimozione totale", LogLevel.Info);
}
// Rimuove tutte le aste dal monitor e dal ViewModel
var auctionsToRemove = _auctionViewModels.ToList(); // Copia per evitare modifiche durante iterazione
foreach (var auction in auctionsToRemove)
{
_auctionMonitor.RemoveAuction(auction.AuctionId);
}
// Pulisci la lista ViewModel
_auctionViewModels.Clear();
// Resetta selezione
_selectedAuction = null;
// Salva modifiche
SaveAuctions();
UpdateTotalCount();
UpdateGlobalControlButtons();
Log($"[REMOVE ALL] Tutte le aste rimosse: {count} aste eliminate", LogLevel.Success);
MessageBox.Show($"Tutte le {count} aste sono state rimosse dal monitoraggio.", "Rimozione Completata", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
Log($"[ERROR] Errore rimozione totale: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante la rimozione delle aste: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void CopyAuctionUrlButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show(
"Seleziona un'asta dalla griglia prima di copiare l'URL.",
"Nessuna Asta Selezionata",
MessageBoxButton.OK,
MessageBoxImage.Information);
Log("[INFO] Tentativo di copia URL senza asta selezionata", LogLevel.Info);
return;
}
var url = _selectedAuction.AuctionInfo.OriginalUrl;
if (string.IsNullOrEmpty(url))
url = $"https://it.bidoo.com/auction.php?a=asta_{_selectedAuction.AuctionId}";
// Tenta di copiare con retry mechanism
const int maxAttempts = 3;
const int delayMs = 50;
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
Clipboard.SetText(url);
Log("URL copiato negli appunti", LogLevel.Success);
return; // Successo, esci
}
catch (System.Runtime.InteropServices.COMException ex) when (ex.ErrorCode == unchecked((int)0x800401D0)) // CLIPBRD_E_CANT_OPEN
{
if (attempt < maxAttempts)
{
// Clipboard occupato, riprova dopo un breve delay
System.Threading.Thread.Sleep(delayMs);
continue;
}
// Ultimo tentativo fallito
Log($"[WARN] Clipboard temporaneamente occupato. Il testo potrebbe essere stato copiato.", LogLevel.Warning);
return;
}
catch (Exception ex)
{
// Altri errori
Log($"[ERRORE] Impossibile copiare URL: {ex.Message}", LogLevel.Error);
return;
}
}
}
private void OpenAuctionInternalButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
try
{
var url = _selectedAuction.AuctionInfo.OriginalUrl;
if (string.IsNullOrEmpty(url))
url = $"https://it.bidoo.com/auction.php?a=asta_{_selectedAuction.AuctionId}";
// Naviga alla scheda Browser
TabBrowser.IsChecked = true;
// Naviga all'URL
if (EmbeddedWebView?.CoreWebView2 != null)
{
EmbeddedWebView.CoreWebView2.Navigate(url);
Log($"[BROWSER] Apertura asta nel browser interno: {_selectedAuction.Name}", LogLevel.Info);
}
else
{
Log($"[WARN] Browser interno non ancora inizializzato", LogLevel.Warning);
MessageBox.Show("Il browser interno non è ancora pronto.\nRiprova tra qualche secondo.", "Browser", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
catch (Exception ex)
{
Log($"[ERRORE] Apertura nel browser interno: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante l'apertura: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OpenAuctionExternalButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
try
{
var url = _selectedAuction.AuctionInfo.OriginalUrl;
if (string.IsNullOrEmpty(url))
url = $"https://it.bidoo.com/auction.php?a=asta_{_selectedAuction.AuctionId}";
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
Log($"[BROWSER] Apertura asta nel browser esterno: {_selectedAuction.Name}", LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Apertura nel browser esterno: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante l'apertura: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void ExportAuctionButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
try
{
MessageBox.Show(
$"Esportazione singola asta:\n\n{_selectedAuction.Name}\n(ID: {_selectedAuction.AuctionId})\n\nFunzionalità in sviluppo.\nUsa 'Esporta' dalla toolbar per esportare tutte le aste.",
"Export Asta",
MessageBoxButton.OK,
MessageBoxImage.Information);
Log($"[INFO] Richiesto export singolo per asta: {_selectedAuction.Name} (funzionalità in sviluppo)", LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Export asta: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void RefreshProductInfoButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
var auction = _selectedAuction.AuctionInfo;
// Verifica che ci siano le info prodotto caricate
if (!auction.BuyNowPrice.HasValue)
{
MessageBox.Show(
"Informazioni prodotto non disponibili.\n\n" +
"Il sistema le sta caricando automaticamente.\n" +
"Riprova tra qualche secondo.",
"Info Prodotto Mancanti",
MessageBoxButton.OK,
MessageBoxImage.Information);
return;
}
// Feedback visivo
AuctionMonitor.RefreshProductInfoButton.IsEnabled = false;
// CALCOLA LIMITI SUGGERITI (CONSERVATIVI)
double buyNowPrice = auction.BuyNowPrice.Value;
double shippingCost = auction.ShippingCost ?? 0;
double totalValue = buyNowPrice + shippingCost;
// Max EUR = 40% del valore TOTALE (più conservativo del 50%)
double suggestedMaxPrice = totalValue * 0.40;
suggestedMaxPrice = Math.Round(suggestedMaxPrice, 2);
// CALCOLA MAX CLICKS (numero massimo puntate conservativo)
// Formula: (Valore Totale - Max EUR) / 0.20€ per puntata
// Poi riduciamo del 20% per maggiore margine di sicurezza
int maxClicksTheoretical = (int)Math.Floor((totalValue - suggestedMaxPrice) / 0.20);
int suggestedMaxClicks = (int)Math.Floor(maxClicksTheoretical * 0.80); // 80% del teorico
// Minimo 10 puntate per dare comunque una chance
if (suggestedMaxClicks < 10) suggestedMaxClicks = 10;
Log($"[LIMITI] Valore={buyNowPrice:F2}€ + Extra={shippingCost:F2}€ = Tot={totalValue:F2}€ ? MaxEUR={suggestedMaxPrice:F2}€ (40%), MaxClicks={suggestedMaxClicks}", LogLevel.Info);
// CHIEDI CONFERMA
var result = MessageBox.Show(
$"Limiti suggeriti (conservativi):\n\n" +
$"Max EUR: {suggestedMaxPrice:F2}€\n" +
$"Max Clicks: {suggestedMaxClicks}\n\n" +
$"Applicare questi valori?",
"Conferma Limiti",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result != MessageBoxResult.Yes)
{
Log($"[LIMITI] Annullato dall'utente", LogLevel.Info);
return;
}
// APPLICA I LIMITI
_selectedAuction.MaxPrice = suggestedMaxPrice;
_selectedAuction.MaxClicks = suggestedMaxClicks;
// AGGIORNA UI
UpdateAuctionSettingsDisplay(_selectedAuction);
// SALVA
SaveAuctions();
Log($"[LIMITI] Applicati: MaxEUR={suggestedMaxPrice:F2}€, MaxClicks={suggestedMaxClicks}", LogLevel.Success);
}
catch (Exception ex)
{
Log($"[ERRORE] Calcolo limiti: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante il calcolo dei limiti:\n\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
AuctionMonitor.RefreshProductInfoButton.IsEnabled = true;
}
}
/// <summary>
/// Sposta l'asta selezionata verso l'alto nell'elenco
/// </summary>
private void MoveUpButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
try
{
var currentIndex = _auctionViewModels.IndexOf(_selectedAuction);
if (currentIndex <= 0)
{
// Già in cima o non trovata
Log($"[MOVE] L'asta è già in cima alla lista", LogLevel.Info);
return;
}
// Sposta l'elemento verso l'alto
_auctionViewModels.Move(currentIndex, currentIndex - 1);
// Mantieni la selezione
MultiAuctionsGrid.SelectedItem = _selectedAuction;
MultiAuctionsGrid.ScrollIntoView(_selectedAuction);
// Salva il nuovo ordine
SaveAuctions();
Log($"[MOVE UP] Asta spostata verso l'alto: {_selectedAuction.Name}", LogLevel.Success);
}
catch (Exception ex)
{
Log($"[ERRORE] Spostamento asta verso l'alto: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante lo spostamento: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Sposta l'asta selezionata verso il basso nell'elenco
/// </summary>
private void MoveDownButton_Click(object sender, RoutedEventArgs e)
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
try
{
var currentIndex = _auctionViewModels.IndexOf(_selectedAuction);
if (currentIndex < 0 || currentIndex >= _auctionViewModels.Count - 1)
{
// Già in fondo o non trovata
Log($"[MOVE] L'asta è già in fondo alla lista", LogLevel.Info);
return;
}
// Sposta l'elemento verso il basso
_auctionViewModels.Move(currentIndex, currentIndex + 1);
// Mantieni la selezione
MultiAuctionsGrid.SelectedItem = _selectedAuction;
MultiAuctionsGrid.ScrollIntoView(_selectedAuction);
// Salva il nuovo ordine
SaveAuctions();
Log($"[MOVE DOWN] Asta spostata verso il basso: {_selectedAuction.Name}", LogLevel.Success);
}
catch (Exception ex)
{
Log($"[ERRORE] Spostamento asta verso il basso: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante lo spostamento: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}

View File

@@ -0,0 +1,139 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using AutoBidder.Utilities;
using AutoBidder.ViewModels;
namespace AutoBidder
{
/// <summary>
/// Command implementations for MainWindow
/// </summary>
public partial class MainWindow
{
private void InitializeCommands()
{
StartAllCommand = new RelayCommand(_ => ExecuteStartAll());
StopAllCommand = new RelayCommand(_ => ExecuteStopAll());
PauseAllCommand = new RelayCommand(_ => ExecutePauseAll());
GridStartCommand = new RelayCommand(param => ExecuteGridStart(param as AuctionViewModel));
GridPauseCommand = new RelayCommand(param => ExecuteGridPause(param as AuctionViewModel));
GridStopCommand = new RelayCommand(param => ExecuteGridStop(param as AuctionViewModel));
GridBidCommand = new RelayCommand(async param => await ExecuteGridBidAsync(param as AuctionViewModel));
}
private void ExecuteStartAll()
{
StartButton_Click(null, null);
}
private void ExecuteStopAll()
{
StopButton_Click(null, null);
}
private void ExecutePauseAll()
{
PauseAllButton_Click(null, null);
}
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);
}
// ? Salva gli stati aggiornati su disco
SaveAuctions();
UpdateGlobalControlButtons();
}
private void ExecuteGridPause(AuctionViewModel? vm)
{
if (vm == null) return;
vm.IsPaused = true;
Log($"[PAUSA] Asta in pausa: {vm.Name}", LogLevel.Info);
// ? Salva gli stati aggiornati su disco
SaveAuctions();
UpdateGlobalControlButtons();
}
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);
}
// ? Salva gli stati aggiornati su disco
SaveAuctions();
UpdateGlobalControlButtons();
}
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;
// Aggiorna immediatamente il banner in alto
Dispatcher.Invoke(() => UpdateRemainingBidsDisplay());
}
if (result.BidsUsedOnThisAuction.HasValue)
{
vm.AuctionInfo.BidsUsedOnThisAuction = result.BidsUsedOnThisAuction.Value;
}
// Notifica aggiornamento contatori per aggiornare la UI - 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);
}
}
}
}

View File

@@ -0,0 +1,112 @@
using System;
using System.Windows;
namespace AutoBidder
{
/// <summary>
/// Event handlers per il nuovo sistema di connessione automatica
/// </summary>
public partial class MainWindow
{
/// <summary>
/// Handler per il click sul nome utente nella sidebar
/// </summary>
private void SidebarUsername_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// Riusa la stessa logica del pulsante connessione (se fosse ancora presente)
ConnectionStatusButton_Click(sender, new RoutedEventArgs());
}
/// <summary>
/// Handler per il pulsante stato connessione nel banner
/// Se non connesso: apre tab Browser per login
/// Se connesso: mostra opzioni (disconnetti, riconnetti)
/// </summary>
private void ConnectionStatusButton_Click(object sender, RoutedEventArgs e)
{
try
{
var session = _sessionService?.GetCurrentSession();
if (session != null && !string.IsNullOrEmpty(session.Username))
{
// Già connesso - Mostra opzioni
var result = MessageBox.Show(
this,
$"Connesso come: {session.Username}\n" +
$"Puntate residue: {session.RemainingBids}\n" +
$"Credito Shop: EUR {session.ShopCredit:F2}\n\n" +
"Vuoi disconnettere e accedere con un altro account?",
"Gestione Connessione",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
// Disconnetti
DisconnectSession();
}
}
else
{
// Non connesso - Apri browser per login
MessageBox.Show(
this,
"Per accedere:\n\n" +
"1. Fai login su Bidoo nella scheda Browser\n" +
"2. La connessione sarà automatica\n\n" +
"Apertura scheda Browser...",
"Accedi a Bidoo",
MessageBoxButton.OK,
MessageBoxImage.Information);
// Apri tab Browser
TabBrowser.IsChecked = true;
}
}
catch (Exception ex)
{
Log($"[ERRORE] Gestione connessione: {ex.Message}", Utilities.LogLevel.Error);
}
}
/// <summary>
/// Disconnette la sessione corrente
/// </summary>
private void DisconnectSession()
{
try
{
Log("[SESSION] Disconnessione in corso...", Utilities.LogLevel.Info);
// Clear session tramite SessionService
_sessionService?.ClearSession();
// Aggiorna UI
SetUserBanner(string.Empty, 0);
// Ferma monitoraggio se attivo
if (_isAutomationActive)
{
_auctionMonitor?.Stop();
_isAutomationActive = false;
UpdateGlobalControlButtons();
}
Log("[SESSION] Disconnesso con successo", Utilities.LogLevel.Success);
MessageBox.Show(
this,
"Disconnesso con successo.\n\n" +
"Per riconnetterti, fai login nella scheda Browser.",
"Disconnesso",
MessageBoxButton.OK,
MessageBoxImage.Information);
}
catch (Exception ex)
{
Log($"[ERRORE] Disconnessione: {ex.Message}", Utilities.LogLevel.Error);
}
}
}
}

View File

@@ -0,0 +1,337 @@
using System.Windows;
namespace AutoBidder
{
/// <summary>
/// Event handlers for UserControl events and tab navigation
/// </summary>
public partial class MainWindow
{
// ===== TAB NAVIGATION =====
private void TabAsteAttive_Checked(object sender, RoutedEventArgs e)
{
ShowPanel(AuctionMonitor);
}
private void TabBrowser_Checked(object sender, RoutedEventArgs e)
{
ShowPanel(Browser);
}
private void TabPuntateGratis_Checked(object sender, RoutedEventArgs e)
{
ShowPanel(PuntateGratisPanel);
}
private void TabDatiStatistici_Checked(object sender, RoutedEventArgs e)
{
ShowPanel(StatisticsPanel);
}
private void TabImpostazioni_Checked(object sender, RoutedEventArgs e)
{
try
{
// Mostra il pannello Impostazioni
ShowPanel(Settings);
// Carica impostazioni quando si apre la tab
LoadDefaultSettings();
// NOTA: Caricamento cookie RIMOSSO - ora automatico tramite browser
}
catch { }
}
private void ShowPanel(System.Windows.UIElement? panelToShow)
{
// Prevent NullReferenceException during initialization
if (AuctionMonitor == null || Browser == null || StatisticsPanel == null || Settings == null || PuntateGratisPanel == null)
return;
// Hide all panels
AuctionMonitor.Visibility = Visibility.Collapsed;
Browser.Visibility = Visibility.Collapsed;
PuntateGratisPanel.Visibility = Visibility.Collapsed;
StatisticsPanel.Visibility = Visibility.Collapsed;
Settings.Visibility = Visibility.Collapsed;
// Show selected panel
if (panelToShow != null)
panelToShow.Visibility = Visibility.Visible;
}
// ===== AUCTION MONITOR CONTROL EVENTS =====
private void AuctionMonitor_StartClicked(object sender, RoutedEventArgs e)
{
StartButton_Click(sender, e);
}
private void AuctionMonitor_PauseAllClicked(object sender, RoutedEventArgs e)
{
PauseAllButton_Click(sender, e);
}
private void AuctionMonitor_StopClicked(object sender, RoutedEventArgs e)
{
StopButton_Click(sender, e);
}
private void AuctionMonitor_ExportClicked(object sender, RoutedEventArgs e)
{
// Chiama il metodo di export esistente
try
{
// Esporta tutte le aste monitorate
var auctions = _auctionMonitor.GetAuctions();
if (auctions.Count == 0)
{
System.Windows.MessageBox.Show("Nessuna asta da esportare", "Export", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
return;
}
// TODO: Implementare dialog export con scelta formato
System.Windows.MessageBox.Show($"Export di {auctions.Count} aste.\n\nFunzionalità in sviluppo.\nUsa le impostazioni nella scheda Impostazioni per configurare l'export.", "Export Aste", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
Log($"[INFO] Richiesto export di {auctions.Count} aste (funzionalità in sviluppo)", Utilities.LogLevel.Info);
}
catch (System.Exception ex)
{
Log($"[ERRORE] Export: {ex.Message}", Utilities.LogLevel.Error);
}
}
private void AuctionMonitor_AddUrlClicked(object sender, RoutedEventArgs e)
{
AddUrlButton_Click(sender, e);
}
private void AuctionMonitor_RemoveUrlClicked(object sender, RoutedEventArgs e)
{
RemoveUrlButton_Click(sender, e);
}
private void AuctionMonitor_RemoveAllClicked(object sender, RoutedEventArgs e)
{
RemoveAllButton_Click(sender, e);
}
private void AuctionMonitor_MoveUpClicked(object sender, RoutedEventArgs e)
{
MoveUpButton_Click(sender, e);
}
private void AuctionMonitor_MoveDownClicked(object sender, RoutedEventArgs e)
{
MoveDownButton_Click(sender, e);
}
private void AuctionMonitor_AuctionSelectionChanged(object sender, RoutedEventArgs e)
{
if (AuctionMonitor.MultiAuctionsGrid.SelectedItem is ViewModels.AuctionViewModel selected)
{
_selectedAuction = selected;
UpdateSelectedAuctionDetails(selected);
// ? NUOVO: Rileva nome generico O info prodotto mancanti e recupera automaticamente
var auction = selected.AuctionInfo;
bool hasGenericName = auction.Name.StartsWith("Asta ") &&
!auction.Name.Contains("Shop") &&
!auction.Name.Contains("€") &&
!auction.Name.Contains("Buono") &&
!auction.Name.Contains("Carburante");
bool needsProductInfo = !auction.BuyNowPrice.HasValue && !auction.ShippingCost.HasValue;
// Se ha nome generico O mancano info prodotto ? recupera in background
if (hasGenericName || needsProductInfo)
{
Log($"[AUTO-FETCH] Recupero automatico per: {auction.Name} (nome generico={hasGenericName}, info mancanti={needsProductInfo})", Utilities.LogLevel.Info);
// Avvia fetch in background senza bloccare UI
_ = LoadProductInfoInBackgroundAsync(auction);
}
}
}
private void AuctionMonitor_CopyUrlClicked(object sender, RoutedEventArgs e)
{
CopyAuctionUrlButton_Click(sender, e);
}
private void AuctionMonitor_OpenAuctionInternalClicked(object sender, RoutedEventArgs e)
{
OpenAuctionInternalButton_Click(sender, e);
}
private void AuctionMonitor_OpenAuctionExternalClicked(object sender, RoutedEventArgs e)
{
OpenAuctionExternalButton_Click(sender, e);
}
private void AuctionMonitor_ExportAuctionClicked(object sender, RoutedEventArgs e)
{
ExportAuctionButton_Click(sender, e);
}
private void AuctionMonitor_ResetSettingsClicked(object sender, RoutedEventArgs e)
{
ResetSettingsButton_Click(sender, e);
}
private void AuctionMonitor_ClearBiddersClicked(object sender, RoutedEventArgs e)
{
ClearBiddersButton_Click(sender, e);
}
private void AuctionMonitor_ClearLogClicked(object sender, RoutedEventArgs e)
{
ClearLogButton_Click(sender, e);
}
private void AuctionMonitor_ClearGlobalLogClicked(object sender, RoutedEventArgs e)
{
ClearLogButton_Click(sender, e); // Clear Log invece di ClearGlobalLog
}
// ===== AUCTION SETTINGS EVENTS =====
private void AuctionMonitor_RefreshProductInfoClicked(object sender, RoutedEventArgs e)
{
RefreshProductInfoButton_Click(sender, e);
}
private void AuctionMonitor_ConnectionStatusClicked(object sender, RoutedEventArgs e)
{
ConnectionStatusButton_Click(sender, e);
}
private void AuctionMonitor_BidBeforeDeadlineMsChanged(object sender, RoutedEventArgs e)
{
// Gestito internamente dal binding WPF
if (_selectedAuction != null && int.TryParse(AuctionMonitor.SelectedBidBeforeDeadlineMs.Text, out int ms))
{
_selectedAuction.AuctionInfo.BidBeforeDeadlineMs = ms;
SaveAuctions();
}
}
private void AuctionMonitor_CheckAuctionOpenChanged(object sender, RoutedEventArgs e)
{
// Gestito internamente dal binding WPF
if (_selectedAuction != null)
{
_selectedAuction.AuctionInfo.CheckAuctionOpenBeforeBid = AuctionMonitor.SelectedCheckAuctionOpen.IsChecked ?? false;
SaveAuctions();
}
}
private void AuctionMonitor_MinPriceChanged(object sender, RoutedEventArgs e)
{
// Gestito internamente dal binding WPF
if (_selectedAuction != null && double.TryParse(AuctionMonitor.SelectedMinPrice.Text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double price))
{
_selectedAuction.MinPrice = price;
SaveAuctions();
}
}
private void AuctionMonitor_MaxPriceChanged(object sender, RoutedEventArgs e)
{
// Gestito internamente dal binding WPF
if (_selectedAuction != null && double.TryParse(AuctionMonitor.SelectedMaxPrice.Text, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double price))
{
_selectedAuction.MaxPrice = price;
SaveAuctions();
}
}
private void AuctionMonitor_MaxClicksChanged(object sender, RoutedEventArgs e)
{
// Gestito internamente dal binding WPF
if (_selectedAuction != null && int.TryParse(AuctionMonitor.SelectedMaxClicks.Text, out int clicks))
{
_selectedAuction.MaxClicks = clicks;
SaveAuctions();
}
}
// ===== BROWSER CONTROL EVENTS =====
private void Browser_BrowserBackClicked(object sender, RoutedEventArgs e)
{
try
{
if (Browser.EmbeddedWebView?.CoreWebView2 != null && Browser.EmbeddedWebView.CoreWebView2.CanGoBack)
Browser.EmbeddedWebView.CoreWebView2.GoBack();
}
catch { }
}
private void Browser_BrowserForwardClicked(object sender, RoutedEventArgs e)
{
try
{
if (Browser.EmbeddedWebView?.CoreWebView2 != null && Browser.EmbeddedWebView.CoreWebView2.CanGoForward)
Browser.EmbeddedWebView.CoreWebView2.GoForward();
}
catch { }
}
private void Browser_BrowserRefreshClicked(object sender, RoutedEventArgs e)
{
try
{
Browser.EmbeddedWebView?.Reload();
}
catch { }
}
private void Browser_BrowserHomeClicked(object sender, RoutedEventArgs e)
{
try
{
Browser.EmbeddedWebView?.CoreWebView2?.Navigate("https://it.bidoo.com/");
Browser.BrowserAddress.Text = "https://it.bidoo.com/";
}
catch { }
}
private void Browser_BrowserGoClicked(object sender, RoutedEventArgs e)
{
try
{
var url = Browser.BrowserAddress.Text?.Trim();
if (string.IsNullOrEmpty(url)) return;
if (!url.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
url = "https://" + url;
Browser.EmbeddedWebView?.CoreWebView2?.Navigate(url);
}
catch { }
}
private void Browser_BrowserAddAuctionClicked(object sender, RoutedEventArgs e)
{
try
{
var url = Browser.BrowserAddress.Text?.Trim() ?? Browser.EmbeddedWebView?.Source?.ToString();
if (!string.IsNullOrEmpty(url))
_ = AddAuctionFromUrl(url);
}
catch { }
}
// ===== SETTINGS CONTROL EVENTS =====
private void Settings_SaveDefaultsClicked(object sender, RoutedEventArgs e)
{
SaveDefaultsButton_Click(sender, e);
}
private void Settings_CancelDefaultsClicked(object sender, RoutedEventArgs e)
{
CancelDefaultsButton_Click(sender, e);
}
}
}

View File

@@ -0,0 +1,99 @@
using System;
using System.Windows;
using System.Windows.Media;
using AutoBidder.Utilities;
namespace AutoBidder
{
/// <summary>
/// Logging functionality with color-coded severity levels and configurable minimum level filtering
/// </summary>
public partial class MainWindow
{
/// <summary>
/// Scrive un messaggio nel log globale con filtraggio basato sul livello minimo configurato
/// </summary>
/// <param name="message">Messaggio da loggare</param>
/// <param name="level">Livello di severità del messaggio</param>
private void Log(string message, LogLevel level = LogLevel.Info)
{
Dispatcher.BeginInvoke(() =>
{
try
{
// Carica impostazioni per ottenere livello minimo e limite righe
var settings = SettingsManager.Load();
// Filtra messaggi in base al livello minimo configurato
MinimumLogLevel minLevel = MinimumLogLevel.Normal; // Default
if (Enum.TryParse<MinimumLogLevel>(settings.MinLogLevel, out var parsedLevel))
{
minLevel = parsedLevel;
}
// Se il livello del messaggio è maggiore del minimo configurato, ignora
if ((int)level > (int)minLevel)
{
return;
}
var timestamp = DateTime.Now.ToString("HH:mm:ss");
// Prefisso in base al livello per chiarezza
string prefix = level switch
{
LogLevel.Error => "[ERROR]",
LogLevel.Warning => "[WARN]",
LogLevel.Info => "[INFO]",
LogLevel.Success => "[OK]",
LogLevel.Debug => "[DEBUG]",
LogLevel.Trace => "[TRACE]",
_ => "[LOG]"
};
var logEntry = $"[{timestamp}] {prefix} {message}";
// Color coding based on severity for dark theme
var color = level switch
{
LogLevel.Error => new SolidColorBrush(Color.FromRgb(232, 17, 35)), // #E81123 (Red)
LogLevel.Warning => new SolidColorBrush(Color.FromRgb(255, 191, 0)), // #FFBF00 (Yellow)
LogLevel.Success => new SolidColorBrush(Color.FromRgb(0, 216, 0)), // #00D800 (Green)
LogLevel.Info => new SolidColorBrush(Color.FromRgb(100, 180, 255)), // #64B4FF (Light Blue)
LogLevel.Debug => new SolidColorBrush(Color.FromRgb(255, 140, 255)), // #FF8CFF (Magenta)
LogLevel.Trace => new SolidColorBrush(Color.FromRgb(160, 160, 160)), // #A0A0A0 (Gray)
_ => new SolidColorBrush(Color.FromRgb(204, 204, 204)) // #CCCCCC (Light Gray)
};
var p = new System.Windows.Documents.Paragraph { Margin = new Thickness(0, 2, 0, 2) };
var r = new System.Windows.Documents.Run(logEntry) { Foreground = color };
p.Inlines.Add(r);
LogBox.Document.Blocks.Add(p);
// Mantieni solo gli ultimi N paragrafi (configurabile dalle impostazioni)
int maxLogLines = settings.MaxGlobalLogLines;
if (LogBox.Document.Blocks.Count > maxLogLines)
{
// Rimuovi i paragrafi più vecchi (primi inseriti)
int excessCount = LogBox.Document.Blocks.Count - maxLogLines;
for (int i = 0; i < excessCount; i++)
{
if (LogBox.Document.Blocks.FirstBlock != null)
{
LogBox.Document.Blocks.Remove(LogBox.Document.Blocks.FirstBlock);
}
}
}
// Auto-scroll if near bottom
if (LogBox.VerticalOffset >= LogBox.ExtentHeight - LogBox.ViewportHeight - 40)
{
LogBox.ScrollToEnd();
}
}
catch { }
});
}
}
}

View File

@@ -0,0 +1,321 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using AutoBidder.Utilities;
using AutoBidder.ViewModels;
namespace AutoBidder
{
/// <summary>
/// UI update methods and selected auction details
/// </summary>
public partial class MainWindow
{
private void UpdateAuctionLog(AuctionViewModel auction)
{
try
{
var auctionInfo = auction.AuctionInfo;
var logBox = SelectedAuctionLog;
var doc = logBox.Document;
doc.Blocks.Clear();
foreach (var entry in auctionInfo.AuctionLog)
{
var upper = entry.ToUpperInvariant();
// Color coding based on log content
Brush color;
if (upper.Contains("[ERRORE]") || upper.Contains("[FAIL]") || upper.Contains("EXCEPTION"))
color = new SolidColorBrush(Color.FromRgb(232, 17, 35)); // Red
else if (upper.Contains("[WARN]") || upper.Contains("ATTENZIONE"))
color = new SolidColorBrush(Color.FromRgb(255, 183, 0)); // Yellow/Orange
else if (upper.Contains("[OK]") || upper.Contains("SUCCESS"))
color = new SolidColorBrush(Color.FromRgb(0, 216, 0)); // Green
else
color = new SolidColorBrush(Color.FromRgb(100, 180, 255)); // Light Blue - #64B4FF (più chiaro e leggibile)
var p = new System.Windows.Documents.Paragraph { Margin = new Thickness(0, 2, 0, 2) };
var r = new System.Windows.Documents.Run(entry) { Foreground = color };
p.Inlines.Add(r);
doc.Blocks.Add(p);
}
// Auto-scroll if near bottom
var viewer = logBox;
var vpos = viewer.VerticalOffset;
var vmax = viewer.ExtentHeight - viewer.ViewportHeight;
if (vmax - vpos < 40)
{
viewer.ScrollToEnd();
}
}
catch { }
}
private void RefreshBiddersGrid(AuctionViewModel auction)
{
try
{
var bidders = auction.AuctionInfo.BidderStats.Values
.OrderByDescending(b => b.BidCount)
.ToList();
SelectedAuctionBiddersGrid.ItemsSource = null;
SelectedAuctionBiddersGrid.ItemsSource = bidders;
SelectedAuctionBiddersCount.Text = $"Utenti: {bidders?.Count ?? 0}";
// ?? NUOVO: Aggiorna il contatore della storia puntate con limite configurato
var settings = SettingsManager.Load();
var maxEntries = settings?.MaxBidHistoryEntries ?? 20;
var historyCount = auction.BidHistoryEntries?.Count ?? 0;
var bidHistoryCountTextBlock = AuctionMonitor.FindName("BidHistoryCount") as TextBlock;
if (bidHistoryCountTextBlock != null)
{
// Mostra "Ultime 20 puntate" se il limite è attivo
if (maxEntries > 0)
{
bidHistoryCountTextBlock.Text = $"Ultime {maxEntries} puntate";
}
else
{
bidHistoryCountTextBlock.Text = $"Ultime puntate: {historyCount}";
}
}
}
catch { }
}
private void UpdateAuctionSettingsDisplay(AuctionViewModel auction)
{
try
{
// Blocca temporaneamente i TextChanged per evitare loop di aggiornamento
_isUpdatingSelection = true;
SelectedAuctionName.Text = auction.Name;
SelectedBidBeforeDeadlineMs.Text = auction.AuctionInfo.BidBeforeDeadlineMs.ToString();
SelectedCheckAuctionOpen.IsChecked = auction.AuctionInfo.CheckAuctionOpenBeforeBid;
SelectedMinPrice.Text = auction.MinPrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
SelectedMaxPrice.Text = auction.MaxPrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture);
SelectedMaxClicks.Text = auction.MaxClicks.ToString();
var url = auction.AuctionInfo.OriginalUrl;
if (string.IsNullOrEmpty(url))
url = $"https://it.bidoo.com/auction.php?a=asta_{auction.AuctionId}";
SelectedAuctionUrl.Text = url;
ResetSettingsButton.IsEnabled = true;
ClearBiddersButton.IsEnabled = true;
ClearLogButton.IsEnabled = true;
UpdateAuctionLog(auction);
RefreshBiddersGrid(auction);
_isUpdatingSelection = false;
}
catch
{
_isUpdatingSelection = false;
}
}
private void UpdateTotalCount()
{
MonitorateTitle.Text = $"Aste monitorate: {_auctionViewModels.Count}";
}
private void UpdateGlobalControlButtons()
{
try
{
var hasAuctions = _auctionViewModels.Count > 0;
if (!hasAuctions)
{
// Nessuna asta: tutti disabilitati
StartButton.IsEnabled = false;
StartButton.Opacity = 0.4;
PauseAllButton.IsEnabled = false;
PauseAllButton.Opacity = 0.4;
StopButton.IsEnabled = false;
StopButton.Opacity = 0.4;
return;
}
// Conta quante aste possono eseguire ogni azione
int canStartCount = _auctionViewModels.Count(a => a.CanStart);
int canPauseCount = _auctionViewModels.Count(a => a.CanPause);
int canStopCount = _auctionViewModels.Count(a => a.CanStop);
// AVVIA TUTTI: abilitato se ALMENO UNA asta può essere avviata
// Scuro se NESSUNA asta può essere avviata (tutte già avviate)
StartButton.IsEnabled = canStartCount > 0;
StartButton.Opacity = canStartCount > 0 ? 1.0 : 0.4;
// PAUSA TUTTI: abilitato se ALMENO UNA asta può essere messa in pausa
// Scuro se NESSUNA asta può essere messa in pausa (tutte già in pausa o ferme)
PauseAllButton.IsEnabled = canPauseCount > 0;
PauseAllButton.Opacity = canPauseCount > 0 ? 1.0 : 0.4;
// FERMA TUTTI: abilitato se ALMENO UNA asta può essere fermata
// Scuro se NESSUNA asta può essere fermata (tutte già ferme)
StopButton.IsEnabled = canStopCount > 0;
StopButton.Opacity = canStopCount > 0 ? 1.0 : 0.4;
}
catch { }
}
private void MultiAuctionsGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (MultiAuctionsGrid.SelectedItem is AuctionViewModel selected)
{
_selectedAuction = selected;
UpdateSelectedAuctionDetails(selected);
}
}
private void GridOpenAuction_Click(object sender, RoutedEventArgs e)
{
try
{
if (sender is FrameworkElement element && element.DataContext is AuctionViewModel vm)
{
var url = vm.AuctionInfo.OriginalUrl;
if (string.IsNullOrEmpty(url))
url = $"https://it.bidoo.com/auction.php?a=asta_{vm.AuctionId}";
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
}
}
catch (Exception ex)
{
Log($"[ERRORE] Apertura asta: {ex.Message}", LogLevel.Error);
}
}
private void ExportSelectedAuction_Click(object sender, RoutedEventArgs e)
{
try
{
if (sender is FrameworkElement element && element.DataContext is AuctionViewModel vm)
{
MessageBox.Show(this, $"Esportazione singola asta non ancora implementata.\nUsa 'Esporta Aste' dalla toolbar.", "Info", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
Log($"[ERRORE] Esportazione asta: {ex.Message}", LogLevel.Error);
}
}
/// <summary>
/// Resetta le impostazioni dell'asta selezionata ai valori predefiniti
/// </summary>
private void ResetSettingsButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var settings = SettingsManager.Load();
// Resetta ai valori predefiniti dalle impostazioni
_selectedAuction.AuctionInfo.BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs;
_selectedAuction.AuctionInfo.CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid;
_selectedAuction.MinPrice = settings.DefaultMinPrice;
_selectedAuction.MaxPrice = settings.DefaultMaxPrice;
_selectedAuction.MaxClicks = settings.DefaultMaxClicks;
// Aggiorna UI
UpdateAuctionSettingsDisplay(_selectedAuction);
// Salva
SaveAuctions();
Log($"[RESET] Impostazioni ripristinate ai valori predefiniti per: {_selectedAuction.Name}", LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Reset impostazioni: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante il reset: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Pulisce la lista degli utenti che hanno puntato sull'asta selezionata
/// </summary>
private void ClearBiddersButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var result = MessageBox.Show(
$"Pulire la lista degli utenti per questa asta?\n\n{_selectedAuction.Name}\n\nLa lista degli utenti che hanno puntato verrà svuotata.",
"Conferma Pulizia",
MessageBoxButton.YesNo,
MessageBoxImage.Question);
if (result != MessageBoxResult.Yes)
return;
// Pulisci la lista bidders
_selectedAuction.AuctionInfo.BidderStats.Clear();
// Aggiorna UI
RefreshBiddersGrid(_selectedAuction);
Log($"[CLEAR] Lista utenti pulita per: {_selectedAuction.Name}", LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Pulizia lista utenti: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante la pulizia: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Pulisce il log dell'asta selezionata
/// </summary>
private void ClearLogButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (_selectedAuction == null)
{
MessageBox.Show("Seleziona un'asta dalla griglia", "Nessuna Selezione", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
// Pulisci il log dell'asta
_selectedAuction.AuctionInfo.AuctionLog.Clear();
// Aggiorna UI
UpdateAuctionLog(_selectedAuction);
Log($"[CLEAR] Log pulito per: {_selectedAuction.Name}", LogLevel.Info);
}
catch (Exception ex)
{
Log($"[ERRORE] Pulizia log asta: {ex.Message}", LogLevel.Error);
MessageBox.Show($"Errore durante la pulizia: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Text.RegularExpressions;
namespace AutoBidder
{
/// <summary>
/// URL parsing and validation utilities
/// </summary>
public partial class MainWindow
{
private bool IsValidAuctionUrl(string url)
{
try
{
var uri = new Uri(url);
var host = uri.Host.ToLowerInvariant();
// Valida dominio Bidoo
if (!host.Contains("bidoo.com") && !host.Contains("bidoo.it") &&
!host.Contains("bidoo.fr") && !host.Contains("bidoo.es") &&
!host.Contains("bidoo.de"))
{
return false;
}
// Valida path asta
return uri.AbsolutePath.Contains("/asta/") || uri.Query.Contains("a=");
}
catch
{
return false;
}
}
private string? ExtractAuctionId(string url)
{
try
{
var uri = new Uri(url);
// Formato nuovo: /asta/nome-prodotto-81204324
var match = Regex.Match(uri.AbsolutePath, @"/asta/[^/]*-(\d{8,})");
if (match.Success)
{
return match.Groups[1].Value;
}
// Formato vecchio: /asta/81204324
match = Regex.Match(uri.AbsolutePath, @"/asta/(\d{8,})");
if (match.Success)
{
return match.Groups[1].Value;
}
// Formato query: ?a=Galaxy_S25_Ultra_256GB_81204324
match = Regex.Match(uri.Query, @"[?&]a=([^&]+)");
if (match.Success)
{
var aValue = match.Groups[1].Value;
// Estrai ID numerico finale (8+ cifre)
var idMatch = Regex.Match(aValue, @"(\d{8,})");
if (idMatch.Success)
{
return idMatch.Groups[1].Value;
}
}
return null;
}
catch
{
return null;
}
}
private string? ExtractProductName(string url)
{
try
{
var uri = new Uri(url);
// Formato query: ?a=Galaxy_S25_Ultra_256GB_81204324
var match = Regex.Match(uri.Query, @"[?&]a=([^&]+)");
if (match.Success)
{
var aValue = match.Groups[1].Value;
// Rimuovi l'ID finale e gli underscore
var nameMatch = Regex.Match(aValue, @"^(.+?)_(\d{8,})$");
if (nameMatch.Success)
{
var productName = nameMatch.Groups[1].Value;
productName = productName.Replace('_', ' ');
return productName;
}
}
// Formato path: /asta/galaxy-s25-ultra-256gb-81204324
match = Regex.Match(uri.AbsolutePath, @"/asta/(.+?)-(\d{8,})");
if (match.Success)
{
var productName = match.Groups[1].Value;
productName = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(
productName.Replace('-', ' ')
);
return productName;
}
return null;
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,338 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using AutoBidder.Services;
using AutoBidder.Utilities;
namespace AutoBidder
{
/// <summary>
/// User info and banner management - REFACTORED con SessionService
/// </summary>
public partial class MainWindow
{
private System.Windows.Threading.DispatcherTimer _userBannerTimer;
private System.Windows.Threading.DispatcherTimer _userHtmlTimer;
private SessionService _sessionService; // NUOVO: Servizio centralizzato
private void InitializeUserInfoTimers()
{
// Timer per aggiornamento dati utente da HTML ogni 5 minuti (PRINCIPALE)
_userHtmlTimer = new System.Windows.Threading.DispatcherTimer();
_userHtmlTimer.Interval = TimeSpan.FromMinutes(5);
_userHtmlTimer.Tick += UserHtmlTimer_Tick;
_userHtmlTimer.Start();
// Timer per aggiornamento banner API ogni 10 minuti (SECONDARIO - fallback)
_userBannerTimer = new System.Windows.Threading.DispatcherTimer();
_userBannerTimer.Interval = TimeSpan.FromMinutes(10);
_userBannerTimer.Tick += UserBannerTimer_Tick;
_userBannerTimer.Start();
}
private void InitializeSessionService()
{
// NUOVO: Inizializza SessionService
_sessionService = new SessionService(_auctionMonitor.GetApiClient());
// Event handlers
_sessionService.OnLog += (msg) => Log(msg, LogLevel.Info);
_sessionService.OnSessionChanged += (session) =>
{
Dispatcher.Invoke(() => SetUserBanner(session.Username, session.RemainingBids));
};
}
private void SetUserBanner(string username, int? remainingBids)
{
try
{
var session = _sessionService?.GetCurrentSession();
if (!string.IsNullOrEmpty(username))
{
// === CONNESSO ===
// Header - Puntate + Credito
RemainingBidsText.Text = remainingBids?.ToString() ?? "0";
if (session?.ShopCredit > 0)
{
AuctionMonitor.ShopCreditText.Text = $"EUR {session.ShopCredit:F2}";
}
else
{
AuctionMonitor.ShopCreditText.Text = "EUR 0.00";
}
// Aste vinte
BannerAsteDaRiscattare.Text = "0";
// Indicatore limite puntate
var settings = Utilities.SettingsManager.Load();
UpdateMinBidsIndicator(settings.MinimumRemainingBids);
// === SIDEBAR - Mostra dati utente ===
SidebarUsernameText.Text = username;
SidebarUsernameText.Foreground = new System.Windows.Media.SolidColorBrush(
System.Windows.Media.Color.FromRgb(0, 216, 0)); // Verde
SidebarUsernameText.FontWeight = System.Windows.FontWeights.Bold;
SidebarUsernameText.ToolTip = $"Connesso come {username} - Click per disconnettere";
// Mostra dettagli (ID + Email)
if (session?.UserId > 0)
{
SidebarUserIdText.Text = $"ID: {session.UserId}";
SidebarUserIdText.Visibility = System.Windows.Visibility.Visible;
}
else
{
SidebarUserIdText.Visibility = System.Windows.Visibility.Collapsed;
}
if (!string.IsNullOrEmpty(session?.Email))
{
SidebarUserEmailText.Text = session.Email;
SidebarUserEmailText.Visibility = System.Windows.Visibility.Visible;
}
else
{
SidebarUserEmailText.Visibility = System.Windows.Visibility.Collapsed;
}
SidebarUserDetailsPanel.Visibility = System.Windows.Visibility.Visible;
}
else
{
// === NON CONNESSO ===
// Reset header
RemainingBidsText.Text = "0";
AuctionMonitor.ShopCreditText.Text = "EUR 0.00";
BannerAsteDaRiscattare.Text = "0";
// Nascondi indicatore limite
MinBidsLimitIndicator.Visibility = Visibility.Collapsed;
// === SIDEBAR - Mostra "Non connesso" ===
SidebarUsernameText.Text = "Non connesso";
SidebarUsernameText.Foreground = new System.Windows.Media.SolidColorBrush(
System.Windows.Media.Color.FromRgb(255, 82, 82)); // Rosso chiaro (#FF5252)
SidebarUsernameText.FontWeight = System.Windows.FontWeights.Bold;
SidebarUsernameText.ToolTip = "Non connesso - Click per accedere tramite browser";
// Nascondi dettagli (ID + Email)
SidebarUserDetailsPanel.Visibility = System.Windows.Visibility.Collapsed;
}
}
catch { }
}
private async void UserBannerTimer_Tick(object? sender, EventArgs e)
{
// Usa SessionService per refresh
if (_sessionService != null)
{
await _sessionService.RefreshUserInfoAsync();
}
}
private async void UserHtmlTimer_Tick(object? sender, EventArgs e)
{
// Usa SessionService per refresh
if (_sessionService != null)
{
await _sessionService.RefreshUserInfoAsync();
}
}
/// <summary>
/// Carica sessione salvata
/// </summary>
private void LoadSavedSession()
{
try
{
var session = _sessionService?.GetCurrentSession();
if (session != null && session.IsValid)
{
StartButton.IsEnabled = true;
Log($"[SESSION] Ripristino sessione per: {session.Username}", LogLevel.Info);
// Aggiorna UI con stato connesso (ottimistico)
SetUserBanner(session.Username, session.RemainingBids);
// Verifica validità cookie in background
System.Threading.Tasks.Task.Run(async () =>
{
try
{
Log("[SESSION] Verifica validità sessione...", LogLevel.Info);
var success = await _auctionMonitor.UpdateUserInfoAsync();
var updatedSession = _auctionMonitor.GetSession();
Dispatcher.Invoke(() =>
{
if (success && updatedSession != null && !string.IsNullOrEmpty(updatedSession.Username))
{
SetUserBanner(updatedSession.Username, updatedSession.RemainingBids);
Log($"[SESSION] Sessione valida - {updatedSession.Username} ({updatedSession.RemainingBids} puntate)", LogLevel.Success);
}
else
{
SetUserBanner(string.Empty, 0);
Log("[SESSION] Sessione scaduta", LogLevel.Warning);
CheckBrowserCookieAfterWebViewReady();
}
});
}
catch (Exception ex)
{
Dispatcher.Invoke(() =>
{
SetUserBanner(string.Empty, 0);
Log($"[SESSION] Errore verifica sessione: {ex.Message}", LogLevel.Warning);
CheckBrowserCookieAfterWebViewReady();
});
}
});
}
else
{
Log("[SESSION] Nessuna sessione salvata", LogLevel.Info);
CheckBrowserCookieAfterWebViewReady();
SetUserBanner(string.Empty, 0);
}
}
catch (Exception ex)
{
Log($"[ERRORE] Caricamento sessione: {ex.Message}", LogLevel.Error);
CheckBrowserCookieAfterWebViewReady();
SetUserBanner(string.Empty, 0);
}
}
/// <summary>
/// Attende che WebView sia pronta, poi verifica presenza cookie
/// </summary>
private void CheckBrowserCookieAfterWebViewReady()
{
System.Threading.Tasks.Task.Run(async () =>
{
try
{
// Aspetta che WebView sia inizializzata (max 60 secondi)
var webViewReady = await WaitForWebViewInitAsync(60);
if (!webViewReady)
{
await Dispatcher.InvokeAsync(() =>
{
Log("[WARN] WebView non inizializzata dopo 60 secondi", LogLevel.Warning);
Log("[INFO] Per accedere:", LogLevel.Info);
Log("[INFO] 1. Click su 'Non connesso' nella sidebar", LogLevel.Info);
Log("[INFO] 2. Si aprirà la scheda Browser", LogLevel.Info);
Log("[INFO] 3. Fai login su Bidoo", LogLevel.Info);
Log("[INFO] 4. La connessione sarà automatica", LogLevel.Info);
});
return;
}
// WebView pronta - verifica cookie
await Dispatcher.InvokeAsync(async () =>
{
var browserCookie = await GetCookieFromWebView();
if (string.IsNullOrEmpty(browserCookie))
{
Log("[INFO] Nessun cookie nel browser", LogLevel.Info);
Log("[INFO] Per accedere:", LogLevel.Info);
Log("[INFO] 1. Click su 'Non connesso' nella sidebar", LogLevel.Info);
Log("[INFO] 2. Si aprirà la scheda Browser", LogLevel.Info);
Log("[INFO] 3. Fai login su Bidoo", LogLevel.Info);
Log("[INFO] 4. La connessione sarà automatica", LogLevel.Info);
}
else
{
Log("[INFO] Cookie rilevato nel browser - importazione in corso...", LogLevel.Info);
}
});
}
catch (Exception ex)
{
Log($"[WARN] Errore verifica cookie: {ex.Message}", LogLevel.Warning);
}
});
}
/// <summary>
/// Aggiorna immediatamente il banner delle puntate residue (chiamato dopo ogni puntata)
/// </summary>
public void UpdateRemainingBidsDisplay()
{
try
{
var session = _sessionService?.GetCurrentSession();
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);
}
}
/// <summary>
/// ? Aggiorna l'indicatore del limite minimo puntate nel banner
/// </summary>
private void UpdateMinBidsIndicator(int minBidsLimit)
{
try
{
if (minBidsLimit > 0)
{
// Mostra indicatore con solo il numero tra parentesi
MinBidsLimitIndicator.Visibility = Visibility.Visible;
MinBidsLimitIndicator.Text = $"({minBidsLimit})";
MinBidsLimitIndicator.ToolTip = $"Limite minimo puntate attivo: non scendera sotto {minBidsLimit} puntate";
// Colore basato su puntate residue
var session = _sessionService?.GetCurrentSession();
if (session != null && session.RemainingBids > 0)
{
if (session.RemainingBids <= minBidsLimit)
{
// Al limite - Rosso chiaro (più visibile su sfondo scuro)
MinBidsLimitIndicator.Foreground = new System.Windows.Media.SolidColorBrush(
System.Windows.Media.Color.FromRgb(255, 82, 82)); // #FF5252 - Rosso chiaro
}
else if (session.RemainingBids <= minBidsLimit + 10)
{
// Vicino al limite - Giallo
MinBidsLimitIndicator.Foreground = new System.Windows.Media.SolidColorBrush(
System.Windows.Media.Color.FromRgb(255, 193, 7)); // #FFC107 - Giallo
}
else
{
// Sopra il limite - Verde
MinBidsLimitIndicator.Foreground = new System.Windows.Media.SolidColorBrush(
System.Windows.Media.Color.FromRgb(0, 216, 0)); // #00D800 - Verde
}
}
}
else
{
// Nascondi indicatore
MinBidsLimitIndicator.Visibility = Visibility.Collapsed;
}
}
catch { }
}
}
}

View File

@@ -0,0 +1,344 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Web.WebView2.Core;
using AutoBidder.Utilities;
namespace AutoBidder
{
/// <summary>
/// Gestione WebView2: pre-caricamento e estrazione cookie
/// </summary>
public partial class MainWindow
{
private bool _isWebViewInitialized = false;
private TaskCompletionSource<bool>? _webViewInitCompletionSource;
/// <summary>
/// Inizializza WebView2 in background all'avvio per pre-caricare il browser
/// </summary>
private async void InitializeWebView2()
{
try
{
if (EmbeddedWebView == null)
{
Log("[WARN] WebView2 non disponibile", LogLevel.Warning);
_webViewInitCompletionSource?.TrySetResult(false);
return;
}
Log("[BROWSER] Inizializzazione WebView2 in background...", LogLevel.Info);
// Aspetta un attimo che l'UI sia completamente caricata
await System.Threading.Tasks.Task.Delay(500);
// ? FIX: WebView2 si inizializza SOLO se visibile
// Salva tab corrente e switcha temporaneamente a Browser
var wasVisible = Browser.Visibility == Visibility.Visible;
var currentTab = TabAsteAttive.IsChecked == true ? "AsteAttive" :
TabBrowser.IsChecked == true ? "Browser" :
TabPuntateGratis.IsChecked == true ? "PuntateGratis" :
TabDatiStatistici.IsChecked == true ? "DatiStatistici" :
TabImpostazioni.IsChecked == true ? "Impostazioni" : "AsteAttive";
if (!wasVisible)
{
await Dispatcher.InvokeAsync(() =>
{
Browser.Visibility = Visibility.Visible;
});
await Task.Delay(100);
}
// Specifica UserDataFolder esplicito
var userDataFolder = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"AutoBidder",
"WebView2"
);
// Crea directory se non esiste
System.IO.Directory.CreateDirectory(userDataFolder);
// Crea environment con UserDataFolder esplicito
var env = await Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(
browserExecutableFolder: null,
userDataFolder: userDataFolder
);
// Inizializza WebView con environment
await EmbeddedWebView.EnsureCoreWebView2Async(env);
// Ripristina tab originale se necessario
if (!wasVisible)
{
await Dispatcher.InvokeAsync(() =>
{
Browser.Visibility = Visibility.Collapsed;
// Ripristina tab originale
switch (currentTab)
{
case "AsteAttive":
TabAsteAttive.IsChecked = true;
AuctionMonitor.Visibility = Visibility.Visible;
break;
case "PuntateGratis":
TabPuntateGratis.IsChecked = true;
PuntateGratisPanel.Visibility = Visibility.Visible;
break;
case "DatiStatistici":
TabDatiStatistici.IsChecked = true;
StatisticsPanel.Visibility = Visibility.Visible;
break;
case "Impostazioni":
TabImpostazioni.IsChecked = true;
Settings.Visibility = Visibility.Visible;
break;
}
});
}
if (EmbeddedWebView.CoreWebView2 != null)
{
_isWebViewInitialized = true;
// Pre-carica la pagina di Bidoo in background
EmbeddedWebView.CoreWebView2.Navigate("https://it.bidoo.com");
Log("[BROWSER] WebView2 inizializzato e pre-caricato", LogLevel.Success);
// Registra evento per rilevare login automatico
EmbeddedWebView.CoreWebView2.NavigationCompleted += OnWebViewNavigationCompleted;
// Notifica che WebView è pronta
_webViewInitCompletionSource?.TrySetResult(true);
// Verifica immediata se c'è già un cookie
await CheckAndImportCookieIfAvailable();
}
else
{
Log("[ERROR] CoreWebView2 è null dopo init", LogLevel.Error);
_webViewInitCompletionSource?.TrySetResult(false);
}
}
catch (Exception ex)
{
Log($"[ERROR] Inizializzazione WebView2 fallita: {ex.Message}", LogLevel.Error);
_webViewInitCompletionSource?.TrySetResult(false);
}
}
/// <summary>
/// Verifica e importa cookie se disponibile
/// </summary>
private async Task CheckAndImportCookieIfAvailable()
{
try
{
// Aspetta che la pagina sia completamente 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 nel browser - importazione automatica...", LogLevel.Info);
await AutoImportCookieFromWebView(cookie);
}
}
}
catch (Exception ex)
{
Log($"[WARN] Verifica cookie fallita: {ex.Message}", LogLevel.Warning);
}
}
/// <summary>
/// Aspetta che WebView sia inizializzata (con timeout)
/// </summary>
private async Task<bool> WaitForWebViewInitAsync(int timeoutSeconds = 60)
{
if (_isWebViewInitialized)
return true;
_webViewInitCompletionSource = new TaskCompletionSource<bool>();
// Timeout
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.Warning);
return false;
}
return await _webViewInitCompletionSource.Task;
}
/// <summary>
/// Evento chiamato quando la navigazione nella WebView è completata
/// Rileva automaticamente se l'utente ha effettuato il login
/// </summary>
private async void OnWebViewNavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e)
{
try
{
if (!e.IsSuccess || EmbeddedWebView?.CoreWebView2 == null)
return;
var url = EmbeddedWebView.CoreWebView2.Source;
// Se l'utente è sulla homepage di Bidoo (dopo login), verifica cookie
if (url.Contains("bidoo.com") && !url.Contains("login"))
{
// ? REFACTORED: Delega a CheckAndImportCookieIfAvailable
await CheckAndImportCookieIfAvailable();
}
}
catch { }
}
/// <summary>
/// Importa automaticamente il cookie dalla WebView senza conferma utente
/// </summary>
private async Task<bool> AutoImportCookieFromWebView(string cookieString)
{
try
{
// Valida e attiva il cookie usando SessionService
var result = await _sessionService.ValidateAndActivateSessionAsync(cookieString);
if (result.Success && result.Session != null)
{
// Salva automaticamente la sessione
_sessionService.SaveSession(result.Session);
// Aggiorna il banner
Dispatcher.Invoke(() =>
{
SetUserBanner(result.Session.Username, result.Session.RemainingBids);
});
return true;
}
return false;
}
catch
{
return false;
}
}
/// <summary>
/// Estrae il cookie __stattrb dalla WebView2
/// </summary>
/// <returns>Cookie completo o null se non trovato</returns>
private async Task<string?> GetCookieFromWebView()
{
try
{
if (EmbeddedWebView?.CoreWebView2 == null)
return null;
// Ottieni tutti i cookie di bidoo.com
var cookies = await EmbeddedWebView.CoreWebView2.CookieManager.GetCookiesAsync("https://it.bidoo.com");
if (cookies == null || cookies.Count == 0)
return null;
// Cerca il cookie __stattrb (cookie di sessione principale)
var stattrb = cookies.FirstOrDefault(c => c.Name == "__stattrb");
if (stattrb == null)
return null;
// Costruisci la stringa cookie completa con tutti i cookie necessari
var cookieStrings = cookies
.Where(c => !string.IsNullOrEmpty(c.Value))
.Select(c => $"{c.Name}={c.Value}")
.ToList();
return string.Join("; ", cookieStrings);
}
catch (Exception ex)
{
Log($"[WARN] Impossibile estrarre cookie da WebView: {ex.Message}", LogLevel.Warning);
return null;
}
}
/// <summary>
/// Importa il cookie dalla WebView e lo salva per l'uso nelle API
/// </summary>
public async Task<bool> ImportCookieFromWebView()
{
try
{
if (!_isWebViewInitialized || EmbeddedWebView?.CoreWebView2 == null)
{
Log("[WARN] Browser non inizializzato - attendi qualche secondo e riprova", LogLevel.Warning);
return false;
}
Log("[BROWSER] Estrazione cookie dal browser...", LogLevel.Info);
var cookieString = await GetCookieFromWebView();
if (string.IsNullOrEmpty(cookieString))
{
Log("[WARN] Nessun cookie trovato nel browser - assicurati di aver effettuato il login su bidoo.com", LogLevel.Warning);
return false;
}
// ? NOTA: Non aggiorna più TextBox (rimossa) - direttamente alla validazione
// Valida e attiva il cookie usando SessionService
var result = await _sessionService.ValidateAndActivateSessionAsync(cookieString);
if (result.Success && result.Session != null)
{
// Salva automaticamente la sessione
_sessionService.SaveSession(result.Session);
// Aggiorna il banner
SetUserBanner(result.Session.Username, result.Session.RemainingBids);
Log($"[OK] Cookie importato e validato - Utente: {result.Session.Username}, Puntate: {result.Session.RemainingBids}", LogLevel.Success);
return true;
}
else
{
Log($"[ERRORE] Cookie importato ma non valido: {result.ErrorMessage}", LogLevel.Error);
return false;
}
}
catch (Exception ex)
{
Log($"[ERRORE] Importazione cookie: {ex.Message}", LogLevel.Error);
return false;
}
}
/// <summary>
/// Verifica se WebView2 è pronta per l'uso
/// </summary>
public bool IsWebViewReady()
{
return _isWebViewInitialized && EmbeddedWebView?.CoreWebView2 != null;
}
}
}

1
Mimante/Data/.gitkeep Normal file
View File

@@ -0,0 +1 @@
# This file ensures the data directory is tracked by git

View File

@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using AutoBidder.Models;
namespace AutoBidder.Data;
/// <summary>
/// DbContext per autenticazione Identity
/// </summary>
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Personalizza nomi tabelle Identity (opzionale)
builder.Entity<ApplicationUser>(entity =>
{
entity.ToTable("Users");
});
}
}

View File

@@ -0,0 +1,211 @@
using Microsoft.EntityFrameworkCore;
using AutoBidder.Models;
namespace AutoBidder.Data
{
/// <summary>
/// Context Entity Framework per PostgreSQL - Database Statistiche Aste
/// Gestisce aste concluse, metriche strategiche e analisi performance
/// </summary>
public class PostgresStatsContext : DbContext
{
public PostgresStatsContext(DbContextOptions<PostgresStatsContext> options)
: base(options)
{
}
// Tabelle principali
public DbSet<CompletedAuction> CompletedAuctions { get; set; }
public DbSet<BidderPerformance> BidderPerformances { get; set; }
public DbSet<ProductStatistic> ProductStatistics { get; set; }
public DbSet<DailyMetric> DailyMetrics { get; set; }
public DbSet<StrategicInsight> StrategicInsights { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configurazione CompletedAuction
modelBuilder.Entity<CompletedAuction>(entity =>
{
entity.ToTable("completed_auctions");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.AuctionId).HasColumnName("auction_id").IsRequired().HasMaxLength(100);
entity.Property(e => e.ProductName).HasColumnName("product_name").IsRequired().HasMaxLength(500);
entity.Property(e => e.FinalPrice).HasColumnName("final_price").HasColumnType("decimal(10,2)");
entity.Property(e => e.BuyNowPrice).HasColumnName("buy_now_price").HasColumnType("decimal(10,2)");
entity.Property(e => e.ShippingCost).HasColumnName("shipping_cost").HasColumnType("decimal(10,2)");
entity.Property(e => e.TotalBids).HasColumnName("total_bids");
entity.Property(e => e.MyBidsCount).HasColumnName("my_bids_count");
entity.Property(e => e.ResetCount).HasColumnName("reset_count");
entity.Property(e => e.Won).HasColumnName("won");
entity.Property(e => e.WinnerUsername).HasColumnName("winner_username").HasMaxLength(100);
entity.Property(e => e.CompletedAt).HasColumnName("completed_at");
entity.Property(e => e.DurationSeconds).HasColumnName("duration_seconds");
entity.Property(e => e.AverageLatency).HasColumnName("average_latency").HasColumnType("decimal(10,2)");
entity.Property(e => e.Savings).HasColumnName("savings").HasColumnType("decimal(10,2)");
entity.Property(e => e.TotalCost).HasColumnName("total_cost").HasColumnType("decimal(10,2)");
entity.Property(e => e.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("CURRENT_TIMESTAMP");
entity.HasIndex(e => e.AuctionId).HasDatabaseName("idx_auction_id");
entity.HasIndex(e => e.ProductName).HasDatabaseName("idx_product_name");
entity.HasIndex(e => e.CompletedAt).HasDatabaseName("idx_completed_at");
entity.HasIndex(e => e.Won).HasDatabaseName("idx_won");
});
// Configurazione BidderPerformance
modelBuilder.Entity<BidderPerformance>(entity =>
{
entity.ToTable("bidder_performances");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Username).HasColumnName("username").IsRequired().HasMaxLength(100);
entity.Property(e => e.TotalAuctions).HasColumnName("total_auctions");
entity.Property(e => e.AuctionsWon).HasColumnName("auctions_won");
entity.Property(e => e.AuctionsLost).HasColumnName("auctions_lost");
entity.Property(e => e.TotalBidsPlaced).HasColumnName("total_bids_placed");
entity.Property(e => e.WinRate).HasColumnName("win_rate").HasColumnType("decimal(5,2)");
entity.Property(e => e.AverageBidsPerAuction).HasColumnName("average_bids_per_auction").HasColumnType("decimal(10,2)");
entity.Property(e => e.AverageCompetition).HasColumnName("average_competition").HasColumnType("decimal(10,2)");
entity.Property(e => e.IsAggressive).HasColumnName("is_aggressive");
entity.Property(e => e.LastSeenAt).HasColumnName("last_seen_at");
entity.Property(e => e.UpdatedAt).HasColumnName("updated_at").HasDefaultValueSql("CURRENT_TIMESTAMP");
entity.HasIndex(e => e.Username).IsUnique().HasDatabaseName("idx_username");
entity.HasIndex(e => e.WinRate).HasDatabaseName("idx_win_rate");
});
// Configurazione ProductStatistic
modelBuilder.Entity<ProductStatistic>(entity =>
{
entity.ToTable("product_statistics");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.ProductKey).HasColumnName("product_key").IsRequired().HasMaxLength(200);
entity.Property(e => e.ProductName).HasColumnName("product_name").IsRequired().HasMaxLength(500);
entity.Property(e => e.TotalAuctions).HasColumnName("total_auctions");
entity.Property(e => e.AverageWinningBids).HasColumnName("average_winning_bids").HasColumnType("decimal(10,2)");
entity.Property(e => e.AverageFinalPrice).HasColumnName("average_final_price").HasColumnType("decimal(10,2)");
entity.Property(e => e.AverageResets).HasColumnName("average_resets").HasColumnType("decimal(10,2)");
entity.Property(e => e.MinBidsSeen).HasColumnName("min_bids_seen");
entity.Property(e => e.MaxBidsSeen).HasColumnName("max_bids_seen");
entity.Property(e => e.RecommendedMaxBids).HasColumnName("recommended_max_bids");
entity.Property(e => e.RecommendedMaxPrice).HasColumnName("recommended_max_price").HasColumnType("decimal(10,2)");
entity.Property(e => e.CompetitionLevel).HasColumnName("competition_level").HasMaxLength(20);
entity.Property(e => e.LastUpdated).HasColumnName("last_updated").HasDefaultValueSql("CURRENT_TIMESTAMP");
entity.HasIndex(e => e.ProductKey).IsUnique().HasDatabaseName("idx_product_key");
entity.HasIndex(e => e.ProductName).HasDatabaseName("idx_product_name_stats");
});
// Configurazione DailyMetric
modelBuilder.Entity<DailyMetric>(entity =>
{
entity.ToTable("daily_metrics");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Date).HasColumnName("date").HasColumnType("date");
entity.Property(e => e.TotalBidsUsed).HasColumnName("total_bids_used");
entity.Property(e => e.MoneySpent).HasColumnName("money_spent").HasColumnType("decimal(10,2)");
entity.Property(e => e.AuctionsWon).HasColumnName("auctions_won");
entity.Property(e => e.AuctionsLost).HasColumnName("auctions_lost");
entity.Property(e => e.TotalSavings).HasColumnName("total_savings").HasColumnType("decimal(10,2)");
entity.Property(e => e.AverageLatency).HasColumnName("average_latency").HasColumnType("decimal(10,2)");
entity.Property(e => e.WinRate).HasColumnName("win_rate").HasColumnType("decimal(5,2)");
entity.Property(e => e.ROI).HasColumnName("roi").HasColumnType("decimal(10,2)");
entity.HasIndex(e => e.Date).IsUnique().HasDatabaseName("idx_date");
});
// Configurazione StrategicInsight
modelBuilder.Entity<StrategicInsight>(entity =>
{
entity.ToTable("strategic_insights");
entity.HasKey(e => e.Id);
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.InsightType).HasColumnName("insight_type").IsRequired().HasMaxLength(50);
entity.Property(e => e.ProductKey).HasColumnName("product_key").HasMaxLength(200);
entity.Property(e => e.RecommendedAction).HasColumnName("recommended_action").IsRequired();
entity.Property(e => e.ConfidenceLevel).HasColumnName("confidence_level").HasColumnType("decimal(5,2)");
entity.Property(e => e.DataPoints).HasColumnName("data_points");
entity.Property(e => e.Reasoning).HasColumnName("reasoning");
entity.Property(e => e.CreatedAt).HasColumnName("created_at").HasDefaultValueSql("CURRENT_TIMESTAMP");
entity.Property(e => e.IsActive).HasColumnName("is_active").HasDefaultValue(true);
entity.HasIndex(e => e.InsightType).HasDatabaseName("idx_insight_type");
entity.HasIndex(e => e.ProductKey).HasDatabaseName("idx_product_key_insight");
entity.HasIndex(e => e.CreatedAt).HasDatabaseName("idx_created_at");
});
}
/// <summary>
/// Verifica e crea lo schema del database
/// </summary>
public async Task<bool> EnsureSchemaAsync()
{
try
{
// Verifica connessione
if (!await Database.CanConnectAsync())
{
Console.WriteLine("[PostgreSQL] Cannot connect to database");
return false;
}
// Crea schema se non esistono le tabelle (senza migrations)
var created = await Database.EnsureCreatedAsync();
if (created)
{
Console.WriteLine("[PostgreSQL] Schema created successfully");
}
else
{
Console.WriteLine("[PostgreSQL] Schema already exists");
}
// Verifica che tutte le tabelle esistano
var hasCompletedAuctions = await CompletedAuctions.AnyAsync();
Console.WriteLine($"[PostgreSQL] Database verified - {(hasCompletedAuctions ? "has data" : "empty")}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"[PostgreSQL ERROR] Schema creation failed: {ex.Message}");
Console.WriteLine($"[PostgreSQL ERROR] Stack trace: {ex.StackTrace}");
return false;
}
}
/// <summary>
/// Verifica che tutte le tabelle richieste esistano
/// </summary>
public async Task<bool> ValidateSchemaAsync()
{
try
{
// Prova a contare le righe di ogni tabella (forza check esistenza)
await CompletedAuctions.CountAsync();
await BidderPerformances.CountAsync();
await ProductStatistics.CountAsync();
await DailyMetrics.CountAsync();
await StrategicInsights.CountAsync();
Console.WriteLine("[PostgreSQL] All tables validated successfully");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"[PostgreSQL ERROR] Schema validation failed: {ex.Message}");
return false;
}
}
}
}

View File

@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore;
using AutoBidder.Models;
namespace AutoBidder.Data
{
public class StatisticsContext : DbContext
{
public DbSet<ProductStat> ProductStats { get; set; }
public StatisticsContext(DbContextOptions<StatisticsContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProductStat>()
.HasIndex(p => p.ProductKey)
.IsUnique(false);
base.OnModelCreating(modelBuilder);
}
}
}

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<Window x:Class="AutoBidder.Dialogs.AddAuctionSimpleDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:AutoBidder.Controls"
Title="Aggiungi Asta" Height="320" Width="700"
Background="#0a0a0a" Foreground="#FFFFFF"
WindowStartupLocation="CenterOwner"
Icon="pack://application:,,,/Icon/favicon.ico"
ResizeMode="NoResize">
<Border Background="#1a1a1a" CornerRadius="8" Padding="16" Margin="8">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="Inserire URL dell'asta (uno o pi&#x00F9;)" Foreground="#CCCCCC" FontSize="14" Margin="0,0,0,6" />
<TextBlock Grid.Row="1" Text="Puoi aggiungere pi&#x00F9; link separandoli con 'a capo', 'spazio' o ';'" Foreground="#999999" FontSize="12" Margin="0,0,0,10" />
<TextBox x:Name="AuctionUrlBox" Grid.Row="2" MinWidth="560" Margin="0,0,0,8"
Background="#181818" Foreground="#00CCFF" BorderBrush="#444" BorderThickness="1"
Padding="8" FontSize="13" ToolTip="Inserisci uno o pi&#x00F9; URL/ID dell'asta. Separali con a capo, spazio o ';'"
AcceptsReturn="True" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" Height="160" />
<controls:SimpleToolbar Grid.Row="3" Margin="0,8,0,0">
<controls:SimpleToolbar.RightContent>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="OK" Width="110" Margin="6" Padding="10,8"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66" Foreground="White" Click="OkButton_Click" />
<Button Content="Annulla" Width="110" Margin="6" Padding="10,8"
Style="{StaticResource SmallButtonStyle}" Background="#666" Foreground="White" Click="CancelButton_Click" />
</StackPanel>
</controls:SimpleToolbar.RightContent>
</controls:SimpleToolbar>
</Grid>
</Border>
</Window>

View File

@@ -0,0 +1,35 @@
using System.Windows;
namespace AutoBidder.Dialogs
{
public partial class AddAuctionSimpleDialog : Window
{
public string AuctionId { get; private set; } = string.Empty;
public AddAuctionSimpleDialog()
{
InitializeComponent();
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
var text = AuctionUrlBox.Text ?? string.Empty;
if (string.IsNullOrWhiteSpace(text))
{
MessageBox.Show("Inserisci almeno un URL o ID dell'asta.", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// Return the raw text (may contain multiple entries); caller will parse it
AuctionId = text.Trim();
DialogResult = true;
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
}
}

View File

@@ -0,0 +1,89 @@
<Window x:Class="AutoBidder.Dialogs.ClosedAuctionsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Aste Chiuse - Estrazione" Height="600" Width="1000"
Background="#0a0a0a" Foreground="#FFFFFF" WindowStartupLocation="CenterOwner">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="8" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Background="#1a1a1a" Padding="10" CornerRadius="6" Grid.Row="0" BorderBrush="#333333" BorderThickness="1">
<DockPanel>
<TextBlock Text="Estrazione Aste Chiuse" FontSize="16" FontWeight="Bold" Foreground="#00CC66" VerticalAlignment="Center" DockPanel.Dock="Left" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" DockPanel.Dock="Right">
<Button x:Name="StartExtractButton" Content="Avvia Estrazione" Click="StartExtractButton_Click" Width="140" Height="36" Margin="8,0,0,0" Background="#00CC66" Style="{StaticResource SmallButtonStyle}"/>
<Button x:Name="ExportStatsButton" Content="Esporta Statistiche" Click="ExportStatsButton_Click" Width="160" Height="36" Margin="8,0,0,0" Background="#8B5CF6" Style="{StaticResource SmallButtonStyle}"/>
<Button x:Name="CloseButton" Content="Chiudi" Click="CloseButton_Click" Width="80" Height="36" Margin="8,0,0,0" Background="#666" Style="{StaticResource SmallButtonStyle}"/>
</StackPanel>
</DockPanel>
</Border>
<Border Grid.Row="2" Background="#1a1a1a" Padding="8" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Products grid: styled like MainWindow -->
<DataGrid x:Name="ProductsGrid" AutoGenerateColumns="False" Grid.Column="0" Background="#1a1a1a" Foreground="#FFFFFF" BorderBrush="#333333" BorderThickness="1"
RowBackground="#1a1a1a" AlternatingRowBackground="#222222" GridLinesVisibility="Horizontal" HorizontalGridLinesBrush="#333333"
IsReadOnly="True" SelectionUnit="CellOrRowHeader" SelectionMode="Extended" ClipboardCopyMode="IncludeHeader" CanUserAddRows="False" CanUserDeleteRows="False">
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#2a2a2a" />
<Setter Property="Foreground" Value="#FFFFFF" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Padding" Value="10,8" />
<Setter Property="BorderThickness" Value="0,0,0,2" />
<Setter Property="BorderBrush" Value="#00CC66" />
</Style>
<Style TargetType="DataGridRow">
<Setter Property="Height" Value="36" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#0099FF" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="10,6" />
</Style>
</DataGrid.Resources>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Copy" Header="Copia" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="Asta URL" Binding="{Binding AuctionUrl}" Width="2*" />
<DataGridTextColumn Header="Nome" Binding="{Binding ProductName}" Width="3*"/>
<DataGridTextColumn Header="Prezzo" Binding="{Binding FinalPrice}" Width="80"/>
<DataGridTextColumn Header="Vincitore" Binding="{Binding Winner}" Width="120"/>
<DataGridTextColumn Header="Puntate Usate" Binding="{Binding BidsUsed}" Width="100"/>
<DataGridTextColumn Header="Scraped At" Binding="{Binding ScrapedAt}" Width="140"/>
</DataGrid.Columns>
</DataGrid>
<GridSplitter Grid.Column="1" Width="8" />
<!-- Log area styled like main window log -->
<Border Grid.Column="2" Background="#0f0f0f" Padding="8" CornerRadius="6" BorderBrush="#333333" BorderThickness="1">
<DockPanel>
<TextBlock Text="Log Operazioni" FontWeight="Bold" Foreground="#00CC66" DockPanel.Dock="Top" Margin="0,0,0,8" />
<RichTextBox x:Name="ExtractLogBox" IsReadOnly="True" VerticalScrollBarVisibility="Auto" FontFamily="Consolas" FontSize="11" Background="#0f0f0f" Foreground="#CCC" BorderBrush="#333333" BorderThickness="1" />
</DockPanel>
</Border>
</Grid>
</Border>
</Grid>
</Window>

View File

@@ -0,0 +1,140 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using Microsoft.Win32;
using AutoBidder.Models;
using AutoBidder.Services;
using AutoBidder.Data;
using Microsoft.EntityFrameworkCore;
namespace AutoBidder.Dialogs
{
public partial class ClosedAuctionsWindow : Window
{
private ObservableCollection<ClosedAuctionRecord> _products = new();
private bool _isRunning = false;
// StatsService using local DB. Create context with default sqlite file in app folder
private readonly StatsService _statsService;
public ClosedAuctionsWindow()
{
InitializeComponent();
ProductsGrid.ItemsSource = _products;
var optionsBuilder = new DbContextOptionsBuilder<StatisticsContext>();
var dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "stats.db");
optionsBuilder.UseSqlite($"Data Source={dbPath}");
var ctx = new StatisticsContext(optionsBuilder.Options);
_statsService = new StatsService(ctx);
Log("Finestra pronta");
}
private void Log(string message)
{
try
{
var para = new Paragraph(new Run($"{DateTime.Now:HH:mm} - {message}"));
ExtractLogBox.Document.Blocks.Add(para);
// keep size manageable
while (ExtractLogBox.Document.Blocks.Count > 500)
ExtractLogBox.Document.Blocks.Remove(ExtractLogBox.Document.Blocks.FirstBlock);
ExtractLogBox.ScrollToEnd();
}
catch { }
}
private async void StartExtractButton_Click(object sender, RoutedEventArgs e)
{
if (_isRunning)
{
Log("Estrazione già in corso");
return;
}
_isRunning = true;
StartExtractButton.IsEnabled = false;
Log("Avvio procedura di estrazione da closed_auctions.php...");
try
{
var scraper = new ClosedAuctionsScraper(null, _statsService, Log);
var closedUrl = "https://it.bidoo.com/closed_auctions.php";
Log($"Scarico: {closedUrl}");
int count = 0;
await foreach (var rec in scraper.ScrapeYieldAsync(closedUrl))
{
// Filter out records without bids info (user requested)
if (!rec.BidsUsed.HasValue)
{
Log($"Scartata asta (mancano puntate): {rec.AuctionUrl} - '{rec.ProductName ?? "?"}'");
continue;
}
// Add and log incrementally so user sees progress
_products.Add(rec);
count++;
Log($"[{count}] {rec.ProductName} | Prezzo: {(rec.FinalPrice.HasValue?rec.FinalPrice.Value.ToString("F2")+"":"--")} | Vincitore: {rec.Winner ?? "--"} | Puntate: {rec.BidsUsed.Value} | URL: {rec.AuctionUrl}");
}
Log($"Estrazione completata: {count} record aggiunti.");
}
catch (Exception ex)
{
Log($"[ERRORE] Estrattore: {ex.Message}");
}
finally
{
_isRunning = false;
StartExtractButton.IsEnabled = true;
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private async void ExportStatsButton_Click(object sender, RoutedEventArgs e)
{
try
{
Log("Preparazione esportazione statistiche...");
var stats = await _statsService.GetAllStatsAsync();
if (stats == null || stats.Count == 0)
{
Log("Nessuna statistica disponibile da esportare.");
MessageBox.Show(this, "Nessuna statistica disponibile.", "Esporta Statistiche", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
var dlg = new SaveFileDialog() { Filter = "CSV files|*.csv|All files|*.*", FileName = "auction_stats.csv" };
if (dlg.ShowDialog(this) != true) return;
using var sw = new StreamWriter(dlg.FileName, false, System.Text.Encoding.UTF8);
sw.WriteLine("ProductKey,ProductName,TotalAuctions,AverageBidsUsed,AverageFinalPrice,LastSeen");
foreach (var s in stats)
{
var line = $"\"{s.ProductKey}\",\"{s.ProductName}\",{s.TotalAuctions},{s.AverageBidsUsed:F2},{s.AverageFinalPrice:F2},{s.LastSeen:O}";
sw.WriteLine(line);
}
Log($"Statistiche esportate su: {dlg.FileName}");
MessageBox.Show(this, "Statistiche esportate con successo.", "Esporta Statistiche", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
Log($"[ERRORE] Esporta: {ex.Message}");
MessageBox.Show(this, "Errore durante esportazione: " + ex.Message, "Esporta Statistiche", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
}

View File

@@ -0,0 +1,41 @@
<Window x:Class="AutoBidder.Dialogs.SessionDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Configura Sessione" Height="440" Width="700"
Background="#0a0a0a" Foreground="#FFFFFF"
WindowStartupLocation="CenterOwner"
Icon="pack://application:,,,/Icon/favicon.ico"
ResizeMode="NoResize">
<Border Background="#1a1a1a" CornerRadius="8" Padding="16" Margin="8">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="Inserisci Cookie di sessione" FontSize="16" FontWeight="SemiBold" Foreground="#00CC66" Margin="0,0,0,12" />
<TextBlock Grid.Row="1" Text="Cookie di sessione (copia dal menu delle Impostazioni/Applicazioni di Chrome)" Foreground="#CCCCCC" FontSize="13" />
<TextBlock Grid.Row="2" Foreground="#888" FontSize="12" TextWrapping="Wrap" Margin="0,4,0,10">
<Run Text="Come trovare i cookie di sessione in Chrome:" />
<LineBreak/>
<Run Text="1. Apri Chrome e premi F12 (Windows) o Cmd+Option+I (Mac) per aprire gli Strumenti per sviluppatori." />
<LineBreak/>
<Run Text="2. Vai alla scheda 'Application'." />
<LineBreak/>
<Run Text="3. Nel pannello a sinistra, espandi 'Storage' e seleziona 'Cookies'." />
<LineBreak/>
<Run Text="4. Scegli il sito desiderato e copia il valore del cookie di sessione." />
</TextBlock>
<TextBox x:Name="CookieBox" Grid.Row="3" MinWidth="320" MinHeight="120" MaxHeight="220" VerticalScrollBarVisibility="Auto"
Background="#181818" Foreground="#00CCFF" BorderBrush="#444" BorderThickness="1" Padding="8" FontSize="14" AcceptsReturn="True" TextWrapping="Wrap" />
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,12,0,0">
<Button x:Name="OkButton" Content="OK" Width="110" Margin="6" Padding="10,8"
Style="{StaticResource SmallButtonStyle}" Background="#00CC66" Foreground="White" Click="OkButton_Click" />
<Button x:Name="CancelButton" Content="Annulla" Width="110" Margin="6" Padding="10,8"
Style="{StaticResource SmallButtonStyle}" Background="#666" Foreground="White" Click="CancelButton_Click" />
</StackPanel>
</Grid>
</Border>
</Window>

View File

@@ -0,0 +1,33 @@
using System.Windows;
namespace AutoBidder.Dialogs
{
public partial class SessionDialog : Window
{
public string AuthToken { get; private set; } = string.Empty;
public SessionDialog(string existingToken = "", string existingUsername = "")
{
InitializeComponent();
CookieBox.Text = existingToken ?? string.Empty;
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
AuthToken = CookieBox.Text?.Trim() ?? string.Empty;
if (string.IsNullOrEmpty(AuthToken))
{
MessageBox.Show("Cookie obbligatorio", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
DialogResult = true;
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
}
}

81
Mimante/Dockerfile Normal file
View File

@@ -0,0 +1,81 @@
# ============================================
# STAGE 1: Build
# ============================================
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Copy csproj and restore dependencies (cache layer)
COPY ["AutoBidder.csproj", "."]
RUN dotnet restore "./AutoBidder.csproj"
# Copy all source files
COPY . .
# Build application
WORKDIR "/src/."
RUN dotnet build "./AutoBidder.csproj" -c $BUILD_CONFIGURATION -o /app/build --no-restore
# ============================================
# STAGE 2: Publish
# ============================================
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
# RIMOSSO --no-build per evitare errore path
RUN dotnet publish "./AutoBidder.csproj" \
-c $BUILD_CONFIGURATION \
-o /app/publish \
/p:UseAppHost=false
# ============================================
# STAGE 3: Final Runtime
# ============================================
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
# Install curl for healthcheck and sqlite3
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ca-certificates \
sqlite3 && \
rm -rf /var/lib/apt/lists/*
# Create data directories for persistence
RUN mkdir -p /app/Data /app/Data/backups /app/logs && \
chmod 777 /app/Data /app/logs
# Copy published application
COPY --from=publish /app/publish .
# Expose port (single HTTP for simplicity)
EXPOSE 8080
# Environment variables (overridable via docker-compose/unraid)
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
ENV Kestrel__EnableHttps=false
# Database path - tutti i database SQLite e dati persistenti
# Può essere sovrascritto nel docker-compose per mappare un volume persistente
ENV DATA_PATH=/app/Data
# Autenticazione applicazione (OBBLIGATORIO)
ENV ADMIN_USERNAME=admin
ENV ADMIN_PASSWORD=
# Health check
# Aumentato timeout e start-period per Blazor Server
HEALTHCHECK --interval=30s --timeout=30s --start-period=90s --retries=5 \
CMD curl -f http://localhost:8080/ || exit 1
# Labels for metadata
LABEL org.opencontainers.image.title="AutoBidder" \
org.opencontainers.image.description="Sistema automatizzato gestione aste Bidoo - Blazor .NET 8" \
org.opencontainers.image.version="1.2.0" \
org.opencontainers.image.vendor="Alby96" \
org.opencontainers.image.source="https://gitea.encke-hake.ts.net/Alby96/Mimante"
# Entry point
ENTRYPOINT ["dotnet", "AutoBidder.dll"]

View File

@@ -0,0 +1,26 @@
______________________________________________________________________________________________________________
FUNZIONALITA
Cambiare la pagina delle statistiche in modo da aggiungere una sezione in più, oltre alle statistiche memorizzate in un automatico, in cui posso associare un range di prezzo e di puntate per ogni articolo, identificato tramite il suo nome
Aggiungere una scansione periodica e automatica delle aste terminate in modo da aggiornare automaticamente il mio elenco degli articoli delle aste terminate per aggiornare prezzo e numero di puntate usate in automatico. Molto importante: salvare anche l'ora di chiusura dell'asta
Aggiungere una funzionalità di aggiunta automatica delle aste al monitor appena compaiono nell'elenco delle aste disponibile cercando tramite sezione e nome articolo
Aggiungi una indicazione visiva nella colonna dello stato che indica quando un'asta pur essendo nello stato attiva il bot non punta perché fuori range oppure per altri motivi
Fare una tasto nelle statistiche che applichi massivamente i limiti a tutti gli articoli attualmente monitorati che hanno delle informazioni salvate nel database delle aste terminate
_______________________________________________________________________________________________________________
REWORK
Esegui un rework generico del sistema di log della singola asta e del log globale. Ci sono troppe righe inutili come tante righe simili duplicate nel log della singola asta e informazioni inutili nel log globale come per esempio l'indicazione del focus che si sposta su una certa riga. Valuta i cambiamenti e le ottimizzazioni da fare e applica le modifiche.
Esegui un rework della grafica in modo da eliminare le animazioni popup che danno fastidio all'usabilità del programma. In particolare intendo che quando il mouse passa su un pulsante o una griglia questa aumenta leggermente di dimensione per evidenziarsi ma questo non mi piace. Elimina questa cosa e sostituiscila piuttosto con una illuminazione o colorazione più chiara o scura per evidenziare il fatto che sto per selezionare quel particolare pulsante
_______________________________________________________________________________________________________________
CORREZIONI
Aggiungi più stati per indicare la strategia o il fatto che non sta puntando e per quale motivo.
In particolare oltre agli stati già presenti indicare anche il motivo per cui non sta puntando come per esempio "fuori range di prezzo", "fuori range di puntate", "asta terminata", "strategia non permette puntata", ecc

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="17px" height="18px" viewBox="0 0 17 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: sketchtool 57.1 (101010) - https://sketch.com -->
<title>E3DC3394-397D-4994-B12B-47234FB13863</title>
<desc>Created with sketchtool.</desc>
<g id="Product-Pages" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Home---Portrait-Version-A-Copy-6" transform="translate(-77.000000, -637.000000)">
<g id="Group-20" transform="translate(63.000000, 553.000000)">
<g id="Group-17-Copy" transform="translate(14.000000, 84.000000)">
<g id="001-settings" transform="translate(0.000000, 0.500000)">
<path d="M15.6392002,7.48800011 C14.1532002,7.20200011 13.4720002,5.46640008 14.3672002,4.24600006 L14.9952002,3.38800005 L13.6376002,2.03040003 L12.7936002,2.60200004 C11.5408002,3.45200005 9.83120015,2.70520004 9.60160014,1.21000002 L9.44080014,0.160000002 L7.52040011,0.160000002 L7.27200011,1.45360002 C6.9920001,2.90520004 5.31720008,3.59920005 4.09200006,2.76920004 L3.00320004,2.03040003 L1.64520002,3.38800005 L2.27360003,4.24600006 C3.16880005,5.46640008 2.48600004,7.20200011 1.00160001,7.48800011 L0,7.68040011 L0,9.60080014 L1.05000002,9.76160015 C2.54520004,9.99120015 3.29200005,11.7008002 2.44200004,12.9536002 L1.87040003,13.7976002 L3.22800005,15.1552002 L4.08600006,14.5272002 C5.30640008,13.6320002 7.0420001,14.3132002 7.32800011,15.7992002 L7.52040011,16.8008003 L9.44080014,16.8008003 L9.55320014,16.0616002 C9.78920015,14.5336002 11.5608002,13.7992002 12.8080002,14.7132002 L13.4108002,15.1552002 L14.7688002,13.7976002 L14.1968002,12.9536002 C13.3484002,11.7008002 14.0936002,9.99120015 15.5892002,9.76160015 L16.6408002,9.60080014 L16.6408002,7.68040011 L15.6392002,7.48800011 Z M8.47960013,10.0804002 C7.68440011,10.0804002 7.0408001,9.43520014 7.0408001,8.63960013 C7.0408001,7.84440012 7.68440011,7.20080011 8.47960013,7.20080011 C9.27520014,7.20080011 9.92040015,7.84440012 9.92040015,8.63960013 C9.92040015,9.43520014 9.27520014,10.0804002 8.47960013,10.0804002 Z" id="Fill-1" fill="#C7CAC7"/>
<path d="M8.47960013,5.60080008 C6.8016001,5.60080008 5.44080008,6.9616001 5.44080008,8.63960013 C5.44080008,10.3192002 6.8016001,11.6804002 8.47960013,11.6804002 C10.1592002,11.6804002 11.5204002,10.3192002 11.5204002,8.63960013 C11.5204002,6.9616001 10.1592002,5.60080008 8.47960013,5.60080008 Z M8.47960013,10.0804002 C7.68440011,10.0804002 7.0408001,9.43520014 7.0408001,8.63960013 C7.0408001,7.84440012 7.68440011,7.20080011 8.47960013,7.20080011 C9.27520014,7.20080011 9.92040015,7.84440012 9.92040015,8.63960013 C9.92040015,9.43520014 9.27520014,10.0804002 8.47960013,10.0804002 Z" id="Fill-2" fill="#556080"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.96 32.35"><defs><style>.cls-1{fill:#38454f;}.cls-2{fill:#1caee4;}.cls-3{fill:#1081e0;}.cls-4{fill:#cbd4d8;}.cls-5{fill:#546a79;}</style></defs><title>Asset 10002-app</title><g id="Layer_2" data-name="Layer 2"><g id="Livello_1" data-name="Livello 1"><path class="cls-1" d="M15.76,32.35H3.2A3.21,3.21,0,0,1,0,29.14V3.2A3.2,3.2,0,0,1,3.2,0H15.76A3.2,3.2,0,0,1,19,3.2V29.14A3.21,3.21,0,0,1,15.76,32.35Z"/><rect class="cls-2" x="1.67" y="3.35" width="15.61" height="23.98"/><path class="cls-3" d="M3.35,7.81a.56.56,0,0,0,.39-.17L6,5.41a.56.56,0,0,0,0-.79.57.57,0,0,0-.79,0L3,6.86a.54.54,0,0,0,0,.78A.56.56,0,0,0,3.35,7.81Z"/><path class="cls-3" d="M3.35,10.6a.56.56,0,0,0,.39-.17L4.86,9.32a.57.57,0,0,0,0-.79.56.56,0,0,0-.79,0L3,9.64a.57.57,0,0,0,.4,1Z"/><path class="cls-3" d="M5.18,7.41a.59.59,0,0,0-.16.4.57.57,0,0,0,.16.39.6.6,0,0,0,.4.17A.58.58,0,0,0,6,8.2a.57.57,0,0,0,.16-.39.56.56,0,0,0-1-.4Z"/><path class="cls-3" d="M6.3,7.09a.54.54,0,0,0,.39.16.57.57,0,0,0,.4-.16L8.76,5.41a.56.56,0,0,0,0-.79.57.57,0,0,0-.79,0L6.3,6.3A.56.56,0,0,0,6.3,7.09Z"/><path class="cls-3" d="M8,7.41l-5,5a.56.56,0,0,0,.4,1,.54.54,0,0,0,.39-.16l5-5a.56.56,0,0,0,0-.79A.57.57,0,0,0,8,7.41Z"/><path class="cls-3" d="M9.08,6.3a.57.57,0,0,0-.16.39.59.59,0,0,0,.16.4.61.61,0,0,0,.4.16A.55.55,0,0,0,10,6.69a.57.57,0,0,0-.16-.39A.59.59,0,0,0,9.08,6.3Z"/><path class="cls-3" d="M11.55,4.62a.57.57,0,0,0-.79,0l-.56.56a.56.56,0,0,0,.4,1A.54.54,0,0,0,11,6l.56-.56A.56.56,0,0,0,11.55,4.62Z"/><path class="cls-4" d="M11.15,2.23H7.81a.56.56,0,0,1-.56-.56.55.55,0,0,1,.56-.55h3.34a.55.55,0,0,1,.56.55A.56.56,0,0,1,11.15,2.23Z"/><path class="cls-5" d="M16.17,2.23h-.56a.56.56,0,0,1-.55-.56.55.55,0,0,1,.55-.55h.56a.55.55,0,0,1,.56.55A.56.56,0,0,1,16.17,2.23Z"/><path class="cls-5" d="M13.94,2.23h-.56a.56.56,0,0,1-.55-.56.55.55,0,0,1,.55-.55h.56a.55.55,0,0,1,.56.55A.56.56,0,0,1,13.94,2.23Z"/><path class="cls-4" d="M10.87,30.67H8.09a.84.84,0,0,1-.84-.83h0A.85.85,0,0,1,8.09,29h2.78a.85.85,0,0,1,.84.84h0A.84.84,0,0,1,10.87,30.67Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31.83 32.52"><defs><style>.cls-1{fill:#ffd039;}.cls-2{fill:#f4b70c;}.cls-3{fill:#ffbb64;}.cls-4{fill:#ffae47;}.cls-5{fill:#ffdf65;}.cls-6{fill:#ffcd2c;}.cls-7{fill:#ffa035;}.cls-8{fill:#f78819;}</style></defs><title>Asset 9002-cup</title><g id="Layer_2" data-name="Layer 2"><g id="Livello_1" data-name="Livello 1"><path class="cls-1" d="M31.05,5.85h0a3.61,3.61,0,0,0-2.83-1.36H24.84a.47.47,0,0,0-.47.48V7.05a.47.47,0,0,0,.47.48h3.38a.56.56,0,0,1,.45.22.58.58,0,0,1,.11.46,9,9,0,0,1-1.93,4,5.79,5.79,0,0,1-2.37,1.58.46.46,0,0,0-.31.34,8.32,8.32,0,0,1-.84,2.26.46.46,0,0,0,0,.5.46.46,0,0,0,.39.2h.08a9,9,0,0,0,5.27-2.83,11.8,11.8,0,0,0,2.64-5.33A3.61,3.61,0,0,0,31.05,5.85Z"/><path class="cls-2" d="M27,12.28V12l-.15.16a5.79,5.79,0,0,1-2.37,1.58.46.46,0,0,0-.31.34,8.32,8.32,0,0,1-.84,2.26.46.46,0,0,0,0,.5.46.46,0,0,0,.39.2h.08a10,10,0,0,0,2.22-.65A9.45,9.45,0,0,0,27,12.28Z"/><path class="cls-2" d="M24.37,5V7.05a.47.47,0,0,0,.47.48H27v-3H24.84A.47.47,0,0,0,24.37,5Z"/><path class="cls-3" d="M19.5,28.05c-.14-.11-1.42-1.18-1.58-7a.49.49,0,0,0-.17-.36.54.54,0,0,0-.39-.1,8.66,8.66,0,0,1-1.44.13h0a8.69,8.69,0,0,1-1.45-.13.54.54,0,0,0-.39.1.49.49,0,0,0-.17.36c-.16,5.8-1.44,6.87-1.58,7a.44.44,0,0,0-.32.5.51.51,0,0,0,.5.42h6.81a.51.51,0,0,0,.5-.42A.44.44,0,0,0,19.5,28.05Z"/><path class="cls-4" d="M19.5,28.05c-.14-.11-1.42-1.18-1.58-7a.49.49,0,0,0-.17-.36.54.54,0,0,0-.39-.1,8.66,8.66,0,0,1-1.44.13h0l-.46,0a.48.48,0,0,1,.16.35c.16,5.8,1.43,6.87,1.58,7a.44.44,0,0,1,.32.5A.51.51,0,0,1,17,29h2.31a.51.51,0,0,0,.5-.42A.44.44,0,0,0,19.5,28.05Z"/><path class="cls-1" d="M.79,5.85h0A3.58,3.58,0,0,1,3.61,4.49H7A.47.47,0,0,1,7.46,5V7.05A.47.47,0,0,1,7,7.53H3.61a.56.56,0,0,0-.45.22.58.58,0,0,0-.11.46,9,9,0,0,0,1.93,4,5.79,5.79,0,0,0,2.37,1.58.46.46,0,0,1,.31.34,8.32,8.32,0,0,0,.84,2.26.46.46,0,0,1,0,.5.46.46,0,0,1-.39.2H8a9,9,0,0,1-5.27-2.83A11.8,11.8,0,0,1,.09,8.89,3.58,3.58,0,0,1,.79,5.85Z"/><path class="cls-2" d="M4.83,12.28V12l.15.16a5.79,5.79,0,0,0,2.37,1.58.46.46,0,0,1,.31.34,8.32,8.32,0,0,0,.84,2.26.46.46,0,0,1,0,.5.46.46,0,0,1-.39.2H8a10.16,10.16,0,0,1-2.22-.65A9.45,9.45,0,0,1,4.83,12.28Z"/><path class="cls-2" d="M7.46,5V7.05A.47.47,0,0,1,7,7.53H4.83v-3H7A.47.47,0,0,1,7.46,5Z"/><path class="cls-5" d="M24.84,2.76H7a.47.47,0,0,0-.48.48v9a9.41,9.41,0,1,0,18.81,0v-9A.47.47,0,0,0,24.84,2.76Z"/><path class="cls-6" d="M24.84,2.76H22.62a.47.47,0,0,1,.47.48v9a9.41,9.41,0,0,1-8.29,9.34,8.32,8.32,0,0,0,1.12.07,9.42,9.42,0,0,0,9.4-9.41v-9A.47.47,0,0,0,24.84,2.76Z"/><path class="cls-7" d="M20.06,11.17a1.05,1.05,0,0,0,.27-1.08,1,1,0,0,0-.85-.71l-1.76-.26a.08.08,0,0,1-.07,0l-.79-1.6a1,1,0,0,0-.94-.58h0a1,1,0,0,0-.95.58l-.79,1.6a.08.08,0,0,1-.07,0l-1.76.26a1,1,0,0,0-.85.71,1.05,1.05,0,0,0,.27,1.08L13,12.41a.1.1,0,0,1,0,.09l-.3,1.75a1.05,1.05,0,0,0,1.53,1.11l1.57-.83H16l1.57.83a1.11,1.11,0,0,0,.49.12,1.07,1.07,0,0,0,.62-.2,1,1,0,0,0,.42-1l-.3-1.75a.14.14,0,0,1,0-.09Z"/><path class="cls-8" d="M19.48,9.38,19,9.31,16.74,11.5a.57.57,0,0,0-.17.51l.52,3.11.44.24a1.11,1.11,0,0,0,.49.12,1.07,1.07,0,0,0,.62-.2,1,1,0,0,0,.42-1l-.3-1.75a.14.14,0,0,1,0-.09l1.27-1.24a1.05,1.05,0,0,0,.27-1.08A1,1,0,0,0,19.48,9.38Z"/><path class="cls-5" d="M25.12,31.89A5.14,5.14,0,0,0,20.43,28h-9a5.14,5.14,0,0,0-4.69,3.88.47.47,0,0,0,.07.43.49.49,0,0,0,.39.2h17.5a.48.48,0,0,0,.38-.2A.47.47,0,0,0,25.12,31.89Z"/><path class="cls-6" d="M25.12,31.89A5.14,5.14,0,0,0,20.43,28H16.77a5.14,5.14,0,0,1,4.69,3.88.5.5,0,0,1-.07.43.49.49,0,0,1-.39.2h3.67a.48.48,0,0,0,.38-.2A.47.47,0,0,0,25.12,31.89Z"/><path class="cls-1" d="M25.62,0H6.21a1.86,1.86,0,0,0,0,3.71H25.62a1.86,1.86,0,0,0,0-3.71Z"/><path class="cls-2" d="M25.62,0H23.46a1.86,1.86,0,1,1,0,3.71h2.16a1.86,1.86,0,0,0,0-3.71Z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -0,0 +1 @@
var configuration_map = {"notificationRuleList":[],"config":{"enableNotification":true},"passKey":"{}"};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
!function(){"use strict";"undefined"!=typeof PushSubscriptionOptions&&PushSubscriptionOptions.prototype.hasOwnProperty("applicationServerKey")||void 0!==window.safari&&void 0!==window.safari.pushNotification?function(){const n=document.createElement("script");n.src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.es6.js?v=160510",n.defer=!0,document.head.appendChild(n)}():function(){let n="Incompatible browser.";"Apple Computer, Inc."===navigator.vendor&&navigator.maxTouchPoints>0&&(n+=" Try these steps: https://tinyurl.com/bdh2j9f7"),console.info(n)}()}();
//# sourceMappingURL=OneSignalSDK.page.js.map

View File

@@ -0,0 +1 @@
window.google_ad_status = 1;

View File

@@ -0,0 +1,220 @@
var mult_send = 0;
function Contest_Send(){
mult_send = mult_send + 1;
PreparaContestSend('senduscontestform',false);
if (mult_send == 1)
{
AJAXReqContestSend("POST","send_us_contest.php",true);
}
}
function PreparaContestSend(nome,ele){
stringa = "";
var form = document.forms[nome];
var numeroElementi = form.elements.length;
for(var i = 0; i < numeroElementi; i++){
nmfrm = form.elements[i].name;
if(i < numeroElementi-1)
{
stringa += form.elements[i].name+"="+encodeURIComponent(form.elements[i].value)+"&";
}
else
{
stringa += form.elements[i].name+"="+encodeURIComponent(form.elements[i].value);
}
}
}
function AJAXReqContestSend(method,url,bool){
if(window.XMLHttpRequest){
myReq = new XMLHttpRequest();
} else
if(window.ActiveXObject){
myReq = new ActiveXObject("Microsoft.XMLHTTP");
if(!myReq){
myReq = new ActiveXObject("Msxml2.XMLHTTP");
}
}
if(myReq){
myReq.onreadystatechange = state_ContestSend;
myReq.open(method,url,bool);
myReq.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
myReq.send(stringa);
}else{
alert("Impossibilitati ad usare AJAX");
}
}
function state_ContestSend(bReload){
if (myReq.readyState==4){
mult_send = 0;
if (myReq.status==200){
ResponseContestSend(myReq.responseText);
}
else {
if (bDebug) {alert("Problem retrieving XML data");}
}
}
}
function ResponseContestSend(sResponse){
var vetResp = sResponse.split('|');
if (vetResp[0].toUpperCase() == 'OK')
{
if (MM_findObj("contest_name_msg"))
{
DisplayHTMLData(MM_findObj('contest_name_msg'), '&nbsp;');
}
if (MM_findObj("contest_video_msg"))
{
DisplayHTMLData(MM_findObj('contest_video_msg'), '&nbsp;');
}
if (MM_findObj("send_box_contest"))
{
MM_findObj("send_box_contest").style.display='none';
}
if (MM_findObj("send_box_contest_response"))
{
MM_findObj("send_box_contest_response").style.display='block';
}
}
else
{
if (MM_findObj("contest_name_msg"))
{
DisplayHTMLData(MM_findObj('contest_name_msg'), '&nbsp;');
}
if (MM_findObj("contest_video_msg"))
{
DisplayHTMLData(MM_findObj('contest_video_msg'), '&nbsp;');
}
for (b=1; b<vetResp.length; b++)
{
var f = vetResp[b].split(';');
var fldcont = f[0];
var msgcont = f[1];
if (fldcont == 'contest_name')
{
DisplayHTMLData(MM_findObj(fldcont + '_msg'), msgcont);
}
if (fldcont == 'contest_video')
{
DisplayHTMLData(MM_findObj(fldcont + '_msg'), msgcont);
}
}
}
}
var HTTP_FIRSTAUCT_URL = new String ('first_auct.php');
var xmlhttpFirstAuct = null;
function FirstAuct() {
var sUrlFirstAuct = HTTP_FIRSTAUCT_URL + "?chk=" + new Date().valueOf();
if (xmlhttpFirstAuct) {
if ((xmlhttpFirstAuct.readyState != 4) && (xmlhttpFirstAuct.readyState != 0)) {
return true;
}
}
try
{
if (window.XMLHttpRequest){
xmlhttpFirstAuct = new XMLHttpRequest();
} else if (window.ActiveXObject){
xmlhttpFirstAuct = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttpFirstAuct != null){
xmlhttpFirstAuct.onreadystatechange = state_FirstAuct;
xmlhttpFirstAuct.open("GET",sUrlFirstAuct,true);
xmlhttpFirstAuct.send(null);
return true;
} else {
if (bDebug)
{
alert("Your browser does not support XMLHTTP.");
}
return false;
}
}
catch (e) {
xmlhttpFirstAuct = null;
if (bDebug) alert('Errore in loadXMLDocElenco');
}
finally {}
}
function state_FirstAuct(){
if (xmlhttpFirstAuct.readyState==4){
if (xmlhttpFirstAuct.status!=200){
if (bDebug) {
alert("Problem retrieving XML data");
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,129 @@
btn-promo {
border-radius: 3px;
background: linear-gradient(rgb(82, 157, 253), rgb(46, 114, 202));
background: -moz-linear-gradient(rgb(82, 157, 253), rgb(46, 114, 202));
background: -webkit-linear-gradient(rgb(82, 157, 253), rgb(46, 114, 202));
background: -o-linear-gradient(rgb(82, 157, 253), rgb(46, 114, 202));
background: -ms-linear-gradient(rgb(82, 157, 253), rgb(46, 114, 202));
color: #fff;
}
.btn.btn-promo:hover {
background: linear-gradient(rgb(117, 175, 250), rgb(53, 124, 216));
background: -moz-linear-gradient(rgb(117, 175, 250), rgb(53, 124, 216));
background: -webkit-linear-gradient(rgb(117, 175, 250), rgb(53, 124, 216));
background: -o-linear-gradient(rgb(117, 175, 250), rgb(53, 124, 216));
background: -ms-linear-gradient(rgb(117, 175, 250), rgb(53, 124, 216));
color: #fff;
}
.mCSB_inside > .mCSB_container {
margin-right: 0px;
}
.mCSB_scrollTools .mCSB_draggerRail {
width: 6px;
background-color: #e2e2e2;
}
.mCSB_scrollTools .mCSB_draggerContainer {
left: 10px;
}
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
background-color: #20cb9a !important;
width: 100%;
}
.loader {
margin: 10px auto;
border: 5px solid #f3f3f3;
/* Light grey */
border-top: 5px solid #20cb9a;
/* Blue */
border-radius: 50%;
width: 20px;
height: 20px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
.stopScroll{
overflow: hidden !important;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@media screen and (max-width: 384px) {
#prod_win_cont_modal h3 {
padding-left: 30px;
padding-right: 30px;
}
}
@media screen and (max-width: 320px) {
.prod_won__2 {
margin-left: 1px !important;
margin-right: 1px !important;
}
#prod_win_cont_modal .col-xs-6{
padding-left: 5px;
padding-right: 5px;
}
}
#modal iframe {
width: 99%;
}
#myModal3 .modal-dialog, #myModal2 .modal-dialog {
margin: 30px auto;
}
.settingBox form div {
border-bottom: 1px solid #efefef;
padding: 15px;
font-weight: 500;
font-size: 12px;
color: #818181;
}
@media screen and (max-width: 991px) {
#menuModal .show {
display: block;
}
#menuModal .modal-header {
height: auto;
}
#menuModal .height {
height: 0px;
}
.parentOverflowY {
overflow-y: hidden;
}
}
#notifBoxContainer .mCSB_container {
top: 0px;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,206 @@
const AuctionsBidManage = (function() {
const _defaultPart = "divAsta";
let _nAstePerBonus = 10;
let _limiteAsteVinte = 10;
let _nAstePuntataVinte = 0;
let _percentualeBonus = 0;
let _nPuntateVinteOggi = 0;
let _nAsteConfermate = 0;
let _nPuntateRiscattate = 0;
let _nPuntateDaRiscattare = 0;
let _initialized = false;
let _defaultValidUntil = null;
let _viewSlot = false;
function _defaultObj() {
return {
auctions: {},
nAsteConfermate: 0,
percentualeBonus: 0,
limiteAsteVinte: 10,
nAstePerBonus: 10,
validUntil: getDefaultValidUntil()
}
}
/**
* Aggiunge una nuova asta all'oggetto delle aste di puntata vinte in un giorno
* @param idAuction {int}
*/
function add(idAuction){
let result = get();
let retrievedObject = JSON.parse(result);
let auctionBidWin = retrievedObject === null ? _defaultObj() : retrievedObject ;
let auctionElement = document.getElementById(_defaultPart + idAuction);
let creditValue = parseInt(auctionElement.getAttribute('data-credit-value')) > 0 ? parseInt(auctionElement.getAttribute('data-credit-value')) : 0;
if(creditValue > 0 && Object.keys(auctionBidWin.auctions).length <= auctionBidWin.limiteAsteVinte){
// let obj =
// {
// idAuction: idAuction,
// value: creditValue
// }
// ;
//
// if(!auctionBidWin.auctions.hasOwnProperty(idAuction)){
// auctionBidWin.auctions[idAuction] = obj;
// }
// let newObj = JSON.stringify(auctionBidWin);
//
// localStorage.setItem("auctionBidWin", newObj);
getRemoteData();
}
return;
}
function getDefaultValidUntil(){
return _defaultValidUntil;
}
function setDefaultValidUntil(untilTimestamp){
_defaultValidUntil = untilTimestamp;
}
/**
* Ritornano le informazioni salvate nel localStorage
* @returns {string}
*/
function get(){
return localStorage.getItem('auctionBidWin');
}
/**
* Rimuove dal localStorage
*/
function remove(){
localStorage.removeItem('auctionBidWin');
}
function getRemoteData(callback = null){
fetch('./ajax/get_auction_bids_info_banner.php',{
method: "GET"
})
// gestisci il successo
.then(response => response.json()) // converti a json
.then(function (data) {
let obj = {
auctions: data.auctions,
nAsteConfermate: data.nAsteConfermate,
nAsteVinte: data.nAsteVinte,
nPuntateRiscattate: data.nPuntateRiscattate,
nPuntateDaRiscattare: data.nPuntateDaRiscattare,
limiteAsteVinte: data.limiteAsteVinte,
nAstePerBonus: data.nAstePerBonus,
percentualeBonus: data.percentualeBonus,
validUntil: data.validUntil,
viewSlot: data.viewSlot,
extraSlots: data.extraSlots, //un elenco degli slots non scaduti e non aperti
nPuntateBonus: data.nPuntateBonus
};
let newObj = JSON.stringify(obj);
localStorage.setItem("auctionBidWin", newObj);
if(callback !== null){
callback();
}
})
.catch(err => console.log('Request Failed', err)); // gestisci gli errori
}
function retriveInfoComponent(){
let result = JSON.parse(get());
if(result) {
_nAstePuntataVinte = result.nAsteVinte;
_limiteAsteVinte = result.limiteAsteVinte;
_nAsteConfermate = result.nAsteConfermate;
_nPuntateDaRiscattare = result.nPuntateDaRiscattare;
_nPuntateRiscattate = result.nPuntateRiscattate;
_nAstePerBonus = result.nAstePerBonus;
_percentualeBonus = result.percentualeBonus;
_viewSlot = result.viewSlot;
_nPuntateVinteOggi = result.nPuntateDaRiscattare + result.nPuntateRiscattate;
/*if (_percentualeBonus > 0) {
let valorePercentualeBonus = ((_nPuntateVinteOggi * _percentualeBonus) / 100);
_nPuntateVinteOggi = _nPuntateVinteOggi + valorePercentualeBonus;
}*/
let asteRimanentiPerBonus = _nAstePerBonus - _nAstePuntataVinte;
return {
auctions: result.auctions,
asteRimanentiPerBonus: asteRimanentiPerBonus,
nAstePerBonus: _nAstePerBonus,
nAstePuntataVinte: _nAstePuntataVinte,
percentualeBonus: _percentualeBonus,
nPuntateVinteOggi: parseInt(_nPuntateVinteOggi),
limiteAsteVinte: _limiteAsteVinte,
nAsteConfermate: _nAsteConfermate,
nPuntateDaRiscattare: _nPuntateDaRiscattare,
nPuntateRiscattate: _nPuntateRiscattate,
viewSlot: _viewSlot,
extraSlots: result.extraSlots,
nPuntateBonus: result.nPuntateBonus
}
}
}
/**
*
* @param auctionId
* @returns {boolean}
*/
function searchByAuctionId(auctionId){
let data = retriveInfoComponent();
let controllo = false;
if(data == undefined || data == null ){ return; }
let keys = Object.keys(data.auctions);
for(let i= 0; i <= keys.length; i++){
if(keys[i] === auctionId){
return true;
}
}
return false;
}
function initRemoteData(){
if(!_initialized){
getRemoteData();
setInterval(function (){
getRemoteData();
}, 1000 * 60);
}
_initialized = true;
}
return {
add,
get,
remove,
getRemoteData,
retriveInfoComponent,
initRemoteData,
setDefaultValidUntil,
searchByAuctionId
}
})();

View File

@@ -0,0 +1,927 @@
#wrapBonusSection{
width: 100%;
background-color: #fff;
margin-bottom: 20px;
-webkit-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.2);
-moz-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.2);
box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.2);
border-top: 1px solid #d0d0d0;
display: none;
cursor: pointer;
}
#wrapBonusSection.visible{
display: block;
}
#BonusSection{
display: flex;
justify-content: space-between;
width: 65%;
min-height: 40px;
margin: 0 auto;
align-items: center;
margin-bottom: -25px;
}
@media (max-width: 576px) {
#BonusSection{
margin-bottom: 0;
}
}
#BonusSection .wrap-msg-bonus, #BonusSection .pt-2 .wrap-progress, #BonusSection .pt-1 .wrap-progress, #BonusSection .pt-3 .wrap-progress, #BonusSection .pt-3 .wrap-bids, #auctionBidsModal .wrap-msg-bonus, #auctionBidsModal .wrap-msg-bonus .wrap-progress, #bidsBonusSection #section2 .wrap-progress, #bidsBonusSection #section3 .wrap-progress{
display: flex;
justify-content: center;
align-items: center;
}
#bidsBonusSection #section2 .wrap-progress{
font-size: 14px;
}
#auctionBidsModal #countdownAddSlot{
font-weight: bold;
color: #55bc62;
}
#auctionBidsModal .wrap-msg-bonus{
margin-bottom: 25px;
}
#BonusSection .pt-2 .item, #BonusSection .pt-3 .item{
margin: 2px;
}
#BonusSection .pt-2, #BonusSection .pt-1, #BonusSection .pt-3, #auctionBidsModal .wrap-pt2{
display: flex;
justify-content: center;
align-items: center;
}
#auctionBidsModal .wrap-pt2 .bonus-obtained{
font-size: 12px;
color: #6F6F6F;
font-weight: bold;
margin-top: 3px;
display: none;
}
#auctionBidsModal .wrap-pt2{
justify-content: space-around;
align-items: flex-start;
margin-top: 20px;
border-top: 1px solid #DBDBDB;
padding-top: 20px;
font-size: 13px;
margin-bottom: 10px;
}
@media (max-width: 340px) {
#auctionBidsModal .wrap-pt2{
font-size: 12px;
}
}
#auctionToBonusModal{
font-size: 15px;
color: #333;
}
#BonusSection .text{
color: #6D6D6D;
font-size: 15px;
margin: auto 4px;
}
#BonusSection .pt-2 img{
height: 29px;
}
#BonusSection .pt-2 .img-emoji img, #auctionBidsModal .img-emoji img {
height: 18px;
width: 18px;
margin-left: -10px;
margin-top: -3px;
}
#auctionBidsModal .img-emoji img{
width: 24px;
height: 24px;
}
#auctionBidsModal .img-emoji{
z-index: 9;
margin-left: -3px;
margin-right: 2px;
}
#BonusSection .pt-dx img, #auctionBidsModal .pt-dx img, #auctionBidsModal .pt-center img{
width: 16px;
}
#BonusSection .pt-2 .wrap-progress .progress{
margin-left: 5px;
background-color: #D1D1D1;
}
#auctionBidsModal .progress{
width: 56px;
height: 24px;
margin: 0 6px;
position: relative;
background-color: #D1D1D1;
border-radius: 20px;
}
#auctionBidsModal .progress{
width: 110px;
height: 22px;
}
#auctionBidsModal .pt-1 .progress{
height: 11px;
}
#BonusSection .progress, #auctionBidsModal .progress{
width: 60px;
height: 13px;
margin-bottom: 0px;
}
#auctionBidsModal .progress{
width: 90px;
}
#BonusSection #countdown-bonus{
width: 60px;
color: #fff;
background-color: #FF0658;
font-weight: bold;
font-size: 11px;
padding: 0px 4px;
height: 16px;
border-radius: 5px;
}
#BonusSection #bonus-earned, #BonusSection #bonus-active-all{
display: none;
font-weight: bold;
margin-right: 15px;
}
@media (max-width: 576px) {
#BonusSection #bonus-earned, #BonusSection #bonus-active-all{
font-size: 12px;
}
}
#BonusSection #bonus-active-all{
color: #55bc62;
}
#BonusSection .progress .progress-bar, #auctionBidsModal .pt-1 .progress .progress-bar, #auctionBidsModal #bidsBonusSection #section2 .progress .progress-bar, #auctionBidsModal .progress .progress-bar{
background: rgb(4,170,176);
background: linear-gradient(90deg, rgba(4,170,176,1) 0%, rgba(7,206,173,1) 100%);
box-shadow: none;
}
#BonusSection .progress .progressbar-text{
position: absolute;
top: 2px;
height: 22px;
color: #000;
width: 100%;
left: 0;
margin: 0;
font-size: 16px;
font-weight: bold;
}
#auctionBidsModal .progress .progressbar-text{
font-size: 15px;
top: 0;
}
#todayBids, #auctionBidsModal{
font-size: 16px;
color: #333;
}
#auctionBidsModal{
font-weight: normal;
}
#auctionToBonus.active{
font-weight: bold;
color: #000;
}
#confirmedAuctionWithBonus{
display: none;
margin-left: 5px;
}
#confirmedAuctionWithBonus .value{
font-weight: bold;
}
.wrap-bonus-mobile{
display: flex;
justify-content: center;
align-items: center;
}
.wrap-bonus-mobile .wrap-bonus-value{
font-size: 14px;
color: #504E4E;
margin-left: 5px;
}
#auctionBidsModal .wrap-bonus-value{
margin-right: 2px;
}
#BonusSection .pt-3 img{
width: 15px;
}
#BonusSection .wrap-title-bonus{
display: flex;
}
#BonusSection .wrap-title-bonus .icon-check{
width: 15px;
display: none;
margin-right: 4px;
}
#BonusSection .pt-2 #countdown-bonus{
display: none;
}
@media (max-width: 1040px) {
#BonusSection{
width: 100%;
justify-content: space-around;
min-height: 50px;
}
#BonusSection .pt-1, #BonusSection .pt-2, #BonusSection .pt-3{
flex-direction: column;
}
#BonusSection .pt-3 .wrap-bids{
display: flex;
justify-content: center;
align-items: center;
}
#BonusSection .text {
font-size: 12px;
}
#BonusSection .pt-2 img{
margin-right: 5px;
height: 18px;
width: 10px;
}
#BonusSection .pt-1 .progress {
width: 90px;
height: 10px;
}
#todayBids{
font-size: 14px;
}
#BonusSection .pt-3 .item{
margin: 0;
}
#BonusSection .pt-3 img{
width: 13px;
margin-top: -1px;
margin-left: 3px;
}
#BonusSection .wrap-msg-bonus{
flex-direction: column;
justify-content: flex-start;
align-items: baseline;
}
.wrap-bonus-mobile{
display: flex;
justify-content: center;
align-items: center;
}
}
@media (max-width: 576px) {
#BonusSection {
min-height: 45px;
}
}
@media (max-width: 360px) {
#BonusSection .text {
font-size: 11px;
}
}
#auctionBidsModal .pt-left .wrap-progress, #auctionBidsModal .pt-dx .wrap-bids, #auctionBidsModal .pt-center .wrap-bids{
display: flex;
justify-content: center;
align-items: center;
margin-top: 5px;
font-weight: bold;
}
#auctionBidsModal .pt-center .item, #auctionBidsModal .pt-dx .item{
margin-left: 1px;
margin-right: 1px;
}
#auctionBidsModal .pt-center .item img, #auctionBidsModal .pt-dx .item img{
margin-left: 2px;
margin-right: 2px;
margin-top: -5px;
}
#auctionToGoModal{
font-size: 14px;
font-weight: bold;
}
@media (max-width: 340px) {
#auctionBidsModal .wrap-pt2{
font-size: 12px;
}
#auctionToGoModal, #todayBidsModal, #todayBidsPayedModal{
font-size: 13px;
}
}
#todayBidsModal, #todayBidsPayedModal{
font-size: 14px;
font-weight: bold;
}
#loaderAuctionBids{
min-height: 40px;
text-align: center;
padding: 5px;
font-size: 20px;
}
#auctionToGo{
color: #000;
margin-left: 5px;
}
.loader-data{
display: block;
position: relative;
margin-right: 0px !important;
margin-left: 0px !important;
}
.loader-data::before{
content: "";
background-color: #eaeaea;
display: block;
width: 100%;
height: 22px;
position: absolute;
}
@media (max-width: 576px) {
.loader-data{
margin-top: 2px !important;
margin-bottom: 2px !important;
}
.loader-data::before{
height: 16px;
min-width: 20px;
}
}
#BonusSection .pt-1, #BonusSection .pt-2, #BonusSection .pt-3{
position: relative;
}
.loader-data img{
display: none !important;
}
.wrap-countdown-auctionBidsModal{
color: #55BC62;
font-weight: bold;
}
#auctionBidsModal .wrapTitle{
margin: 20px auto 10px;
display: flex;
align-items: center;
justify-content: center;
}
#auctionBidsModal .modal-body{
padding: 0;
}
#auctionBidsModal .contentModal #bidsBonusSection .content, #auctionBidsModal .contentModal #rankingBonusSection{
font-size: 16px;
text-align: center;
margin-top: 15px;
padding: 15px;
}
#auctionBidsModal .contentModal #bidsBonusSection .content{
margin-top: 0;
padding: 0;
}
#auctionBidsModal .contentModal #bidsBonusSection .content.parent-content-div {
padding: 0 0 5px 0;
}
#tabsSection{
display: flex;
align-items: center;
}
@media (max-width: 576px) {
#tabsSection{
font-size: 14px;
}
}
#tabsSection .pt-1{
width: 55%;
}
#tabsSection .pt-2{
width: 40%;
}
#tabsSection .pt-1, #tabsSection .pt-2{
padding: 8px 18px;
border-bottom: 1px solid #BCBCBC;
text-align: center;
font-size: 14px;
}
#tabsSection .pt-1 .fa, #tabsSection .pt-2 .fa{
margin-right: 5px;
}
#tabsSection .pt-3{
width: 10%;
padding: 5px 10px;
border-bottom: 1px solid #BCBCBC;
}
button[aria-label='Close'] span{
font-size: 26px;
}
@media (max-width: 576px) {
#tabsSection .pt-3{
padding: 4px 10px;
}
#tabsSection .pt-1, #tabsSection .pt-2{
font-size: 12px;
padding: 8px 10px;
}
button[aria-label='Close'] span{
font-size: 25px;
}
}
#tabsSection .pt-1.active, #tabsSection .pt-2.active, #tabsSection .pt-3.active{
border-color: #2F80ED;
}
#tabsSection .pt-1.active a, #tabsSection .pt-2.active a, #tabsSection .pt-3.active a, #tabsSection .pt-1.active a:hover, #tabsSection .pt-2.active a:hover{
color: #2F80ED;
font-weight: bold;
text-decoration: none;
}
#tabsSection .pt-1 a, #tabsSection .pt-2 a{
color: #7d7d7d;
}
#tabsSection .pt-1 a:hover, #tabsSection .pt-2 a:hover{
text-decoration: none;
font-weight: normal;
color: #2F80ED;
}
#rankingBonusSection{
display: none;
}
#bidsBonusSection #section2 .box-congrats,
#bidsBonusSection #section3 .box-congrats{
margin-top: 12px;
}
#bidsBonusSection #section2, #bidsBonusSection #section3{
display: none;
}
#bidsBonusSection #section2 .titleModal{
font-size: 20px;
}
#auctionBidsModal .wrap-credit-bonus{
display: inline-block;
}
#auctionBidsModal #bidsBonusSection .wrap-content{
display: flex;
flex-direction: column;
}
#bidsBonusSection #section2 .summary-body #countdown-bonus{
font-size: 14px;
}
#bidsBonusSection #section2 .summary-body .countdown{
color: #FF0658;
}
#bidsBonusSection #section2 .summary-body #countdownForBonus{
font-weight: bold;
}
#bidsBonusSection #section2 .summary{
margin-top: 30px;
}
#bidsBonusSection #section2 .summary-body{
width: 250px;
margin: -18px auto 25px;
border: 1px solid #000;
border-radius: 5px;
padding: 20px 15px;
box-shadow: 2px 2px 3px 1px rgba(208, 209, 213, 0.2), 0 2px 2px 1px rgba(220, 221, 224, 0.2);
-webkit-box-shadow: 2px 2px 3px 1px rgba(208, 209, 213, 0.2), 0 2px 2px 1px rgba(220, 221, 224, 0.2);
-moz-box-shadow: 2px 2px 3px 1px rgba(208, 209, 213, 0.2), 0 2px 2px 1px rgba(220, 221, 224, 0.2);
}
#bidsBonusSection #section3 .summaryTitle{
font-size: 20px;
font-weight: bold;
margin-top: 40px;
}
#bidsBonusSection #section3 .summaryList img{
width: 18px;
}
#bidsBonusSection #section3 .summaryList ul{
text-align: left;
width: 300px;
margin: 5px auto 20px;
line-height: 30px;
}
.bottom-area{
font-size: 16px;
}
.bottom-area.highlight{
color: #FF0658;
font-weight: bold;
margin-top: 15px;
margin-bottom: -10px;
}
#auctionBidsModal #bidsBonusSection #bonusSection img{
width: 20px;
margin-top: -2px;
}
#auctionBidsModal #bidsBonusSection #bonusSection .bottomSection img{
width: 16px;
margin-right: 4px;
}
#auctionBidsModal #bidsBonusSection #bonusSection .bottomSection{
font-size: 16px;
margin-bottom: 15px;
color: #5F5F5F;
}
#bonusSection .btnConfirm{
font-size: 18px;
display: inline-block;
color: #333;
background-color: #fcc62d;
padding: 5px;
line-height: 25px;
border-radius: 5px;
font-weight: bold;
margin-bottom: 10px;
margin-top: 10px;
width: 95%;
text-decoration: none;
}
@media (max-width: 576px) {
#auctionBidsModal #bidsBonusSection #bonusSection .bottomSection {
font-size: 15px;
}
#bonusSection .btnConfirm{
font-size: 16px;
}
}
#rankingBonusSection .title{
font-size: 20px;
font-weight: bold;
margin-bottom: 5px;
}
#rankingBonusSection .subtitle{
font-size: 14px;
}
#rankingBonusSection #ranking{
padding: 0 10px;
}
#rankingBonusSection #ranking table{
margin-top:30px;
width: 100%;
}
#rankingBonusSection #ranking table td{
text-align: left;
}
#rankingBonusSection #ranking table .td1{
text-align: center;
font-weight: bold;
font-size: 14px;
}
#rankingBonusSection #ranking table .td1 img{
width: 38px;
}
#rankingBonusSection #ranking table td.td2{
font-size: 16px;
width: 70%;
padding: 8px 10px;
text-transform: capitalize;
}
#rankingBonusSection #ranking table td.td3{
width: 25%;
font-size: 14px;
font-weight: bold;
text-align: right;
}
#rankingBonusSection #ranking table td.td3 img{
width: 17px;
margin-left: 4px;
}
#auctionBidsModal #section1, #auctionBidsModal #section4{
display: none;
}
#auctionBidsModal #section1{
padding: 0px 20px;
}
#auctionBidsModal #section4 .sad{
width: 25px;
margin-bottom: 10px;
}
#BonusSection .img-lock, #BonusSection .img-lock-open{
display: none;
}
#BonusSection .img-lock img, #BonusSection .img-lock-open img{
width: 12px;
margin-left: 5px;
margin-top: -1px;
}
#BonusSection .pay-bids-counter{
margin-left: 5px;
color: #fff;
background-color: #FF0658;
border-radius: 40px;
width: 19px;
height: 19px;
text-align: center;
font-weight: bold;
font-size: 11px;
padding: 2px;
display: none;
}
#auctionBidsModal .wrap-new-daily-challenge.wrap2{
margin-top: 5px;
}
#auctionBidsModal .wrap-new-daily-challenge{
color: #2F80ED;
font-size: 16px;
font-weight: bold;
margin: 20px 60px 0px;
display: none;
}
@media (max-width: 576px) {
#auctionBidsModal .wrap-new-daily-challenge {
margin: 20px 40px 0;
}
}
#BonusSection .img-plus-not-active, #BonusSection .img-plus-active{
display: none;
}
#auctionBidsModal .extraSlots .slot-title .open-lock{
margin-top: -5px;
width: 15px;
margin-right: 3px;
}
#auctionBidsModal .extraSlots .slot-title span .fa{
font-size: 20px;
position: absolute;
margin-left: 5px;
}
#auctionBidsModal .extraSlots .wrap-content-slot{
padding: 10px 0 15px;
}
#auctionBidsModal .bonus-obtained{
display: none;
}
#auctionBidsModal .extraSlots{
border: none;
margin: -5px auto 0;
padding: 10px 15px;
text-align: center;
background-color: #f3f6f9;
border-radius: 0;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
#auctionBidsModal .extraSlots.avaible{
border-color: #55BC62;
}
#extraSlotTemplate{
display: none;
}
#wrapSlots{
display: flex;
justify-content: space-evenly;
flex-wrap: wrap;
}
#wrapSlots .box-extra-slot{
border: 1px solid #6F6F6F;
background-color: #f3f6f9;
padding: 10px;
border-radius: 5px;
width: 100px;
margin-top: 15px;
display: none;
}
.wrap-num-other-slot{
position: relative;
display: none;
font-weight: bold;
margin-top: 10px;
font-size: 12px;
}
.wrap-num-other-slot .reduce{
display: none;
position: absolute;
top: 0;
right: 20px;
color: #333;
text-decoration: underline;
}
.wrap-num-other-slot .open{
color: #55BC62;
text-decoration: underline;
display: none;
}
#wrapSlots .box-extra-slot .expire{
font-size: 10px;
font-weight: bold;
color: #6A6B6C;
margin-bottom: 5px;
}
#wrapSlots .box-extra-slot .expire img{
margin-left: 2px;
}
#wrapSlots .box-extra-slot .content{
display: flex;
justify-content: center;
}
#wrapSlots .box-extra-slot .content .slot-value{
font-size: 18px;
font-weight: bold;
color: #333;
}
#wrapSlots .box-extra-slot .wrap-cta .cta{
background-color: #B4B4B4;
color: #fff;
padding: 0px 10px;
font-size: 12px;
font-weight: bold;
width: 100%;
max-height: 23px;
}
#wrapSlots .box-extra-slot .wrap-cta .cta img{
margin-top: -2px;
margin-right: 2px;
}
.extraSlots .wrap-content-slot{
display: none;
}
.extraSlots .slot-title a{
width: 100%;
display: block;
color: #333;
text-decoration: none;
}
.extraSlots .slot-title{
color: #000;
font-size: 14px;
font-weight: bold;
}
.extraSlots .slot-content{
font-size: 12px;
}
.extraSlots .slot-content .beforeConfirmed, .extraSlots .slot-content .afterConfirmed{
display: none;
}
.wrap-extra-slots .box-noSlot .titleNoSlot{
color: #FE4E4E;
font-size: 14px;
font-weight: bold;
}
.wrap-extra-slots .box-noSlot .contentNoSlot{
font-size: 12px;
}
.wrap-extra-slots .box-noSlot .contentNoSlot img{
width: 17px;
margin-top: -3px;
margin-left: 3px;
}
.wrap-extra-slots .box-noSlot{
margin-top: 10px;
}
.wrap-extra-slots .box-noSlot{
display: none;
}
.wrap-extra-slots .box-noSlot .box-noextra-slot .no-extra-slot-content .slot-img img{
width: 20px;
opacity: 0.6;
margin-bottom: 5px;
}
.wrap-extra-slots .box-noSlot .box-noextra-slot .no-extra-slot-content{
font-size: 10px;
color: #333;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
}
.wrap-extra-slots .box-noSlot .box-noextra-slot{
width: 92px;
margin: 20px auto;
height: 81px;
border: 1px solid #55BC62;
border-radius: 5px;
}
#wrapSlots.avaible .box-extra-slot{
border-color: #55BC62;
background-color: #EDF8EF;
}
#wrapSlots.avaible .box-extra-slot .wrap-cta .cta{
background-color: #55BC62;
}
.wrap-extra-slots{
display: none;
}
.wrap-extra-slots .title-extraSlot-blocked{
font-size: 18px;
font-weight: bold;
width: 100%;
margin: 0 0 10px;
display: none;
text-align: center;
}
.wrap-extra-slots .title-extraSlot-blocked img{
width: 18px;
margin-top: -5px;
}
#auctionBidsModal #bidsBonusSection .img-lock, #auctionBidsModal #bidsBonusSection .img-lock-open{
display: none;
}
#auctionBidsModal #bidsBonusSection .img-lock img, #auctionBidsModal #bidsBonusSection .img-lock-open img{
margin-left: 5px;
width: 14px;
margin-top: -5px;
}
#auctionBidsModal #differenzaAsteDaConfermare{
color: #fff;
background-color: #FF0658;
border-radius: 40px;
width: 23px;
height: 23px;
text-align: center;
font-weight: bold;
padding: 1px 2px;
display: inline-block;
font-size: 15px;
}
#auctionBidsModal #bonusEarned img{
width: 15px;
margin-left: 5px;
}
#auctionBidsModal .wrap-already-taken, #auctionBidsModal .bonus-yet-to-be-obtained{
display: none;
}
#auctionBidsModal .wrap-already-taken .txt-already-taken{
color: #797979;
}
#auctionBidsModal .bonus-yet-to-be-obtained{
color: #FF0658;
}
#auctionBidsModal #bonusEarned .wrap-details-bonus{
text-align: center;
margin: 7px 0;
}
#auctionBidsModal #modalConfirmSlotStopGame{
z-index: 11;
position: absolute;
top: 0;
bottom: 0;
height: 130px;
background-color: #fff;
width: 270px;
margin: auto;
left: 0;
right: 0;
padding: 15px;
border-radius: 5px;
text-align: center;
display: none;
}
#auctionBidsModal #modalConfirmSlotStopGame .contentButton .btn{
padding: 2px 13px;
font-size: 12px;
color: #fff;
font-weight: bold;
margin: 3px;
}
#auctionBidsModal #modalConfirmSlotStopGame .contentButton .btn-confirm{
background-color: #55BC62
}
#auctionBidsModal #modalConfirmSlotStopGame .contentButton .btn-cancel{
background-color: #BFBFBF;
}
#auctionBidsModal #modalConfirmSlotStopGame .contentButton{
display: flex;
justify-content: center;
margin-top: 10px;
}
#auctionBidsModal #modalConfirmSlotStopGame .content{
font-size: 12px;
text-align: center;
}
#auctionBidsModal #modalConfirmSlotStopGame .title{
color: #FF0202;
text-align: center;
font-size: 13px;
font-weight: bold;
margin-bottom: 5px;
}
#auctionBidsModal .overlayModalConfirmSlotStopGame{
background: rgba(0,0,0,0.2);
top: 0;
left: 0;
position: absolute;
width: 100%;
height: 100%;
display: none;
}

View File

@@ -0,0 +1,113 @@
$(document).ready(function () {
window.myAuctionsControlDetail = new Array(); // array di oggetti deputato a contenere l'asta dove si sta autopuntando
window.myAuctionsControlDetail_lock = false; // flag to lock SetInterval execution
/*
*
* @returns {undefined}
* questa funzione si occupa di controllare ogni 2 secondi se l'asta (dettaglio) su cui c'è un'autopuntata sia realmente attive o c'è stato un blocco lato UI
*
*/
setInterval(
function () {
if (window.myAuctionsControlDetail_lock == false) {
window.myAuctionsControlDetail_lock = true; // lock setinterval execution
//console.log("--- Checking autobids..."); // FOR DEBUG
let isAuctionStarted_element = $(".auction-action-timer.auction-header-item-size.closed-timer"); // element not present if auction started
let callingAjax = false;
if (isAuctionStarted_element.length == 0) { // check element not present if auction started
let element_value = $('.auction-autobid-current-value'); // recupero il valore delle puntate rimanenti nell'asta
if (element_value.length > 0) {
let value = $(element_value[0]).text(); // recupero il valore delle puntate rimanenti nell'asta
//console.log("Puntate autobid = "+value); // FOR DEBUG
if (value > 0) {
let idasta = $('input.js-switch.autobid-switch').data("id"); // recupero l'id dell'asta
//console.log("Checking Asta: " + idasta); // FOR DEBUG
let timestamp = Date.now();
let myAuctions = {
idasta: idasta,
value: value,
timestamp: timestamp,
element_value: element_value
}
if (window.myAuctionsControlDetail.length == 0) { // controllo che questa asta non sia già nell'array
//console.log("Adding Asta in array."); // FOR DEBUG
window.myAuctionsControlDetail = myAuctions;
} else {
if (window.myAuctionsControlDetail.value != value) { // controllo che il valore sia cambiato per in modo da aggiornare le informazioni
//console.log("Value changed."); // FOR DEBUG
window.myAuctionsControlDetail = myAuctions;
} else {
//console.log("Checking time..."); // FOR DEBUG
// in questa condizione il valore non è cambiato dunque controllerò da quanto tempo non cambia
var diffMs = (Date.now() - window.myAuctionsControlDetail.timestamp);
//console.log("diffMs = "+diffMs); // FOR DEBUG
//var diffMins = Math.round(((diffMs % 86400000) % 3600000) / 60000); // minutes
var diffSecs = Math.round(((diffMs % 86400000) % 3600000) / 1000); // minutes
//console.log("diffSecs = "+diffSecs); // FOR DEBUG
// nel caso in cui la differenza è maggiore o uguale a 2 minuti invoco la funzione che si occuperà di spedire le informazioni lato backend
if (diffSecs >= 70) { // default 70 secs
callingAjax = true;
sentToVerification(myAuctions);
window.myAuctionsControlDetail = new Array(); // elimino l'asta dall'array
}
}
}
} else {
window.myAuctionsControlDetail = new Array(); // elimino l'asta dall'array
}
}
}
if (callingAjax === false) {
window.myAuctionsControlDetail_lock = false; // unlock setinterval execution
}
}
},
2000);
function sentToVerification(myAuctions) {
// funzione che serve ad inviare al backend l'asta attiva ma con valori di autopuntata fermi da 2 min
//console.log(myAuctions); // FOR DEBUG
$.ajax({
url: "check_autobid.php",
//dataType: json,
method: 'POST',
timeout: 10000, // default 10000
data : {
idasta: myAuctions.idasta,
value: myAuctions.value,
timestamp: myAuctions.timestamp
},
}).done(function (response) {
window.myAuctionsControlDetail_lock = false; // unlock setinterval execution
//console.log("response = " + response); // FOR DEBUG
$(myAuctions.element_value).text(response);
}).fail(function(jqXHR, textStatus){
if(textStatus === 'timeout') {
//console.log("Ajax timeout. Recall ajax."); // FOR DEBUG
sentToVerification(myAuctions);
}
});
}
});

View File

@@ -0,0 +1,322 @@
function getTexts() {
"use strict"
return {
dialog_confirm: "Sei sicuro di voler rimuovere l\'AutoPuntata?",
autobid_active: "Hai attivato la funzione utilizzando le puntate prenotate",
autobid_not_active: "Attiva la funzione utilizzando le puntate prenotate",
autobid_add: "AGGIUNGI",
autobid_insert: "INSERISCI"
};
}
function enableAutobid() {
"use strict";
$(".auction-action-autobid-trigger")
.toggleClass("button-fucsia-flat", true)
.toggleClass("button-gray-flat", false)
.off('click')
.on('click', setAutobid);
$(".auction-action-autobid-input")
.attr('disabled', false)
.off("keyup").keyup(function (e) {
if (13 == e.which)
$(".auction-action-autobid-trigger").click();
$(".auction-action-autobid-mobile .auction-action-autobid-trigger").toggleClass("disable", $(this).val().length == 0);
});
}
function disableAutobid(reason) {
"use strict";
$(".auction-action-autobid-trigger")
.off('click')
.on('click', function () {
if (!reason)
return;
showErrorTooltip('.auction-action-autobid-trigger:eq(' + getAuctionSelector() + ')', {
title: reason,
html: true,
container: "body",
trigger: "manual",
placement: "top",
template: getTemplateTooltip("error")
}, 3000);
});
}
function unsetAutobid(evt) {
"use strict";
if ('undefined' == typeof window['autobid_switchery']) {
return;
}
if (!isSwitchEnabled()) {
if (evt) {
window._autoController.setAutobid('delete', null, cleanUpAutobidSwitch);
}
}
}
function cleanUpAutobidSwitch() {
"use strict"
$(".auction-autobid-button")
.toggleClass("active", false)
.find(".bi-autobid")
.toggleClass("bi-dark", true)
.toggleClass("bi-green", false);
$(".auction-action-bid-mobile .auction-autobid-current-value").empty();
setTimeout(function () {
if (!isSmartphoneDevice())
$('.auction-action-autobid-trigger').text(getTexts().autobid_insert);
}, 400);
updateAutobid(0);
$('.auction-action-autobid:not(.auction-seat-autobid) .autobid-switch-container, .auction-action-autobid-mobile .autobid-switch-container').hide();
}
function isSwitchEnabled() {
return 'undefined' != typeof window['autobid_switchery'] && window.autobid_switchery[isSmartphoneDevice() ? 1 : 0].isChecked();
}
function hideAutobid() {
"use strict";
$(".auction-action-autobid:visible").hide();
}
function showLoginAutobid() {
"use strict";
$(".auction-action-autobid-trigger")
.off('click')
.on('click', window.parent.showLogin);
$(".auction-action-autobid-input").attr('disabled', true);
}
function bindAutobidTrigger() {
"use strict";
var sNickLoggato = $("#NickLoggato").length > 0 ? $("#NickLoggato").val() : "";
if (sNickLoggato.length <= 0) {
return showLoginAutobid();
}
$('.auction-action-autobid-trigger').off('click').on('click', function (evt) {
var triggerElement = $(this);
rippleButton(triggerElement, evt);
var autobidInputElement = $(".auction-action-autobid-input").eq(isSmartphoneDevice() ? 1 : 0);
var inputAmount = parseInt(autobidInputElement.val(), 10);
var dataInputAmount = parseInt(autobidInputElement.data("amount"), 10);
var autobidAmount = !isNaN(dataInputAmount) ? dataInputAmount : inputAmount;
autobidInputElement.removeData("amount");
var autobidLoader = $(".auction-autobid-loader-container");
var switchContainer = $('.autobid-switch-container');
triggerElement.removeAttr("data-autobid-button");
var isNotValidAmount = isNaN(inputAmount) && isNaN(dataInputAmount);
if (isNotValidAmount) {
if (isSmartphoneDevice() && !$("[data-stage='2']").is(":visible"))
return $(".auction-action-autobid-mobile .auction-action-autobid-input").trigger("focus");
} else {
autobidLoader.removeClass("hidden");
switchContainer.hide();
}
cleanAutobidRequest();
window._autoController.setAutobid('create', autobidAmount, function () {
switchContainer.show();
if (true == isSwitchEnabled())
return;
$(".autobid-switch.js-switch:hidden")
.eq(isSmartphoneDevice() ? 1 : 0)
.data("autobid-enabled", "true")
.trigger('click');
$(".auction-autobid-button")
.toggleClass("active", true)
.find(".bi-autobid")
.toggleClass("bi-dark", false)
.toggleClass("bi-green", true);
var id_product = getUrlParam("a").split("_").reverse()[0];
$("#DA"+id_product).find('.favorite').attr('title', "Non puoi rimuoverla dai preferiti se è attiva l\'autopuntata");
$("#DA"+id_product).find('.favorite').attr('data-original-title', "Non puoi rimuoverla dai preferiti se è attiva l\'autopuntata");
$("#DA"+id_product).find('.favorite').attr('disabled', 'disabled');
$("#DA"+id_product).find('.favorite').addClass('active');
if (isDeepModal()) {
window.parent.BidooCnf.instances.auction.features.startAutobidAuctionUpdate();
}
if (isSmartphoneDevice())
return;
setTimeout(function () {
$('.auction-action-autobid-trigger').text(getTexts().autobid_add);
}, 400);
});
});
}
function setAutobid() {
"use strict";
if ('undefined' == typeof window['autobid_switchery']) {
return;
}
bindAutobidTrigger();
$('.auction-action-autobid-trigger').not("[data-autobid-button]").trigger('click');
}
function updateAutobid(value) {
"use strict";
var element = $(".auction-autobid-current-value");
var oldValue = parseInt(element.eq(0).text(), 10);
if (value != oldValue) {
element.toggle(value > 0);
element.text(value);
return true;
}
return false;
}
function cleanAutobidRequest() {
"use strict";
$(".auction-action-autobid-input").val('');
window._autoController.stopTicker();
}
function updateAutobidStatus(status, value) {
"use strict";
switch (status) {
case 'set':
case 'create':
{
if (0 == value) {
closeSwitch();
} else {
updateAutobid(value);
}
break;
}
case 'unset':
{
closeSwitch();
unsetAutobid(0);
break;
}
}
}
function closeSwitch() {
$('.js-switch.autobid-switch')
.eq(isSmartphoneDevice() ? 1 : 0)
.data("autobid-enabled", "false")
.trigger("click");
}
function setAutobidUI(isAutobid) {
"use strict"
$(".auction-action-autobid-mobile .autobid-switch-container").toggle(isAutobid);
$(".auction-action-bid-mobile .auction-autobid-button")
.toggleClass("active", isAutobid)
.find(".bi-autobid")
.toggleClass("bi-dark", !isAutobid)
.toggleClass("bi-green", isAutobid);
$(".js-switch.autobid-switch")
.data("autobid-enabled", "false")
.trigger('click');
}
function setCorrectPlaceholder(isFocused) {
"use strict"
this.attr("placeholder", isFocused ? "" : $(this).data("placeholder"));
$(".auction-action-autobid-mobile .auction-action-autobid-trigger").toggleClass("disable", this.val().length == 0);
}
$(document).ready(function () {
"use strict";
window.autobid_switchery = [];
window.autobid_seat_switchery = [];
$(".js-switch.autobid-switch").each(function (k, item) {
window.autobid_switchery.push(new Switchery(item, {size: 'small'}));
});
$(".js-switch.autobid-seat-switch").each(function (k, item) {
window.autobid_seat_switchery.push(new Switchery(item, {size: 'small'}));
});
$('.js-switch.autobid-seat-switch').off('change').on('change', function () {
var self = this;
var isEnabled = $(this).is(':checked');
if (isEnabled) {
window.stage.getUpdate(function (update) {
window._autoController.setAutobid('create', update.me.budget.total, function () {
$(".autobid-seat-status").text(getTexts().autobid_active);
});
});
} else {
window._autoController.setAutobid('delete', null, function () {
updateAutobid(0);
$(".autobid-seat-status").text(getTexts().autobid_not_active);
});
}
if (isSmartphoneDevice())
setAutobidUI(isEnabled);
return true;
});
function confirmAutobidUnset() {
if(confirm(getTexts().dialog_confirm)){
return true;
}else{
if (isSmartphoneDevice()){
$('.switchery-small small').css('left', '30px');
}else{
$('#boxcontent .autobid-switch').click();
}
}
}
$('.js-switch.autobid-switch').off('change').on('change', function () {
var switchAutobid = $(this);
if (isSmartphoneDevice() && $("[data-stage='2']").is(":visible"))
return true;
var id_product = getUrlParam("a").split("_").reverse()[0];
if (!switchAutobid.is(':checked') && ("false" == switchAutobid.data("autobid-enabled") || confirmAutobidUnset())) {
unsetAutobid({});
$("#DA"+id_product).find('.favorite').removeAttr('disabled');
$("#DA"+id_product).find('.favorite').attr('title', "Rimuovi quest\'asta dalle tue preferite");
if (isDeepModal()) {
$("#DA"+id_product).find('.favorite').removeAttr('data-original-title');
window.parent.BidooCnf.instances.auction.features.stopAutobidAuctionUpdate();
setTimeout(function () {
$("#divAsta"+id_product, parent.document).find('.favorite').removeAttr('data-original-title');
$("#divAsta"+id_product, parent.document).find('.favorite').removeAttr('disabled');
$("#divAsta"+id_product, parent.document).find('.favorite').attr('title', "Rimuovi quest\'asta dalle tue preferite");
}, 500);
} else {
$("#DA"+id_product).find('.favorite').attr("data-original-title", "Rimuovi quest\'asta dalle tue preferite");
}
}
return true;
});
$(".autobid-speed-dial > div > a").on('click', function (e) {
e.preventDefault();
var self = $(this);
var amount = parseInt(self.attr("data-amount"));
$(".auction-action-autobid-input").data("amount", amount);
$('.auction-action-autobid-trigger').attr("data-autobid-button", true).trigger('click');
});
var scopeElement = $(".auction-action-autobid-input[data-placeholder]");
scopeElement
.focus(setCorrectPlaceholder.bind(scopeElement, true))
.blur(setCorrectPlaceholder.bind(scopeElement, false));
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,255 @@
.btn-promo, .btn-promo:hover {
background: #2196f3 !important;
}
.mCSB_inside > .mCSB_container {
margin-right: 0px;
}
.mCSB_scrollTools .mCSB_draggerRail {
width: 6px;
background-color: #e2e2e2;
}
.mCSB_scrollTools .mCSB_draggerContainer {
left: 10px;
}
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {
background-color: #20cb9a !important;
width: 100%;
}
#toggleBar {
margin-left: 0 !important;
left: 20px;
display: none;
}
.barra {
-webkit-font-smoothing: antialiased;
}
.btn-promo {
margin-top: -2px;
line-height: 17.5px;
}
.view_gray_link {
text-decoration: none;
cursor: pointer;
}
.leader-btn {
margin: 0;
padding: 0;
border: 0;
text-transform: uppercase;
font-size: 10px;
margin-top: 2px;
}
.bid_chal img.img-lock{
display: none;
}
.bid_chal img{
margin-top: -3px;
}
.wrap-limit-unlock{
color: #fff;
background-color: #55bc62;
border-radius: 5px;
font-weight: bold;
padding: 0;
text-transform: initial;
width: 120px;
margin: -4px auto 0;
}
.wrap-button-get-bonus{
color: #000;
background-color: #FFC642;
border-radius: 5px;
font-weight: bold;
padding: 0;
display: none;
text-transform: initial;
margin-top: -4px;
}
.wrap-button-get-bonus img{
width: 14px;
}
.bid_chal {
font-weight: bold;
font-size: 13px;
text-transform: none;
margin-bottom: 3px;
}
.next-level {
background-color: #eaeaea;
margin: 0;
width: 124px;
height: 8px;
box-shadow: none;
margin: 0 auto;
}
#tickNotif {
background: white;
width: 15px;
height: 15px;
transform: rotate(-45deg);
border: 1px solid #e2e2e2;
position: fixed;
margin-top: -15px;
display: none;
}
.notifIcon {
margin-left: 0px;
}
#boxarea.dodici {
width: 920px;
}
#tickNotif {
margin-left: 17px;
}
.small_notif {
margin-left: 119px !important;
}
.bonus_dialog {
left: 48.5%;
}
.leader_btn {
margin-right: 4px;
}
.tooltip.reach > .tooltip-inner .wrap{
display: flex;
}
.tooltip.reach > .tooltip-inner .wrap img{
width: 16px;
margin-right: 10px;
}
.tooltip.reach > .tooltip-inner {
background-color: #fff;
border: 1px solid #333;
color: #232323;
padding: 10px;
}
.tooltip.reach > .tooltip-inner > span {
text-align: center;
}
.tooltip.reach > .tooltip-inner > span:last-child {
padding: 10px 0;
}
.tooltip.reach > .tooltip-inner strong {
display: block;
}
.bid-challenge > strong {
color: darkorange;
display: block;
}
.tooltip.reach > .tooltip-inner {
max-width: 300px;
}
.leader-btn:hover, .leader-btn {
background-color: transparent !important;
}
.paid-all {
color: #565454;
margin-top: -5px;
text-transform: initial;
}
.active-all {
color: #55bc62;
margin-top: -5px;
text-transform: initial;
}
.paid-all img, .active-all img{
width: 16px;
}
.bar-right-side .pull-right{
margin-right: -30px;
}
.bar-right-side .pull-right > *,
.bar-left-side > *{
display: inline-block;
}
.bar-left-side{
margin-top: 5px;
}
.auctions_won_bottom_bar { /*[GR]*/
border: 2px solid #ffc518 !important;
background-color:#fff;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
border-radius: 5px;
padding: 5px 10px;
color:#3d3a3a;
outline: 0;
font-weight:bold;
height:29px;
vertical-align: top;
}
.auctions_won_bottom_bar:hover{ /*[GR]*/
background-color: #ffc518 !important;
color: #fff;
}
.auctions_won_bottom_bar .badge { /*[GR]*/
background-color: #ff2f4e;
left: 20px;
top: -12px;
margin-left: -20px;
}
.barra[data-lang="es"] #ba #boxarea .notifIcon{
margin-left: 10px;
}
.barra[data-lang="es"] #ba #boxarea #lim{
margin-left: 5px;
}
.barra[data-lang="es"] #ba #boxarea .auctions_won_bottom_bar{
margin-left: 5px;
margin-top: 1px;
}
@media(max-width: 1200px){
.barra[data-lang="es"] #ba #boxarea .auctions_won_bottom_bar, .barra[data-lang="es"] #ba #boxarea #lim{
width: 110px;
font-size: 11px;
padding: 5px;
}
.barra[data-lang="es"] .notif{
margin: -5px 6px !important;
}
}
.bidooBell{
color: #c3c0c1;
font-size: 21px;
margin-top: 4px;
}
.bidooBell:hover, .bidooBell:active, .bidooBell:focus, .bidooBell.active{
color: #666666;
transition: color 0.4s;
}
#auctionBidBottomBar{
outline: none !important;
}

View File

@@ -0,0 +1,21 @@
function BottomBar(){
"use strict"
var self = this;
self.footer = $(".footer");
self.checkFooter();
}
BottomBar.prototype.checkFooter = function() {
"use strict"
var self = this;
if (!self.footer.length) return;
$(window).scroll(function() {
$(".goTop").find("i")
.toggleClass("white_top_arrow", isElementInView(self.footer, false));
});
}
$(document).ready(function() {
"use strict"
new BottomBar();
});

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,140 @@
var BUYNOW_COUNTDOWN = null;
var BUYNOW_ERRORS = {
already_used: 'Hai usato l&rsquo;opzione Compralo in quest&rsquo;asta',
already_won: 'Hai vinto questa Asta.<br>Non puoi usare l&rsquo;opzione Compralo'
};
window.serverTime = () => {
//vado a prendere il valore dalla pagina, precedentemente messo in php
if($('.buynow-countdown-container .product-buynow-countdown').hasClass('time-server')){
return parseInt($('.time-server').attr('data-time-server')) != "NaN" ? parseInt($('.time-server').attr('data-time-server')) : null ;
}else{
return null;
}
}
function startBuynowCountdown(time) {
"use strict";
var element = $(".product-buynow-countdown[data-countdown]");
if('active' == element.attr("data-countdown-status")) {
return false;
}
if('undefined' != typeof time) {
element.attr('data-countdown', time);
}
var countdown = element.attr('data-countdown');
if(countdown && countdown.length > 0) {
BUYNOW_COUNTDOWN = setInterval(function() {
var countdown_value = SimpleCountdown(countdown);
element.text(countdown_value);
/*
Destroy interval
Hide countdown
*/
var timeServer = typeof window.serverTime() != null ? window.serverTime() : (new Date()).getTime() / 1000;
var isExpired = countdown <= parseInt(timeServer);
$(".buyitnow-status p > span.product-value").toggle(isExpired);
$("span.product-buynow-countdown").toggle(!isExpired);
if(isExpired) clearInterval(BUYNOW_COUNTDOWN);
}, 1000);
element.attr("data-countdown-status", "active");
}
}
function setStatusBuynowButton(status, error_type) {
"use strict";
var selector = ".buyitnow-button";
var element = $(selector);
var defaults = "button-default button-full buyitnow-button ripple-button";
var base = "buyitnow-button";
var specific = 'button-blue-gradient';
switch(status) {
default:
case 'enabled': {
bindBuynowTrigger(error_type);
break;
}
case 'engaged': {
$('body').find("[data-buynow-state='engaged']").fadeIn();
bindBuynowTrigger(error_type);
break;
}
case 'disabled': {
specific = "button-gray-flat";
element.off('click');
element.find("[data-buynow-state='engaged']").fadeOut('fast');
break;
}
case 'login': {
element.off('click').on('click', window.parent.showLogin);
break;
}
}
if("undefined"===typeof element[0]) return element;
var oldClass = element[0].className;
var newClass = [defaults, specific, [base, status].join('-')].join(' ');
if(oldClass != newClass) {
$("main.buyitnow").find(selector).each(function(k, item) {
$(item).removeClass();
$(item).addClass(newClass);
});
$(".auction-action-bid-mobile .buyitnow-button")
.toggleClass(specific,true);
}
return element;
}
function bindBuynowTrigger(error_type) {
"use strict";
var selector = ".buyitnow-button";
var element = $('body').find(selector);
element.each(function(k, elem) {
$(elem).off('click').on('click', function(e) {
e.preventDefault();
rippleButton($(elem), e);
if(!error_type) {
var url = "buy_your_product.php"+parseURL(window.location.href).search;
navigateDeepModalURL(url);
return false;
}
$(elem).popover({
html: true,
content: BUYNOW_ERRORS[error_type],
placement: isSmartphoneDevice() ? "top" : "bottom",
selector: selector,
container: "body"
}).on('shown.bs.popover', function() {
setTimeout(function() {
$(selector).popover('destroy');
}, 3000);
}).popover('show');
});
});
}
$(document).ready(function() {
"use strict";
$("body").find(".expenditure-value").each(function(k, item) {
var expenditure = $(item).text();
if(expenditure.length && parseInt(expenditure, 10) > 0) {
updateUserExpenditure(expenditure);
$('[data-buynow-state="engaged"]').fadeIn();
return false;
}
});
});

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,99 @@
(function(){'use strict';var f,aa=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}},g=typeof Object.defineProperties=="function"?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a},ba=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");
},ca=ba(this),da=function(a,b){if(b)a:{var c=ca;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&b!=null&&g(c,a,{configurable:!0,writable:!0,value:b})}};
da("Symbol",function(a){if(a)return a;var b=function(h,k){this.g=h;g(this,"description",{configurable:!0,writable:!0,value:k})};b.prototype.toString=function(){return this.g};var c="jscomp_symbol_"+(Math.random()*1E9>>>0)+"_",d=0,e=function(h){if(this instanceof e)throw new TypeError("Symbol is not a constructor");return new b(c+(h||"")+"_"+d++,h)};return e});
da("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");g(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return ea(aa(this))}});return a});var ea=function(a){a={next:a};a[Symbol.iterator]=function(){return this};return a},fa=typeof Object.create=="function"?Object.create:function(a){var b=function(){};b.prototype=a;return new b},l;
if(typeof Object.setPrototypeOf=="function")l=Object.setPrototypeOf;else{var n;a:{var ha={a:!0},ia={};try{ia.__proto__=ha;n=ia.a;break a}catch(a){}n=!1}l=n?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null}
var ja=l,q=function(a,b){a.prototype=fa(b.prototype);a.prototype.constructor=a;if(ja)ja(a,b);else for(var c in b)if(c!="prototype")if(Object.defineProperties){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.sc=b.prototype},ka=function(a){var b=typeof Symbol!="undefined"&&Symbol.iterator&&a[Symbol.iterator];if(b)return b.call(a);if(typeof a.length=="number")return{next:aa(a)};throw Error(String(a)+" is not an iterable or ArrayLike");};/*
Copyright The Closure Library Authors.
SPDX-License-Identifier: Apache-2.0
*/
var r=this||self,u=function(a){var b=typeof a;b=b!="object"?b:a?Array.isArray(a)?"array":b:"null";return b=="array"||b=="object"&&typeof a.length=="number"},v="closure_uid_"+(Math.random()*1E9>>>0),la=0,ma=function(a,b,c){return a.call.apply(a.bind,arguments)},na=function(a,b,c){if(!a)throw Error();if(arguments.length>2){var d=Array.prototype.slice.call(arguments,2);return function(){var e=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(e,d);return a.apply(b,e)}}return function(){return a.apply(b,
arguments)}},w=function(a,b,c){w=Function.prototype.bind&&Function.prototype.bind.toString().indexOf("native code")!=-1?ma:na;return w.apply(null,arguments)},x=function(a,b){a=a.split(".");for(var c=r,d;a.length&&(d=a.shift());)a.length||b===void 0?c[d]&&c[d]!==Object.prototype[d]?c=c[d]:c=c[d]={}:c[d]=b};var chrome=chrome||window.chrome||{};chrome.cast=chrome.cast||{};chrome.cast.media=chrome.cast.media||{};chrome.cast.ReceiverActionListener={};chrome.cast.VERSION=[1,2];x("chrome.cast.VERSION",chrome.cast.VERSION);chrome.cast.rc=!0;x("chrome.cast.usingPresentationApi",chrome.cast.rc);chrome.cast.Na=function(a,b){this.credentials=a;this.credentialsType=b===void 0?"web":b};x("chrome.cast.CredentialsData",chrome.cast.Na);chrome.cast.Error=function(a,b,c){this.code=a;this.description=b||null;this.details=c||null};x("chrome.cast.Error",chrome.cast.Error);
chrome.cast.nb=function(a){this.platform=a;this.packageId=this.url=null};x("chrome.cast.SenderApplication",chrome.cast.nb);chrome.cast.Image=function(a){this.url=a;this.width=this.height=null};x("chrome.cast.Image",chrome.cast.Image);chrome.cast.Volume=function(a,b){this.level=a===void 0?null:a;this.muted=b===void 0?null:b};x("chrome.cast.Volume",chrome.cast.Volume);chrome.cast.ha={CUSTOM_CONTROLLER_SCOPED:"custom_controller_scoped",TAB_AND_ORIGIN_SCOPED:"tab_and_origin_scoped",ORIGIN_SCOPED:"origin_scoped",PAGE_SCOPED:"page_scoped"};x("chrome.cast.AutoJoinPolicy",chrome.cast.ha);chrome.cast.ja={CREATE_SESSION:"create_session",CAST_THIS_TAB:"cast_this_tab"};x("chrome.cast.DefaultActionPolicy",chrome.cast.ja);chrome.cast.Ma={VIDEO_OUT:"video_out",AUDIO_OUT:"audio_out",VIDEO_IN:"video_in",AUDIO_IN:"audio_in",MULTIZONE_GROUP:"multizone_group"};
x("chrome.cast.Capability",chrome.cast.Ma);chrome.cast.A={CANCEL:"cancel",TIMEOUT:"timeout",API_NOT_INITIALIZED:"api_not_initialized",INVALID_PARAMETER:"invalid_parameter",EXTENSION_NOT_COMPATIBLE:"extension_not_compatible",EXTENSION_MISSING:"extension_missing",RECEIVER_UNAVAILABLE:"receiver_unavailable",SESSION_ERROR:"session_error",CHANNEL_ERROR:"channel_error",LOAD_MEDIA_FAILED:"load_media_failed"};x("chrome.cast.ErrorCode",chrome.cast.A);chrome.cast.N={AVAILABLE:"available",UNAVAILABLE:"unavailable"};
x("chrome.cast.ReceiverAvailability",chrome.cast.N);chrome.cast.ob={CHROME:"chrome",IOS:"ios",ANDROID:"android"};x("chrome.cast.SenderPlatform",chrome.cast.ob);chrome.cast.xa={CAST:"cast",DIAL:"dial",HANGOUT:"hangout",CUSTOM:"custom"};x("chrome.cast.ReceiverType",chrome.cast.xa);chrome.cast.Qa={RUNNING:"running",STOPPED:"stopped",ERROR:"error"};x("chrome.cast.DialAppState",chrome.cast.Qa);chrome.cast.jb={CAST:"cast",STOP:"stop"};x("chrome.cast.ReceiverAction",chrome.cast.jb);
chrome.cast.K={CONNECTED:"connected",DISCONNECTED:"disconnected",STOPPED:"stopped"};x("chrome.cast.SessionStatus",chrome.cast.K);chrome.cast.Db={ATTENUATION:"attenuation",FIXED:"fixed",MASTER:"master"};x("chrome.cast.VolumeControlType",chrome.cast.Db);var oa=/&/g,pa=/</g,qa=/>/g,ra=/"/g,sa=/'/g,ta=/\x00/g,ua=/[\x00&<>"']/;/*
Copyright Google LLC
SPDX-License-Identifier: Apache-2.0
*/
var va={};function wa(){if(va!==va)throw Error("Bad secret");};var xa=globalThis.trustedTypes,y;function ya(){var a=null;if(!xa)return a;try{var b=function(c){return c};a=xa.createPolicy("goog#html",{createHTML:b,createScript:b,createScriptURL:b})}catch(c){throw c;}return a};var z=function(a){wa();this.g=a};z.prototype.toString=function(){return this.g};new z("about:blank");new z("about:invalid#zClosurez");var za=[],Aa=function(a){console.warn("A URL with content '"+a+"' was sanitized away.")};za.indexOf(Aa)===-1&&za.push(Aa);var A=function(a){wa();this.g=a};A.prototype.toString=function(){return this.g+""};var Ba=Array.prototype.forEach?function(a,b){Array.prototype.forEach.call(a,b,void 0)}:function(a,b){for(var c=a.length,d=typeof a==="string"?a.split(""):a,e=0;e<c;e++)e in d&&b.call(void 0,d[e],e,a)};function Ca(a,b){for(var c=a.length,d=typeof a==="string"?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a))return e;return-1};var Da=Object.freeze||function(a){return a};var Fa=function(a){var b={"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"'};var c=r.document.createElement("div");return a.replace(Ea,function(d,e){var h=b[d];if(h)return h;e.charAt(0)=="#"&&(e=Number("0"+e.slice(1)),isNaN(e)||(h=String.fromCharCode(e)));if(!h){h=d+" ";y===void 0&&(y=ya());h=(e=y)?e.createHTML(h):h;h=new A(h);if(c.nodeType===1&&(e=c.tagName,/^(script|style)$/i.test(e)))throw d=e.toLowerCase()==="script"?"Use setScriptTextContent with a SafeScript.":"Use setStyleTextContent with a SafeStyleSheet.",
Error(d);if(h instanceof A)h=h.g;else throw Error("Unexpected type when unwrapping SafeHtml");c.innerHTML=h;h=c.firstChild.nodeValue.slice(0,-1)}return b[d]=h})},Ga=function(a){return a.replace(/&([^;]+);/g,function(b,c){switch(c){case "amp":return"&";case "lt":return"<";case "gt":return">";case "quot":return'"';default:return c.charAt(0)!="#"||(c=Number("0"+c.slice(1)),isNaN(c))?b:String.fromCharCode(c)}})},Ea=/&([^;\s<&]+);?/g;chrome.cast.Ia=function(a,b,c,d,e){this.sessionRequest=a;this.sessionListener=b;this.receiverListener=c;this.autoJoinPolicy=d||chrome.cast.ha.TAB_AND_ORIGIN_SCOPED;this.defaultActionPolicy=e||chrome.cast.ja.CREATE_SESSION;this.customDialLaunchCallback=null;this.invisibleSender=!1;this.additionalSessionRequests=[]};x("chrome.cast.ApiConfig",chrome.cast.Ia);chrome.cast.Ta=function(a,b){this.appName=a;this.launchParameter=b||null};x("chrome.cast.DialRequest",chrome.cast.Ta);
chrome.cast.Ra=function(a,b,c){this.receiver=a;this.appState=b;this.extraData=c||null};x("chrome.cast.DialLaunchData",chrome.cast.Ra);chrome.cast.Sa=function(a,b){this.doLaunch=a;this.launchParameter=b||null};x("chrome.cast.DialLaunchResponse",chrome.cast.Sa);
chrome.cast.pb=function(a,b,c,d,e){c=c===void 0?chrome.cast.timeout.requestSession:c;this.appId=a;this.capabilities=Array.isArray(b)?b:[];this.requestSessionTimeout=c;this.dialRequest=this.language=null;this.androidReceiverCompatible=d===void 0?!1:d;this.credentialsData=e===void 0?null:e};x("chrome.cast.SessionRequest",chrome.cast.pb);
chrome.cast.ib=function(a,b,c,d){this.label=a;a=b;ua.test(a)&&(a.indexOf("&")!=-1&&(a=a.replace(oa,"&amp;")),a.indexOf("<")!=-1&&(a=a.replace(pa,"&lt;")),a.indexOf(">")!=-1&&(a=a.replace(qa,"&gt;")),a.indexOf('"')!=-1&&(a=a.replace(ra,"&quot;")),a.indexOf("'")!=-1&&(a=a.replace(sa,"&#39;")),a.indexOf("\x00")!=-1&&(a=a.replace(ta,"&#0;")));this.friendlyName=a;this.capabilities=c||[];this.volume=d||null;this.receiverType=chrome.cast.xa.CAST;this.displayStatus=this.isActiveInput=null};
x("chrome.cast.Receiver",chrome.cast.ib);chrome.cast.kb=function(a,b){this.statusText=a;this.appImages=b;this.showStop=null};x("chrome.cast.ReceiverDisplayStatus",chrome.cast.kb);chrome.cast.Aa=function(){this.requestSession=6E4;this.getDialAppInfo=this.sendCustomMessage=this.setReceiverVolume=this.stopSession=this.leaveSession=3E3};x("chrome.cast.Timeout",chrome.cast.Aa);chrome.cast.timeout=new chrome.cast.Aa;x("chrome.cast.timeout",chrome.cast.timeout);chrome.cast.Ha="auto-join";
chrome.cast.cb="cast-session_";chrome.cast.media.Va={SDR:"sdr",HDR:"hdr",DV:"dv"};x("chrome.cast.media.HdrType",chrome.cast.media.Va);chrome.cast.media.Wa={AAC:"aac",AC3:"ac3",MP3:"mp3",TS:"ts",TS_AAC:"ts_aac",E_AC3:"e_ac3",FMP4:"fmp4"};x("chrome.cast.media.HlsSegmentFormat",chrome.cast.media.Wa);chrome.cast.media.Xa={MPEG2_TS:"mpeg2_ts",FMP4:"fmp4"};x("chrome.cast.media.HlsVideoSegmentFormat",chrome.cast.media.Xa);chrome.cast.media.ab={PAUSE:"pause",SEEK:"seek",STREAM_VOLUME:"stream_volume",STREAM_MUTE:"stream_mute"};
x("chrome.cast.media.MediaCommand",chrome.cast.media.ab);chrome.cast.media.gb={ALBUM:"ALBUM",PLAYLIST:"PLAYLIST",AUDIOBOOK:"AUDIOBOOK",RADIO_STATION:"RADIO_STATION",PODCAST_SERIES:"PODCAST_SERIES",TV_SERIES:"TV_SERIES",VIDEO_PLAYLIST:"VIDEO_PLAYLIST",LIVE_TV:"LIVE_TV",MOVIE:"MOVIE"};x("chrome.cast.media.QueueType",chrome.cast.media.gb);chrome.cast.media.U={GENERIC_CONTAINER:0,AUDIOBOOK_CONTAINER:1};x("chrome.cast.media.ContainerType",chrome.cast.media.U);
chrome.cast.media.F={GENERIC:0,MOVIE:1,TV_SHOW:2,MUSIC_TRACK:3,PHOTO:4,AUDIOBOOK_CHAPTER:5};x("chrome.cast.media.MetadataType",chrome.cast.media.F);chrome.cast.media.B={IDLE:"IDLE",PLAYING:"PLAYING",PAUSED:"PAUSED",BUFFERING:"BUFFERING"};x("chrome.cast.media.PlayerState",chrome.cast.media.B);chrome.cast.media.V={OFF:"REPEAT_OFF",ALL:"REPEAT_ALL",SINGLE:"REPEAT_SINGLE",ALL_AND_SHUFFLE:"REPEAT_ALL_AND_SHUFFLE"};x("chrome.cast.media.RepeatMode",chrome.cast.media.V);
chrome.cast.media.lb={PLAYBACK_START:"PLAYBACK_START",PLAYBACK_PAUSE:"PLAYBACK_PAUSE"};x("chrome.cast.media.ResumeState",chrome.cast.media.lb);chrome.cast.media.za={BUFFERED:"BUFFERED",LIVE:"LIVE",OTHER:"OTHER"};x("chrome.cast.media.StreamType",chrome.cast.media.za);chrome.cast.media.Ya={CANCELLED:"CANCELLED",INTERRUPTED:"INTERRUPTED",FINISHED:"FINISHED",ERROR:"ERROR"};x("chrome.cast.media.IdleReason",chrome.cast.media.Ya);chrome.cast.media.yb={TEXT:"TEXT",AUDIO:"AUDIO",VIDEO:"VIDEO"};
x("chrome.cast.media.TrackType",chrome.cast.media.yb);chrome.cast.media.ub={SUBTITLES:"SUBTITLES",CAPTIONS:"CAPTIONS",DESCRIPTIONS:"DESCRIPTIONS",CHAPTERS:"CHAPTERS",METADATA:"METADATA"};x("chrome.cast.media.TextTrackType",chrome.cast.media.ub);chrome.cast.media.qb={NONE:"NONE",OUTLINE:"OUTLINE",DROP_SHADOW:"DROP_SHADOW",RAISED:"RAISED",DEPRESSED:"DEPRESSED"};x("chrome.cast.media.TextTrackEdgeType",chrome.cast.media.qb);chrome.cast.media.wb={NONE:"NONE",NORMAL:"NORMAL",ROUNDED_CORNERS:"ROUNDED_CORNERS"};
x("chrome.cast.media.TextTrackWindowType",chrome.cast.media.wb);chrome.cast.media.rb={SANS_SERIF:"SANS_SERIF",MONOSPACED_SANS_SERIF:"MONOSPACED_SANS_SERIF",SERIF:"SERIF",MONOSPACED_SERIF:"MONOSPACED_SERIF",CASUAL:"CASUAL",CURSIVE:"CURSIVE",SMALL_CAPITALS:"SMALL_CAPITALS"};x("chrome.cast.media.TextTrackFontGenericFamily",chrome.cast.media.rb);chrome.cast.media.sb={NORMAL:"NORMAL",BOLD:"BOLD",BOLD_ITALIC:"BOLD_ITALIC",ITALIC:"ITALIC"};x("chrome.cast.media.TextTrackFontStyle",chrome.cast.media.sb);
chrome.cast.media.zb={LIKE:"LIKE",DISLIKE:"DISLIKE",FOLLOW:"FOLLOW",UNFOLLOW:"UNFOLLOW"};x("chrome.cast.media.UserAction",chrome.cast.media.zb);chrome.cast.media.la=function(){this.customData=null};x("chrome.cast.media.GetStatusRequest",chrome.cast.media.la);chrome.cast.media.pa=function(){this.customData=null};x("chrome.cast.media.PauseRequest",chrome.cast.media.pa);chrome.cast.media.ra=function(){this.customData=null};x("chrome.cast.media.PlayRequest",chrome.cast.media.ra);chrome.cast.media.mb=function(){this.customData=this.resumeState=this.currentTime=null};x("chrome.cast.media.SeekRequest",chrome.cast.media.mb);
chrome.cast.media.ya=function(){this.customData=null};x("chrome.cast.media.StopRequest",chrome.cast.media.ya);chrome.cast.media.Eb=function(a){this.volume=a;this.customData=null};x("chrome.cast.media.VolumeRequest",chrome.cast.media.Eb);
chrome.cast.media.Za=function(a){this.type="LOAD";this.requestId=0;this.sessionId=null;this.media=a;this.activeTrackIds=null;this.autoplay=!0;this.atvCredentialsType=this.atvCredentials=this.credentialsType=this.credentials=void 0;this.customData=this.currentTime=null;this.queueData=this.playbackRate=void 0};x("chrome.cast.media.LoadRequest",chrome.cast.media.Za);chrome.cast.media.Ua=function(a,b){this.requestId=0;this.activeTrackIds=a||null;this.textTrackStyle=b||null};
x("chrome.cast.media.EditTracksInfoRequest",chrome.cast.media.Ua);chrome.cast.media.T=function(a){this.containerType=a=a===void 0?chrome.cast.media.U.GENERIC_CONTAINER:a;this.containerDuration=this.containerImages=this.sections=this.title=void 0};x("chrome.cast.media.ContainerMetadata",chrome.cast.media.T);
chrome.cast.media.MediaMetadata=function(a){this.metadataType=this.type=a;this.queueItemId=this.sectionStartTimeInContainer=this.sectionStartAbsoluteTime=this.sectionStartTimeInMedia=this.sectionDuration=void 0};x("chrome.cast.media.MediaMetadata",chrome.cast.media.MediaMetadata);chrome.cast.media.ka=function(){chrome.cast.media.MediaMetadata.call(this,chrome.cast.media.F.GENERIC);this.releaseDate=this.releaseYear=this.images=this.subtitle=this.title=void 0};q(chrome.cast.media.ka,chrome.cast.media.MediaMetadata);
x("chrome.cast.media.GenericMediaMetadata",chrome.cast.media.ka);chrome.cast.media.na=function(){chrome.cast.media.MediaMetadata.call(this,chrome.cast.media.F.MOVIE);this.releaseDate=this.releaseYear=this.images=this.subtitle=this.studio=this.title=void 0};q(chrome.cast.media.na,chrome.cast.media.MediaMetadata);x("chrome.cast.media.MovieMediaMetadata",chrome.cast.media.na);
chrome.cast.media.Ba=function(){chrome.cast.media.MediaMetadata.call(this,chrome.cast.media.F.TV_SHOW);this.originalAirdate=this.releaseYear=this.images=this.episode=this.episodeNumber=this.season=this.seasonNumber=this.episodeTitle=this.title=this.seriesTitle=void 0};q(chrome.cast.media.Ba,chrome.cast.media.MediaMetadata);x("chrome.cast.media.TvShowMediaMetadata",chrome.cast.media.Ba);
chrome.cast.media.oa=function(){chrome.cast.media.MediaMetadata.call(this,chrome.cast.media.F.MUSIC_TRACK);this.releaseDate=this.releaseYear=this.images=this.discNumber=this.trackNumber=this.artistName=this.songName=this.composer=this.artist=this.albumArtist=this.title=this.albumName=void 0};q(chrome.cast.media.oa,chrome.cast.media.MediaMetadata);x("chrome.cast.media.MusicTrackMediaMetadata",chrome.cast.media.oa);
chrome.cast.media.qa=function(){chrome.cast.media.MediaMetadata.call(this,chrome.cast.media.F.PHOTO);this.creationDateTime=this.height=this.width=this.longitude=this.latitude=this.images=this.location=this.artist=this.title=void 0};q(chrome.cast.media.qa,chrome.cast.media.MediaMetadata);x("chrome.cast.media.PhotoMediaMetadata",chrome.cast.media.qa);
chrome.cast.media.ga=function(){chrome.cast.media.T.call(this,chrome.cast.media.U.AUDIOBOOK_CONTAINER);this.releaseDate=this.publisher=this.narrators=this.authors=void 0};q(chrome.cast.media.ga,chrome.cast.media.T);x("chrome.cast.media.AudiobookContainerMetadata",chrome.cast.media.ga);chrome.cast.media.fa=function(){chrome.cast.media.MediaMetadata.call(this,chrome.cast.media.F.AUDIOBOOK_CHAPTER);this.images=this.subtitle=this.bookTitle=this.chapterNumber=this.title=this.chapterTitle=void 0};
q(chrome.cast.media.fa,chrome.cast.media.MediaMetadata);x("chrome.cast.media.AudiobookChapterMediaMetadata",chrome.cast.media.fa);
chrome.cast.media.bb=function(a,b){this.contentId=a;this.contentUrl=void 0;this.streamType=chrome.cast.media.za.BUFFERED;this.contentType=b===void 0?"":b;this.metadata=null;this.atvEntity=this.entity=void 0;this.duration=null;this.startAbsoluteTime=void 0;this.customData=this.textTrackStyle=this.tracks=null;this.userActionStates=this.hlsVideoSegmentFormat=this.hlsSegmentFormat=this.vmapAdsRequest=this.breakClips=this.breaks=void 0};x("chrome.cast.media.MediaInfo",chrome.cast.media.bb);
chrome.cast.media.ta=function(a){this.itemId=null;this.media=a;this.autoplay=!0;this.startTime=0;this.playbackDuration=null;this.preloadTime=0;this.customData=this.activeTrackIds=null};x("chrome.cast.media.QueueItem",chrome.cast.media.ta);chrome.cast.media.Pa="CC1AD845";x("chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID",chrome.cast.media.Pa);chrome.cast.media.timeout={};chrome.cast.media.timeout.load=0;x("chrome.cast.media.timeout.load",chrome.cast.media.timeout.load);
chrome.cast.media.timeout.P=0;x("chrome.cast.media.timeout.getStatus",chrome.cast.media.timeout.P);chrome.cast.media.timeout.play=0;x("chrome.cast.media.timeout.play",chrome.cast.media.timeout.play);chrome.cast.media.timeout.pause=0;x("chrome.cast.media.timeout.pause",chrome.cast.media.timeout.pause);chrome.cast.media.timeout.seek=0;x("chrome.cast.media.timeout.seek",chrome.cast.media.timeout.seek);chrome.cast.media.timeout.stop=0;x("chrome.cast.media.timeout.stop",chrome.cast.media.timeout.stop);
chrome.cast.media.timeout.R=0;x("chrome.cast.media.timeout.setVolume",chrome.cast.media.timeout.R);chrome.cast.media.timeout.O=0;x("chrome.cast.media.timeout.editTracksInfo",chrome.cast.media.timeout.O);chrome.cast.media.timeout.v=0;x("chrome.cast.media.timeout.queue",chrome.cast.media.timeout.v);chrome.cast.media.xb=function(a,b){this.trackId=a;this.trackContentType=this.trackContentId=null;this.type=b;this.customData=this.subtype=this.language=this.name=null};x("chrome.cast.media.Track",chrome.cast.media.xb);
chrome.cast.media.tb=function(){this.customData=this.fontStyle=this.fontGenericFamily=this.fontFamily=this.fontScale=this.windowRoundedCornerRadius=this.windowColor=this.windowType=this.edgeColor=this.edgeType=this.backgroundColor=this.foregroundColor=null};x("chrome.cast.media.TextTrackStyle",chrome.cast.media.tb);chrome.cast.media.fb=function(a){this.type="QUEUE_LOAD";this.sessionId=this.requestId=null;this.items=a;this.startIndex=0;this.repeatMode=chrome.cast.media.V.OFF;this.customData=null};
x("chrome.cast.media.QueueLoadRequest",chrome.cast.media.fb);chrome.cast.media.sa=function(a){this.type="QUEUE_INSERT";this.sessionId=this.requestId=null;this.items=a;this.customData=this.insertBefore=null};x("chrome.cast.media.QueueInsertItemsRequest",chrome.cast.media.sa);chrome.cast.media.hb=function(a){this.type="QUEUE_UPDATE";this.sessionId=this.requestId=null;this.items=a;this.customData=null};x("chrome.cast.media.QueueUpdateItemsRequest",chrome.cast.media.hb);
chrome.cast.media.M=function(){this.type="QUEUE_UPDATE";this.customData=this.jump=this.currentItemId=this.sessionId=this.requestId=null};x("chrome.cast.media.QueueJumpRequest",chrome.cast.media.M);chrome.cast.media.wa=function(){this.type="QUEUE_UPDATE";this.customData=this.repeatMode=this.sessionId=this.requestId=null};x("chrome.cast.media.QueueSetPropertiesRequest",chrome.cast.media.wa);
chrome.cast.media.ua=function(a){this.type="QUEUE_REMOVE";this.sessionId=this.requestId=null;this.itemIds=a;this.customData=null};x("chrome.cast.media.QueueRemoveItemsRequest",chrome.cast.media.ua);chrome.cast.media.va=function(a){this.type="QUEUE_REORDER";this.sessionId=this.requestId=null;this.itemIds=a;this.customData=this.insertBefore=null};x("chrome.cast.media.QueueReorderItemsRequest",chrome.cast.media.va);
chrome.cast.media.Ja=function(a,b,c){this.id=a;this.breakClipIds=b;this.position=c;this.duration=void 0;this.isWatched=!1;this.isEmbedded=void 0};x("chrome.cast.media.Break",chrome.cast.media.Ja);chrome.cast.media.Ka=function(a){this.id=a;this.vastAdsRequest=this.customData=this.hlsSegmentFormat=this.clickThroughUrl=this.posterUrl=this.whenSkippable=this.duration=this.title=this.contentType=this.contentUrl=this.contentId=void 0};x("chrome.cast.media.BreakClip",chrome.cast.media.Ka);
chrome.cast.media.Bb=function(){this.adsResponse=this.adTagUrl=void 0};x("chrome.cast.media.VastAdsRequest",chrome.cast.media.Bb);chrome.cast.media.La=function(){this.whenSkippable=this.breakClipId=this.breakId=this.currentBreakClipTime=this.currentBreakTime=void 0};x("chrome.cast.media.BreakStatus",chrome.cast.media.La);chrome.cast.media.ma=function(a,b,c,d){this.start=a;this.end=b;this.isMovingWindow=c;this.isLiveDone=d};x("chrome.cast.media.LiveSeekableRange",chrome.cast.media.ma);
chrome.cast.media.eb=function(a,b,c,d,e,h,k){this.id=a;this.queueType=this.entity=void 0;this.name=b;this.description=c;this.repeatMode=d;this.shuffle=!1;this.items=e;this.startIndex=h;this.startTime=k;this.containerMetadata=void 0};x("chrome.cast.media.QueueData",chrome.cast.media.eb);chrome.cast.media.Ab=function(a){this.userAction=a;this.customData=void 0};x("chrome.cast.media.UserActionState",chrome.cast.media.Ab);chrome.cast.media.Cb=function(a,b,c){this.width=a;this.height=b;this.hdrType=c};
x("chrome.cast.media.VideoInformation",chrome.cast.media.Cb);var B=null;chrome.cast.media.h=function(a,b){this.sessionId=a;this.mediaSessionId=b;this.media=null;this.videoInfo=this.queueData=void 0;this.playbackRate=1;this.playerState=chrome.cast.media.B.IDLE;this.currentTime=0;this.g=-1;this.supportedMediaCommands=[];this.volume=new chrome.cast.Volume;this.items=this.preloadedItemId=this.loadingItemId=this.currentItemId=this.customData=this.activeTrackIds=this.idleReason=null;this.repeatMode=chrome.cast.media.V.OFF;this.breakStatus=void 0;this.l=!1;this.i=[];this.liveSeekableRange=
void 0};f=chrome.cast.media.h.prototype;f.P=function(a,b,c){a||(a=new chrome.cast.media.la);B.m(this,"MEDIA_GET_STATUS",a,b,c,chrome.cast.media.timeout.P)};f.play=function(a,b,c){var d=B;a||(a=new chrome.cast.media.ra);d.m(this,"PLAY",a,b,c,chrome.cast.media.timeout.play)};f.pause=function(a,b,c){var d=B;a||(a=new chrome.cast.media.pa);d.m(this,"PAUSE",a,b,c,chrome.cast.media.timeout.pause)};f.seek=function(a,b,c){B.m(this,"SEEK",a,b,c,chrome.cast.media.timeout.seek)};
f.stop=function(a,b,c){a||(a=new chrome.cast.media.ya);B.m(this,"STOP_MEDIA",a,b,c,chrome.cast.media.timeout.stop)};f.R=function(a,b,c){B.m(this,"MEDIA_SET_VOLUME",a,b,c,chrome.cast.media.timeout.R)};f.O=function(a,b,c){B.m(this,"EDIT_TRACKS_INFO",a,b,c,chrome.cast.media.timeout.O)};f.Tb=function(a,b,c){B.m(this,"QUEUE_INSERT",a,b,c,chrome.cast.media.timeout.v)};f.Sb=function(a,b,c){B.m(this,"QUEUE_INSERT",new chrome.cast.media.sa([a]),b,c,chrome.cast.media.timeout.v)};
f.dc=function(a,b,c){B.m(this,"QUEUE_UPDATE",a,b,c,chrome.cast.media.timeout.v)};f.Yb=function(a,b){var c=new chrome.cast.media.M;c.jump=-1;B.m(this,"QUEUE_UPDATE",c,a,b,chrome.cast.media.timeout.v)};f.Xb=function(a,b){var c=new chrome.cast.media.M;c.jump=1;B.m(this,"QUEUE_UPDATE",c,a,b,chrome.cast.media.timeout.v)};f.Ub=function(a,b,c){if(!(C(this,a)<0)){var d=new chrome.cast.media.M;d.currentItemId=a;B.m(this,"QUEUE_UPDATE",d,b,c,chrome.cast.media.timeout.v)}};
f.cc=function(a,b,c){var d=new chrome.cast.media.wa;d.repeatMode=a;B.m(this,"QUEUE_UPDATE",d,b,c,chrome.cast.media.timeout.v)};f.ac=function(a,b,c){B.m(this,"QUEUE_REMOVE",a,b,c,chrome.cast.media.timeout.v)};f.Zb=function(a,b,c){C(this,a)<0||B.m(this,"QUEUE_REMOVE",new chrome.cast.media.ua([a]),b,c,chrome.cast.media.timeout.v)};f.bc=function(a,b,c){B.m(this,"QUEUE_REORDER",a,b,c,chrome.cast.media.timeout.v)};
f.Wb=function(a,b,c,d){var e=C(this,a);if(!(e<0))if(b<0)d&&d(new chrome.cast.Error(chrome.cast.A.INVALID_PARAMETER));else if(e==b)c&&c();else{var h=null;b=b>e?b+1:b;b<this.items.length&&(h=this.items[b]);a=new chrome.cast.media.va([a]);a.insertBefore=h?h.itemId:null;B.m(this,"QUEUE_REORDER",a,c,d,chrome.cast.media.timeout.v)}};f.qc=function(a){return this.supportedMediaCommands.indexOf(a)>-1};
f.Nb=function(){if(this.playerState==chrome.cast.media.B.PLAYING&&this.g>=0){var a=this.currentTime+(Date.now()-this.g)/1E3*this.playbackRate;this.media&&this.media.duration!=null&&a>this.media.duration&&this.media.duration!=-1&&(a=this.media.duration);a<0&&(a=0);return a}return this.currentTime};f.Lb=function(){if(this.breakStatus&&this.breakStatus.currentBreakTime!==void 0)return this.playerState==chrome.cast.media.B.PLAYING&&this.g>=0?this.breakStatus.currentBreakTime+(Date.now()-this.g)/1E3:this.breakStatus.currentBreakTime};
f.Kb=function(){if(this.breakStatus&&this.breakStatus.currentBreakClipTime!==void 0)return this.playerState==chrome.cast.media.B.PLAYING&&this.g>=0?this.breakStatus.currentBreakClipTime+(Date.now()-this.g)/1E3:this.breakStatus.currentBreakClipTime};
f.Mb=function(){if(this.liveSeekableRange&&this.liveSeekableRange.start!==void 0&&this.liveSeekableRange.end!==void 0){if(this.playerState==chrome.cast.media.B.PLAYING&&this.g>=0){var a=(Date.now()-this.g)/1E3,b=new chrome.cast.media.ma;b.isMovingWindow=this.liveSeekableRange.isMovingWindow;b.isLiveDone=this.liveSeekableRange.isLiveDone;b.start=b.isMovingWindow?this.liveSeekableRange.start+a:this.liveSeekableRange.start;b.end=b.isLiveDone?this.liveSeekableRange.end:this.liveSeekableRange.end+a;return b}return this.liveSeekableRange}};
f.Y=function(a){B.Gb(this,a)};f.ba=function(a){B.fc(this,a)};var C=function(a,b){return Ca(a.items,function(c){return c.itemId==b})};x("chrome.cast.media.Media",chrome.cast.media.h);chrome.cast.media.h.prototype.removeUpdateListener=chrome.cast.media.h.prototype.ba;chrome.cast.media.h.prototype.addUpdateListener=chrome.cast.media.h.prototype.Y;chrome.cast.media.h.prototype.getEstimatedLiveSeekableRange=chrome.cast.media.h.prototype.Mb;chrome.cast.media.h.prototype.getEstimatedBreakClipTime=chrome.cast.media.h.prototype.Kb;
chrome.cast.media.h.prototype.getEstimatedBreakTime=chrome.cast.media.h.prototype.Lb;chrome.cast.media.h.prototype.getEstimatedTime=chrome.cast.media.h.prototype.Nb;chrome.cast.media.h.prototype.supportsCommand=chrome.cast.media.h.prototype.qc;chrome.cast.media.h.prototype.queueMoveItemToNewIndex=chrome.cast.media.h.prototype.Wb;chrome.cast.media.h.prototype.queueReorderItems=chrome.cast.media.h.prototype.bc;chrome.cast.media.h.prototype.queueRemoveItem=chrome.cast.media.h.prototype.Zb;
chrome.cast.media.h.prototype.queueRemoveItems=chrome.cast.media.h.prototype.ac;chrome.cast.media.h.prototype.queueSetRepeatMode=chrome.cast.media.h.prototype.cc;chrome.cast.media.h.prototype.queueJumpToItem=chrome.cast.media.h.prototype.Ub;chrome.cast.media.h.prototype.queueNext=chrome.cast.media.h.prototype.Xb;chrome.cast.media.h.prototype.queuePrev=chrome.cast.media.h.prototype.Yb;chrome.cast.media.h.prototype.queueUpdateItems=chrome.cast.media.h.prototype.dc;
chrome.cast.media.h.prototype.queueAppendItem=chrome.cast.media.h.prototype.Sb;chrome.cast.media.h.prototype.queueInsertItems=chrome.cast.media.h.prototype.Tb;chrome.cast.media.h.prototype.editTracksInfo=chrome.cast.media.h.prototype.O;chrome.cast.media.h.prototype.setVolume=chrome.cast.media.h.prototype.R;chrome.cast.media.h.prototype.stop=chrome.cast.media.h.prototype.stop;chrome.cast.media.h.prototype.seek=chrome.cast.media.h.prototype.seek;chrome.cast.media.h.prototype.pause=chrome.cast.media.h.prototype.pause;
chrome.cast.media.h.prototype.play=chrome.cast.media.h.prototype.play;chrome.cast.media.h.prototype.getStatus=chrome.cast.media.h.prototype.P;var Ha=function(a,b,c){this.sessionId=a;this.namespaceName=b;this.message=c};var Ia=function(a,b){this.type="SET_VOLUME";this.requestId=0;this.volume=a;this.expectedVolume=b||null};var Ja=function(a){this.type="STOP";this.requestId=0;this.sessionId=a||null};chrome.cast.j=function(a,b,c,d,e){this.sessionId=a;this.appId=b;this.displayName=c;this.statusText=null;this.appImages=d;this.receiver=e;this.senderApps=[];this.namespaces=[];this.media=[];this.status=chrome.cast.K.CONNECTED;this.transportId=""};f=chrome.cast.j.prototype;f.oc=function(a,b,c){var d=B;a=new Ia(new chrome.cast.Volume(a,null),this.receiver.volume);d.setReceiverVolume(this.sessionId,a,b,c)};
f.nc=function(a,b,c){a=new Ia(new chrome.cast.Volume(null,a),this.receiver.volume);B.setReceiverVolume(this.sessionId,a,b,c)};f.getDialAppInfo=function(a,b){B.getDialAppInfo(a,b)};f.Ob=function(a,b){B.leaveSession(this.sessionId,a,b)};f.stop=function(a,b){B.Da(new Ja(this.sessionId),a,b,chrome.cast.timeout.stopSession)};f.sendMessage=function(a,b,c,d){B.kc(new Ha(this.sessionId,a,b),c,d)};f.Y=function(a){B.Ib(this.sessionId,a)};f.ba=function(a){B.jc(this.sessionId,a)};
f.Hb=function(a,b){B.Fb(this.sessionId,a,b)};f.W=function(a){B.W(this.sessionId,a)};f.Z=function(a){B.Z(this.sessionId,a)};f.hc=function(a,b){B.ec(this.sessionId,a,b)};f.Pb=function(a,b,c){a.sessionId=this.sessionId;B.Ea(a,"LOAD",b,c)};f.Vb=function(a,b,c){a.sessionId=this.sessionId;B.Ea(a,"QUEUE_LOAD",b,c)};x("chrome.cast.Session",chrome.cast.j);chrome.cast.j.prototype.queueLoad=chrome.cast.j.prototype.Vb;chrome.cast.j.prototype.loadMedia=chrome.cast.j.prototype.Pb;
chrome.cast.j.prototype.removeMessageListener=chrome.cast.j.prototype.hc;chrome.cast.j.prototype.removeMediaListener=chrome.cast.j.prototype.Z;chrome.cast.j.prototype.addMediaListener=chrome.cast.j.prototype.W;chrome.cast.j.prototype.addMessageListener=chrome.cast.j.prototype.Hb;chrome.cast.j.prototype.removeUpdateListener=chrome.cast.j.prototype.ba;chrome.cast.j.prototype.addUpdateListener=chrome.cast.j.prototype.Y;chrome.cast.j.prototype.sendMessage=chrome.cast.j.prototype.sendMessage;
chrome.cast.j.prototype.stop=chrome.cast.j.prototype.stop;chrome.cast.j.prototype.leave=chrome.cast.j.prototype.Ob;chrome.cast.j.prototype.getDialAppInfo=chrome.cast.j.prototype.getDialAppInfo;chrome.cast.j.prototype.setReceiverMuted=chrome.cast.j.prototype.nc;chrome.cast.j.prototype.setReceiverVolumeLevel=chrome.cast.j.prototype.oc;var D=function(a,b){this.g=a[r.Symbol.iterator]();this.i=b};D.prototype[Symbol.iterator]=function(){return this};D.prototype.next=function(){var a=this.g.next();return{value:a.done?void 0:this.i.call(void 0,a.value),done:a.done}};var Ka=function(a,b){return new D(a,b)};var E=function(){};E.prototype.next=function(){return F};var F=Da({done:!0,value:void 0});E.prototype.o=function(){return this};var La=function(a){if(a instanceof E)return a;if(typeof a.o=="function")return a.o(!1);if(u(a)){var b=0,c=new E;c.next=function(){for(;;){if(b>=a.length)return F;if(b in a)return{value:a[b++],done:!1};b++}};return c}throw Error("Not implemented");},G=function(a,b){if(u(a))Ba(a,b);else for(a=La(a);;){var c=a.next();if(c.done)break;b.call(void 0,c.value,void 0,a)}};var Ma=function(a){if(a instanceof H||a instanceof I||a instanceof J)return a;if(typeof a.next=="function")return new H(function(){return a});if(typeof a[Symbol.iterator]=="function")return new H(function(){return a[Symbol.iterator]()});if(typeof a.o=="function")return new H(function(){return a.o()});throw Error("Not an iterator or iterable.");},H=function(a){this.g=a};H.prototype.o=function(){return new I(this.g())};H.prototype[Symbol.iterator]=function(){return new J(this.g())};H.prototype.i=function(){return new J(this.g())};
var I=function(a){this.g=a};q(I,E);I.prototype.next=function(){return this.g.next()};I.prototype[Symbol.iterator]=function(){return new J(this.g)};I.prototype.i=function(){return new J(this.g)};var J=function(a){H.call(this,function(){return a});this.l=a};q(J,H);J.prototype.next=function(){return this.l.next()};var K=function(a,b){this.i={};this.g=[];this.l=this.size=0;var c=arguments.length;if(c>1){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else if(a)if(a instanceof K)for(c=Na(a),d=0;d<c.length;d++)this.set(c[d],a.get(c[d]));else for(d in a)this.set(d,a[d])};K.prototype.L=function(){L(this);for(var a=[],b=0;b<this.g.length;b++)a.push(this.i[this.g[b]]);return a};var Na=function(a){L(a);return a.g.concat()};
K.prototype.has=function(a){return M(this.i,a)};K.prototype.clear=function(){this.i={};this.l=this.size=this.g.length=0};K.prototype.remove=function(a){return this.delete(a)};K.prototype.delete=function(a){return M(this.i,a)?(delete this.i[a],--this.size,this.l++,this.g.length>2*this.size&&L(this),!0):!1};
var L=function(a){if(a.size!=a.g.length){for(var b=0,c=0;b<a.g.length;){var d=a.g[b];M(a.i,d)&&(a.g[c++]=d);b++}a.g.length=c}if(a.size!=a.g.length){b={};for(d=c=0;c<a.g.length;){var e=a.g[c];M(b,e)||(a.g[d++]=e,b[e]=1);c++}a.g.length=d}};f=K.prototype;f.get=function(a,b){return M(this.i,a)?this.i[a]:b};f.set=function(a,b){M(this.i,a)||(this.size+=1,this.g.push(a),this.l++);this.i[a]=b};f.forEach=function(a,b){for(var c=Na(this),d=0;d<c.length;d++){var e=c[d],h=this.get(e);a.call(b,h,e,this)}};
f.keys=function(){return Ma(this.o(!0)).i()};f.values=function(){return Ma(this.o(!1)).i()};f.entries=function(){var a=this;return Ka(this.keys(),function(b){return[b,a.get(b)]})};f.o=function(a){L(this);var b=0,c=this.l,d=this,e=new E;e.next=function(){if(c!=d.l)throw Error("The map has changed since the iterator was created");if(b>=d.g.length)return F;var h=d.g[b++];return{value:a?h:d.i[h],done:!1}};return e};var M=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)};var N=function(a,b){this.requestId=a;this.u=b;this.Ga=null};N.prototype.i=function(){};var Oa=function(){this.g=new K},Pa=function(a,b){a.g.set(b.requestId,b);b.Ga=setTimeout(function(){a.g.delete(b.requestId);b.i()},b.u)},Qa=function(a,b){var c=a.g.get(b);if(!c)return null;clearTimeout(c.Ga);a.g.delete(b);return c};var O=function(a,b,c,d){N.call(this,a,d||6E5);this.l=b;this.g=c};q(O,N);O.prototype.i=function(){this.g(new chrome.cast.Error(chrome.cast.A.TIMEOUT))};var P=function(a,b,c,d){this.type=a;this.message=b;this.sequenceNumber=c!==void 0?c:-1;this.timeoutMillis=d||0;this.clientId=""};var Q=function(a){this.l=a;this.i=String(Date.now())+String(Math.floor(Math.random()*1E5));this.g=null},Ra=function(a,b){if(!a.g)return"No active session";b.clientId=a.i;b=JSON.stringify(b);if(b.length>32768)return"Message length over limit";a.g.send(b);return null};Q.prototype.connect=function(a){this.g=a;this.g.onmessage=w(this.u,this);Ra(this,new P("client_connect",this.i))};Q.prototype.disconnect=function(){this.g.close();this.g=null};
Q.prototype.u=function(a){a=JSON.parse(a.data);if(a.clientId==this.i)this.l.onMessage(a)};var Sa=function(a,b,c){this.l=a;this.i=b;this.g=c},Ta=function(a){var b="cast-dial:"+a.l,c=new URLSearchParams;a.i&&c.set("dialPostData",a.i);a.g&&c.set("clientId",a.g);(a=c.toString())&&(b+="?"+a);return b};var Ua=function(a,b,c,d,e,h,k,m,p,t){this.I=a;this.g=b||null;this.l=c||null;this.C=d||null;this.D=e!==void 0?e:null;this.i=h||null;this.H=k||null;this.J=m||!1;this.G=p?["WEB","ANDROID_TV"]:["WEB"];this.u=t||null},Va=function(a){var b=a.I.map(function(c){var d="cast:"+c.appId,e=new URLSearchParams;c.capabilities&&c.capabilities.length>0&&e.set("capabilities",c.capabilities.join(","));a.g&&e.set("clientId",a.g);a.l&&e.set("autoJoinPolicy",a.l);a.C&&e.set("defaultActionPolicy",a.C);a.D!=null&&e.set("launchTimeout",
String(a.D));a.J&&e.set("invisibleSender","true");e.set("supportedAppTypes",a.G.join(","));c=e.set;var h=JSON,k=h.stringify,m={launchCheckerParams:{}};a.u&&(m.launchCheckerParams.credentialsData=a.u);c.call(e,"appParams",k.call(h,m));return d+"?"+e.toString()});a.i&&b.push(Ta(new Sa(a.i,a.H,a.g)));return b};var Wa=function(){this.g={};this.i={}},Xa=function(a,b,c){var d=a.g[b];return d?(d.status=c,d.media.forEach(function(e){delete a.i[e.sessionId+"#"+e.mediaSessionId]}),delete a.g[b],!0):!1},Za=function(a,b){var c=a.g[b.sessionId];if(c)return c.statusText=b.statusText,c.namespaces=b.namespaces||[],c.receiver.volume=b.receiver.volume,c;c=new chrome.cast.j(b.sessionId,b.appId,b.displayName,b.appImages,b.receiver);for(var d in b)d=="media"?c.media=b.media.map(function(e){e=Ya(a,e);e.u=!1;e.l=!0;return e}):
b.hasOwnProperty(d)&&(c[d]=b[d]);return a.g[b.sessionId]=c},Ya=function(a,b){var c=b.sessionId+"#"+b.mediaSessionId,d=a.i[c];d||(d=new chrome.cast.media.h(b.sessionId,b.mediaSessionId),a.i[c]=d,(a=a.g[b.sessionId])&&a.media.push(d));a=d;a.currentItemId=null;a.loadingItemId=null;a.preloadedItemId=null;for(var e in b)e!="items"&&b.hasOwnProperty(e)&&(e=="volume"?(a.volume.level=b.volume.level,a.volume.muted=b.volume.muted):a[e]=b[e]);e=ka(["idleReason","extendedStatus","breakStatus"]);for(c=e.next();!c.done;c=
e.next())c=c.value,b.hasOwnProperty(c)||(a[c]=null);"currentTime"in b&&(a.g=Date.now());if(a.playerState==chrome.cast.media.B.IDLE&&a.loadingItemId==null)a.currentItemId=null,a.loadingItemId=null,a.preloadedItemId=null,a.items=null;else if(b.hasOwnProperty("items")&&b.items){e=[];var h=a.items;c={};if(h)for(var k=0;k<h.length;k++)c[h[k].itemId]=k;b=ka(b.items);for(h=b.next();!h.done;h=b.next()){h=h.value;if(!h.media){k=h.itemId;var m=a.items?a.items[c[k]]:null;m&&m.media?h.media=m.media:k==a.currentItemId&&
a.media&&(h.media=a.media)}k=e;m=k.push;var p=void 0,t=new chrome.cast.media.ta(h.media);for(p in h)h.hasOwnProperty(p)&&(t[p]=h[p]);m.call(k,t)}a.items=e}return d},$a=function(a,b){delete a.i[b.sessionId+"#"+b.mediaSessionId];if(a=a.g[b.sessionId])b=a.media.indexOf(b),b!=-1&&a.media.splice(b,1)};function R(){var a=r.navigator;return a&&(a=a.userAgent)?a:""};var ab=R().toLowerCase().indexOf("webkit")!=-1&&R().indexOf("Edge")==-1;var bb={},S=null,cb=R().indexOf("Gecko")!=-1&&!(R().toLowerCase().indexOf("webkit")!=-1&&R().indexOf("Edge")==-1)&&!(R().indexOf("Trident")!=-1||R().indexOf("MSIE")!=-1)&&R().indexOf("Edge")==-1||ab||typeof r.btoa=="function",db=function(a){if(cb)var b=r.btoa(a);else{b=[];for(var c=0,d=0;d<a.length;d++){var e=a.charCodeAt(d);if(e>255)throw Error("go/unicode-to-byte-error");b[c++]=e}a=void 0;a===void 0&&(a=0);if(!S)for(S={},c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),
d=["+/=","+/","-_=","-_.","-_"],e=0;e<5;e++){var h=c.concat(d[e].split(""));bb[e]=h;for(var k=0;k<h.length;k++){var m=h[k];S[m]===void 0&&(S[m]=k)}}a=bb[a];c=Array(Math.floor(b.length/3));d=a[64]||"";for(e=h=0;h<b.length-2;h+=3){var p=b[h],t=b[h+1];m=b[h+2];k=a[p>>2];p=a[(p&3)<<4|t>>4];t=a[(t&15)<<2|m>>6];m=a[m&63];c[e++]=""+k+p+t+m}k=0;m=d;switch(b.length-h){case 2:k=b[h+1],m=a[(k&15)<<2]||d;case 1:b=b[h],c[e]=""+a[b>>2]+a[(b&3)<<4|k>>4]+m+d}b=c.join("")}return b};var eb=function(a){if(a.L&&typeof a.L=="function")return a.L();if(typeof Map!=="undefined"&&a instanceof Map||typeof Set!=="undefined"&&a instanceof Set)return Array.from(a.values());if(typeof a==="string")return a.split("");if(u(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}b=[];c=0;for(d in a)b[c++]=a[d];return b};var T=function(){this.g=new K;this.size=0},U=function(a){var b=typeof a;return b=="object"&&a||b=="function"?"o"+(Object.prototype.hasOwnProperty.call(a,v)&&a[v]||(a[v]=++la)):b.slice(0,1)+a};f=T.prototype;f.add=function(a){this.g.set(U(a),a);this.size=this.g.size};f.removeAll=function(a){a=eb(a);for(var b=a.length,c=0;c<b;c++)this.remove(a[c]);this.size=this.g.size};f.delete=function(a){a=this.g.remove(U(a));this.size=this.g.size;return a};f.remove=function(a){return this.delete(a)};
f.clear=function(){this.g.clear();this.size=0};f.has=function(a){var b=this.g;a=U(a);return b.has(a)};f.contains=function(a){var b=this.g;a=U(a);return b.has(a)};f.L=function(){return this.g.L()};f.values=function(){return this.g.values()};f.o=function(){return this.g.o(!1)};T.prototype[Symbol.iterator]=function(){return this.values()};var V=function(){this.C=new Q(this);this.g=null;this.G=new Wa;this.i=0;this.S=new Oa;this.D=new K;this.u=new K;this.I=new K;this.J=[];this.Oa=this.Jb.bind(this);this.ia=this.H=this.l=null},fb=function(a){var b=new chrome.cast.Error(chrome.cast.A.INVALID_PARAMETER,"Already requesting session");a&&a(b)},W=function(a,b,c,d){c&&Pa(a.S,c);d!==void 0?b.sequenceNumber=d:(b.sequenceNumber=a.i,a.i=(a.i+1)%9007199254740992);d=Ra(a.C,b);c&&d&&(a=Qa(a.S,b.sequenceNumber))&&(a=a.g,d=new chrome.cast.Error(chrome.cast.A.INVALID_PARAMETER,
d),a&&a(d))};
V.prototype.initialize=function(a,b){var c=this;B=this;this.g=a;a.invisibleSender||(a=new PresentationRequest(X(this)),a.getAvailability().then(function(d){d.onchange=function(){c.g.receiverListener(d.value?chrome.cast.N.AVAILABLE:chrome.cast.N.UNAVAILABLE)};d.onchange()},function(){c.g.receiverListener(chrome.cast.N.AVAILABLE)}),a.onconnectionavailable=function(d){Y(c,d.connection)},this.ia=(r.navigator||null).presentation.defaultRequest=a,a.reconnect(chrome.cast.Ha).then(function(d){Y(c,d)},function(){}));
b&&b(void 0)};V.prototype.da=function(a){a.navigator.presentation.defaultRequest=this.ia};var Y=function(a,b,c){c=c===void 0?null:c;b.onclose=function(d){a.l=null;switch(d.reason){case "closed":gb(a,chrome.cast.K.DISCONNECTED);break;case "error":if(c){d=c;var e=new chrome.cast.Error(chrome.cast.A.SESSION_ERROR);d&&d(e)}}};b.onterminate=function(){gb(a,chrome.cast.K.STOPPED)};b.state=="connected"?a.C.connect(b):b.onconnect=function(){a.C.connect(b)}};
V.prototype.requestSession=function(a,b,c){var d=this;this.l?fb(b):(c=X(this,c),this.l=a,(new PresentationRequest(c)).start().then(function(e){Y(d,e,b)}).catch(function(e){d.l=null;e=new chrome.cast.Error(e.name=="AbortError"||e.name=="NotAllowedError"?chrome.cast.A.CANCEL:chrome.cast.A.SESSION_ERROR);b&&b(e)}))};
var X=function(a,b){var c=null,d=null;b=b||a.g.sessionRequest;var e=b.dialRequest;e&&(c=e.appName,(d=e.launchParameter)&&!d.match(hb)&&(d=db(d)));var h=[];h.push({appId:b.appId,capabilities:b.capabilities});b||Ba(a.g.additionalSessionRequests,function(k){h.push({appId:k.appId,capabilities:k.capabilities})});return Va(new Ua(h,a.C.i,a.g.autoJoinPolicy,a.g.defaultActionPolicy,b.requestSessionTimeout,c,d,a.g.invisibleSender,b.androidReceiverCompatible,b.credentialsData))};
V.prototype.Ea=function(a,b,c,d){ib(this,null,b,a,function(e){e.l=!0;c&&c(e)},function(e){d(e)},chrome.cast.media.timeout.load)};V.prototype.m=function(a,b,c,d,e,h){var k=this;ib(this,a,b,c,function(m){k.Ca(m);d&&d(void 0)},e,h)};var ib=function(a,b,c,d,e,h,k){d.type=c;b!=null&&(d.mediaSessionId=b.mediaSessionId,d.sessionId=b.sessionId);a.Da(d,function(m){m.status&&m.status.length==1?e&&e(m.status[0]):(m=new chrome.cast.Error(chrome.cast.A.SESSION_ERROR),h&&h(m))},h,k)};f=V.prototype;
f.setReceiverVolume=function(a,b,c,d){b.sessionId=a;W(this,new P("v2_message",b,void 0,chrome.cast.timeout.setReceiverVolume),new O(this.i,c,d,chrome.cast.timeout.sendCustomMessage))};f.getDialAppInfo=function(a,b){W(this,new P("dial_app_info",void 0,void 0,chrome.cast.timeout.getDialAppInfo),new O(this.i,a,b,chrome.cast.timeout.sendCustomMessage))};f.ca=function(a){var b=this;(new PresentationRequest(X(this))).reconnect(chrome.cast.cb+a).then(function(c){Y(b,c)},function(){})};
f.leaveSession=function(a,b,c){W(this,new P("leave_session",a,void 0,chrome.cast.timeout.leaveSession),new O(this.i,b,c,chrome.cast.timeout.leaveSession))};f.kc=function(a,b,c){W(this,new P("app_message",a,void 0,chrome.cast.timeout.sendCustomMessage),new O(this.i,b,c,chrome.cast.timeout.sendCustomMessage))};f.Da=function(a,b,c,d){W(this,new P("v2_message",a,void 0,d),new O(this.i,b,c,d))};var jb=function(a,b,c){var d=a.get(b);d||(d=new T,a.set(b,d));d.add(c)};f=V.prototype;
f.Ib=function(a,b){jb(this.D,a,b)};f.jc=function(a,b){(a=this.D.get(a))&&a.remove(b)};f.X=function(a){this.J.push(a)};f.aa=function(a){a=this.J.indexOf(a);a>=0&&this.J.splice(a,1)};f.Fb=function(a,b,c){var d=this.u.get(a);d||(d=new K,this.u.set(a,d));a=d.get(b);a||(a=new T,d.set(b,a));a.add(c)};f.ec=function(a,b,c){(a=this.u.get(a))&&(b=a.get(b))&&b.remove(c)};f.W=function(a,b){jb(this.I,a,b)};f.Z=function(a,b){(a=this.I.get(a))&&a.remove(b)};f.Gb=function(a,b){a.i.indexOf(b)==-1&&a.i.push(b)};
f.fc=function(a,b){b=a.i.indexOf(b);b!=-1&&a.i.splice(b,1)};f.Ca=function(a){if(a.l){var b=a.playerState!=chrome.cast.media.B.IDLE||a.loadingItemId!=null;a.i.forEach(function(d){d(b)});b||$a(this.G,a)}else{a.l=!0;var c=this.I.get(a.sessionId);c&&G(c.o(),function(d){d(a)})}};f.Jb=function(a){return Ya(this.G,a)};var gb=function(a,b){if(a.H){var c=a.H;a.H=null;a.C.disconnect();var d=b!=chrome.cast.K.STOPPED;Xa(a.G,c,b)&&(a.u.delete(c),a.I.delete(c),b=a.D.get(c))&&(a.D.delete(c),G(b.o(),function(e){e(d)}))}};
V.prototype.onMessage=function(a){switch(a.type){case "new_session":case "update_session":a.message=Za(this.G,a.message);break;case "v2_message":var b=a.message;b&&b.type=="MEDIA_STATUS"&&b.status&&(b.status=b.status.map(this.Oa))}if(b=Qa(this.S,a.sequenceNumber))a.type=="error"?(b=b.g)&&b(a.message):(b=b.l)&&b(a.message);if(b=a.message)switch(a.type){case "receiver_action":kb(this,b);break;case "new_session":this.H=b.sessionId;this.l?(this.l(b),this.l=null):this.g&&this.g.sessionListener(b);break;
case "update_session":lb(this,b);break;case "app_message":mb(this,b);break;case "v2_message":b.type=="MEDIA_STATUS"&&b.status.forEach(this.Ca.bind(this));break;case "custom_dial_launch":nb(this,a.sequenceNumber,b)}};
var lb=function(a,b){(a=a.D.get(b.sessionId))&&G(a.o(),function(c){c(!0)})},kb=function(a,b){a.J.forEach(function(c){c(b.receiver,b.action)})},mb=function(a,b){(a=a.u.get(b.sessionId))&&(a=a.get(b.namespaceName))&&G(a.o(),function(c){c(b.namespaceName,b.message)})},ob=function(a,b,c){W(a,new P("custom_dial_launch",c,void 0,chrome.cast.timeout.sendCustomMessage),null,b)},nb=function(a,b,c){a.g.customDialLaunchCallback?a.g.customDialLaunchCallback(c).then(function(d){ob(a,b,d)},function(){ob(a,b)}):
ob(a,b)},hb=RegExp("^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$"),Z=new V;chrome.cast.initialize=function(a,b,c){Z.initialize(a,b,c)};x("chrome.cast.initialize",chrome.cast.initialize);chrome.cast.da=function(a){Z.da(a)};x("chrome.cast.setPageContext",chrome.cast.da);chrome.cast.requestSession=function(a,b,c){Z.requestSession(a,b,c)};x("chrome.cast.requestSession",chrome.cast.requestSession);chrome.cast.Rb=function(){};x("chrome.cast.precache",chrome.cast.Rb);chrome.cast.ca=function(a){Z.ca(a)};x("chrome.cast.requestSessionById",chrome.cast.ca);chrome.cast.X=function(a){Z.X(a)};
x("chrome.cast.addReceiverActionListener",chrome.cast.X);chrome.cast.aa=function(a){Z.aa(a)};x("chrome.cast.removeReceiverActionListener",chrome.cast.aa);chrome.cast.Qb=function(){};x("chrome.cast.logMessage",chrome.cast.Qb);chrome.cast.lc=function(a,b){b()};x("chrome.cast.setCustomReceivers",chrome.cast.lc);chrome.cast.mc=function(a,b){b()};x("chrome.cast.setReceiverDisplayStatus",chrome.cast.mc);chrome.cast.unescape=function(a){return a.indexOf("&")!=-1?"document"in r?Fa(a):Ga(a):a};
x("chrome.cast.unescape",chrome.cast.unescape);chrome.cast.isAvailable=!1;x("chrome.cast.isAvailable",chrome.cast.isAvailable);chrome.cast.Fa=!1;chrome.cast.ea=function(){if(!chrome.cast.Fa){chrome.cast.Fa=!0;chrome.cast.isAvailable=!0;var a=window.__onGCastApiAvailable;a&&typeof a=="function"&&a(!0)}};document.readyState=="complete"?chrome.cast.ea():(window.addEventListener("load",chrome.cast.ea,!1),window.addEventListener("DOMContentLoaded",chrome.cast.ea,!1));}).call(this);

View File

@@ -0,0 +1,12 @@
(function(){/*
Copyright The Closure Library Authors.
SPDX-License-Identifier: Apache-2.0
*/
'use strict';var l=function(){var a=h,b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}},m=this||self,n=/^[\w+/_-]+[=]{0,2}$/,p=null,q=function(a){return(a=a.querySelector&&a.querySelector("script[nonce]"))&&(a=a.nonce||a.getAttribute("nonce"))&&n.test(a)?a:""},r=function(a,b){function e(){}e.prototype=b.prototype;a.i=b.prototype;a.prototype=new e;a.prototype.constructor=a;a.h=function(c,g,k){for(var f=Array(arguments.length-2),d=2;d<arguments.length;d++)f[d-2]=arguments[d];
return b.prototype[g].apply(c,f)}},t=function(a){return a};function u(a){if(Error.captureStackTrace)Error.captureStackTrace(this,u);else{var b=Error().stack;b&&(this.stack=b)}a&&(this.message=String(a))}r(u,Error);u.prototype.name="CustomError";var v=function(a,b){a=a.split("%s");for(var e="",c=a.length-1,g=0;g<c;g++)e+=a[g]+(g<b.length?b[g]:"%s");u.call(this,e+a[c])};r(v,u);v.prototype.name="AssertionError";var w=function(a,b){throw new v("Failure"+(a?": "+a:""),Array.prototype.slice.call(arguments,1));};var x;var A=function(a,b){this.g=b===z?a:""};A.prototype.toString=function(){return this.g+""};var z={};var B=function(){var a=window.navigator.userAgent.match(/Chrome\/([0-9]+)/);return a?parseInt(a[1],10):0},C=function(a){return!!document.currentScript&&(-1!=document.currentScript.src.indexOf("?"+a)||-1!=document.currentScript.src.indexOf("&"+a))},D=function(){return"function"==typeof window.__onGCastApiAvailable?window.__onGCastApiAvailable:null},F=function(a){a.length?E(a.shift(),function(){F(a)}):G()},H=function(a){return"chrome-extension://"+a+"/cast_sender.js"},E=function(a,b,e){var c=document.createElement("script");
c.onerror=b;e&&(c.onload=e);if(void 0===x)if(b=null,(e=m.trustedTypes)&&e.createPolicy){try{b=e.createPolicy("goog#html",{createHTML:t,createScript:t,createScriptURL:t})}catch(y){m.console&&m.console.error(y.message)}x=b}else x=b;a=(b=x)?b.createScriptURL(a):a;a=new A(a,z);a:{try{var g=c&&c.ownerDocument,k=g&&(g.defaultView||g.parentWindow);k=k||m;if(k.Element&&k.Location){var f=k;break a}}catch(y){}f=null}if(f&&"undefined"!=typeof f.HTMLScriptElement&&(!c||!(c instanceof f.HTMLScriptElement)&&(c instanceof
f.Location||c instanceof f.Element))){f=typeof c;if("object"==f&&null!=c||"function"==f)try{var d=c.constructor.displayName||c.constructor.name||Object.prototype.toString.call(c)}catch(y){d="<object could not be stringified>"}else d=void 0===c?"undefined":null===c?"null":typeof c;w("Argument is not a %s (or a non-Element, non-Location mock); got: %s","HTMLScriptElement",d)}a instanceof A&&a.constructor===A?d=a.g:(d=typeof a,w("expected object of type TrustedResourceUrl, got '"+a+"' of type "+("object"!=
d?d:a?Array.isArray(a)?"array":d:"null")),d="type_error:TrustedResourceUrl");c.src=d;(d=c.ownerDocument&&c.ownerDocument.defaultView)&&d!=m?d=q(d.document):(null===p&&(p=q(m.document)),d=p);d&&c.setAttribute("nonce",d);(document.head||document.documentElement).appendChild(c)},I=function(){var a=B(),b=[];if(1<a){var e=a-1;b.push("//www.gstatic.com/eureka/clank/"+a+"/cast_sender.js");b.push("//www.gstatic.com/eureka/clank/"+e+"/cast_sender.js")}return b},G=function(){var a=D();a&&a(!1,"No cast extension found")},
K=function(){if(J){var a=2,b=D(),e=function(){a--;0==a&&b&&b(!0)};window.__onGCastApiAvailable=e;E("//www.gstatic.com/cast/sdk/libs/sender/1.0/cast_framework.js",G,e)}},J=C("loadCastFramework")||C("loadCastApplicationFramework"),L=["pkedcjkdefgpdelpbcmbmeomcjbeemfm","enhhojjnijigcajfphajepfemndkmdlo"];if(0<=window.navigator.userAgent.indexOf("Android")&&0<=window.navigator.userAgent.indexOf("Chrome/")&&window.navigator.presentation){if(60<=B()){K();var M=I();M.push("//www.gstatic.com/eureka/clank/cast_sender.js");F(M)}}else if(!window.chrome||!window.navigator.presentation||0<=window.navigator.userAgent.indexOf("Edge"))G();else if(89<=B()){K();var N=I(),O=N.push,P=O.apply,h=L.map(H),Q;if(h instanceof Array)Q=h;else{var R,S="undefined"!=typeof Symbol&&Symbol.iterator&&h[Symbol.iterator];R=S?S.call(h):
{next:l()};for(var T,U=[];!(T=R.next()).done;)U.push(T.value);Q=U}P.call(O,N,Q);N.push("//www.gstatic.com/eureka/clank/cast_sender.js");F(N)}else K(),F(L.map(H));}).call(this);

View File

@@ -0,0 +1,3 @@
<svg width="14" height="11" viewBox="0 0 14 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.40014 10.2952L0.854126 5.74924L1.99063 4.61273L5.40014 8.02224L12.7176 0.704758L13.8541 1.84126L5.40014 10.2952Z" fill="#55BC62"/>
</svg>

After

Width:  |  Height:  |  Size: 246 B

View File

@@ -0,0 +1,622 @@
function UserNotifications() {
"use strict"
var self = this;
self.totalScrollHeight = 0;
self.topNotif = 0;
self.offSss = false;
self._tipTimeout = false;
self.notifBoxHtml;
self.audio = 1;
self.undelivN = 0;
self.HTTP_ENDPOINT = "/checkN.php";
self.startIntervals();
}
UserNotifications.prototype.startIntervals = function () {
"use strict"
var self = this;
var intervals = BidooCnf.intervals.user.notifications;
self.pingNotification();
setInterval(self.bidping.bind(self, getBidsBonus()), intervals.bidping);
setInterval(self.updateNotificationsDateTime.bind(self), intervals.updateNotificationsDateTime);
setInterval(self.pingNotification.bind(self), intervals.pingNotification);
setInterval(self.updateAuctionsWon.bind(self), intervals.auctionsWon); // [GR] for update badge number for auctions won to pay by user
}
UserNotifications.prototype.updateNotificationsDateTime = function () {
"use strict"
var self = this;
moment.locale('it');
self.getCorrectNotifSelector().find("abbr").each(function () {
var abbrTime = parseInt($(this).data("utime"), 10);
var newTime = parseInt((new Date()).getTime() / 1000, 10);
var moment_abbr_time = moment(abbrTime, "X");
var shouldBeFromNow = (newTime - abbrTime) < 21600;
$(this).data("alt", moment().format());
$(this).text(shouldBeFromNow ? moment_abbr_time.fromNow() : moment_abbr_time.calendar());
});
};
UserNotifications.prototype.updateAuctionsWon = function () { // [GR] for update badge number for auctions won to pay by user
"use strict"
$.get("/check_auctions_won.php", function (data) {
if (self.offSss) {
window.location.reload();
return;
}
$(".navbar-fixed-bottom #bottomAuctionsWonToPay").html(data);
$(".myBidooDesk #bottomAuctionsWonToPay").html(data);
$(".myBidooMobile #bottomAuctionsWonToPay").html(data);
$("#testataAuctionsWonToPay").html(data);
if (parseInt(data) > 0) {
$("#bottomAuctionsWonToPay").css("visibility", "visible");
$("#testataAuctionsWonToPay").css("visibility", "visible");
} else {
$("#bottomAuctionsWonToPay").css("visibility", "hidden");
$("#testataAuctionsWonToPay").css("visibility", "hidden");
}
});
}
UserNotifications.prototype.bidping = function (bonus) {
"use strict"
var self = this;
$.get("/bidping.php", function (data) {
if (self.offSss) {
window.location.reload();
return;
}
var progressValue = data[0] + "/" + data[1];
$("#seven_7").html(progressValue);
$(".bid-challenge [data-spot=0]")
.html(progressValue)
.parent()
.attr("data-progress", progressValue);
$(".leader-btn .progress-bar-success").css("width", ((data[0] / data[1]) * 100.00).toFixed(2) + "%");
if (data[0] >= data[1] && data[2] < data[1]) {
$('.bid-challenge .img-lock-open').hide();
$('.bid-challenge .img-lock').show();
$('#auctionBidBottomBar .wrap-progress').hide();
$('#auctionBidBottomBar .wrap-button-get-bonus').show();
}
if (data[0] >= data[1] && (typeof getCookie('won') == "undefined")) {
var expireWonDate = new Date();
expireWonDate.setTime(getTimeFrames());
self.wonChallenge(data[0], bonus);
setValueCookie("won", 1, expireWonDate);
}
}).fail(function (jqXHR, textStatus, error) {
if (jqXHR.status == 403) {
self.offSss = true;
$(".btn.leader-btn[data-target=#leader]")
.html(getSessionExpired(true))
.attr('data-toggle', null)
.attr('data-target', null)
.off("click").on({
click: showLogin
});
}
});
self.bidPingProduct();
}
UserNotifications.prototype.bidPingProduct = function () {
"use strict"
$.get("/bidping_product.php", function (data) {
if (self.offSss) {
window.location.reload();
return;
}
$(".bid-challenge-product").html(data);
});
}
UserNotifications.prototype.getCallTipMsg = function (credits, bonus) {
"use strict"
var html = [
"<div class='wrap'>",
"<div>",
"<img src='/images/razzo.svg'>",
"</div>",
"<div>",
"<strong>Complimenti!</strong>",
"<div>Hai Vinto " + credits + " Aste di Puntate</div>",
"</div>",
"</div>"
];
return html.join("");
}
UserNotifications.prototype.callTip = function (credits, bonus, callback) {
"use strict"
var self = this;
var tooltipReach = $(".tooltip.reach");
$(".leader-btn")
.tooltip('destroy').tooltip({
html: true,
placement: 'top',
title: self.getCallTipMsg(credits, bonus),
trigger: 'manual',
animation: false,
template: '<div class="tooltip reach" role="tooltip"><div class="tooltip-inner"></div></div>'
})
.tooltip("show");
tooltipReach.removeClass("bounceOutDown");
if (self._tipTimeout)
clearTimeout(self._tipTimeout);
self._tipTimeout = setTimeout(function () {
callback();
}, 10000);
}
UserNotifications.prototype.wonChallenge = function (nAuctions, bonus) {
"use strict"
var self = this;
var selector = $(".leader-btn > div.bid-challenge");
if (!selector.hasClass("achieved")) {
self.callTip(nAuctions, bonus);
}
}
UserNotifications.prototype.pingNotification = function () {
"use strict"
var self = this;
$.get(self.HTTP_ENDPOINT, {_t: 1}, function (r) {
if (r.count > 0) {
$(".bubble_desktop, .bubble_mobile, .toggle_bar_mobile").html(r.count).show();
if ($("#notifBox").is(":visible") || $("#notifBoxMobile").is(":visible")) {
self.loadNotification(true);
}
if (typeof r.undeliv != "undefined" && (Object.keys(r.undeliv).length > 0 && self.undelivN != Object.keys(r.undeliv).length)) {
var audioCookie = getCookie('audioN');
if (self.audio && ("undefined" == typeof audioCookie || audioCookie < r.count)) {
self
.playSound(r.audio)
.then(setCookieMinutes.bind(null, 'audioN', r.count, 5))
.catch(function () {
$(document)
.off('touchstart click')
.on('touchstart click', function () {
self.playSound(r.audio);
$(document).off('touchstart click');
});
});
}
self.undelivN = Object.keys(r.undeliv).length;
}
} else {
delCookie('audioN');
$(".bubble_desktop, .bubble_mobile").hide();
}
});
}
UserNotifications.prototype.playSound = function (audioSrc) {
"use strict"
var audio = $("#push");
if (audio.length)
audio.remove();
var aSound = document.createElement('audio');
aSound.id = 'push';
aSound.setAttribute('src', audioSrc + "?chk=" + (new Date()).getTime());
return aSound.play();
}
UserNotifications.prototype.toggleAudio = function (audioSetting) {
"use strict"
var self = this;
var isNotArgPassed = "undefined" == typeof audioSetting;
var snd = self.getCorrectNotifSelector().find(".sAudio");
var snData = !!(isNotArgPassed ? parseInt(snd.attr("data-audio")) : audioSetting);
snd.attr("data-audio", (!snData | 0))
.toggleClass("disabled glyphicon-volume-off", !snData)
.toggleClass("enabled glyphicon-volume-up", snData);
if (isNotArgPassed)
$.get(self.HTTP_ENDPOINT, {_s: (snData | 0)});
}
UserNotifications.prototype.loadSettings = function (shouldSetCheckOptions) {
"use strict"
var self = this;
$.get(self.HTTP_ENDPOINT, {_load: 0}, function (settings) {
self.audio = settings.audio;
self.toggleAudio(self.audio);
if (shouldSetCheckOptions) {
$("#ticketMail").prop("checked", !!+settings["1"]);
$("#creditMail").prop("checked", !!+settings["2"]);
$("#packageMail").prop("checked", !!+settings["3"]);
}
});
}
UserNotifications.prototype.cleanData = function (dirtyString) {
"use strict"
dirtyString = dirtyString.replace(/&amp;/g, "&");
dirtyString = dirtyString.replace(/&gt;/g, ">");
dirtyString = dirtyString.replace(/&lt;/g, "<");
dirtyString = dirtyString.replace(/&quot;/g, "\"");
dirtyString = dirtyString.replace("</i>", "</i><p class='paragraph-notification'>");
dirtyString = dirtyString.replace("</a>", "</p></a>");
dirtyString = dirtyString.replace("data-href", "data-mobile-fullscreen='true' data-no-padding-modal-body='true' data-href");
dirtyString = dirtyString.replace("//it.bidoo.com", "");
return dirtyString;
}
UserNotifications.prototype.getNotificationItem = function (data) {
"use strict"
var self = this;
var flag = parseInt(data.readFlag, 10);
var classNotif = 2 == flag ? "class='read wrap-notif'" : (1 == flag ? "class='deliv wrap-notif'" : "");
var item = [
"<li id='notification_" + data.id + "' data-type='" + data.type + "' " + classNotif + ">",
"<div class='notif-sx'>"+self.cleanData(data.content)+"</div>",
"<div class='notif-dx'><abbr data-utime='" + data.created_at + "'></abbr>",
"<i class='fa fa-clock-o clock-notification' aria-hidden='true'></i></div>",
"</li>"
];
return item.join("");
}
UserNotifications.prototype.getEmptyNotifications = function () {
"use strict"
var notif = [
'<li class="text-center empty-notification">',
'<p>Non hai alcuna notifica.</p>',
'</li>'
];
return notif.join("");
}
UserNotifications.prototype._renderN = function (data, more) {
"use strict"
var self = this;
var list = [];
var selector = this.getCorrectNotifSelector().find("ul");
if (data.length) {
$.each(data, function (i, item) {
if ("object" == typeof item) {
selector.append(self.getNotificationItem(item));
if (parseInt(item.readFlag, 10) < 2 && item.type != '1') {
list.push(item.id);
}
}
});
self.updateNotificationsDateTime();
} else {
if (more === undefined || more === false) {
selector.append(self.getEmptyNotifications());
}
}
return list;
}
UserNotifications.prototype._renderFoot = function (shouldLoadMore, paging) {
"use strict"
var loader = [
"<a href='javascript:void(0)' onclick='BidooCnf.instances.user.notifications.loadMore(" + paging + ");' class='load-more load-more-notif'>",
"Vedi altre",
"</a>"
].join("");
var footer = [
"<div class='whatelse nFoot text-center' id='more'>",
shouldLoadMore ? loader : "",
"</div>"
];
return footer.join("");
}
UserNotifications.prototype.loadMore = function (id) {
"use strict"
var self = this;
$.get(self.HTTP_ENDPOINT, {f: id, m: 5}, function (r) {
var selector = self.getCorrectNotifSelector();
var listNotif = selector.find("ul");
selector.find(".whatelse").remove();
if (Object.keys(r.elements).length > 0) {
var list = self._renderN(r.elements, true);
var welse = self._renderFoot(r.shexc, r.elements[Object.keys(r.elements).length - 1].id);
listNotif.append(welse);
if (listNotif.height() <= selector.find("#notifBoxContainer").height()) {
//selector.find("#more").find("a").click();
}
}
if (typeof list != "undefined" && list.length > 0) {
self.sendReadReq(list);
}
self.loadCustomScrollbar();
return false;
});
return false;
}
$("body").click(function (event) {
window.elementSelected = event.target.classList[0];
if ($('.bidooBell').hasClass('active')) {
$('.bidooBell').removeClass('active');
} else {
$('.bidooBell').addClass('active');
}
});
UserNotifications.prototype.loadNotification = function (forceFetchNotif) {
"use strict"
var self = this;
var isMobile = $(window).width() <= 991;
var selector = self.getCorrectNotifSelector();
self.topNotif = 0;
if (selector.is(":visible") && !forceFetchNotif) {
stopBodyScroll(false);
if (window.elementSelected == "bidooBell") {
selector.hide();
$("#tickNotif").hide();
}
if (isMobile) {
$('#notifBoxMobile').hide();
$('#menuModal #btn-1 span').addClass('fa-plus');
$('#menuModal #btn-1 span').removeClass('fa-minus');
$('#menuModal #submenu1').css('display', 'none');
}
self.totalScrollHeight = 0;
} else {
selector.empty().show();
if (isMobile)
self.hideModalHeaderNotifications(true);
self.composeNotificationsUI(isMobile, function (jqXHR, textStatus, errorThrown) {
var isError = jqXHR && textStatus && errorThrown;
if (!isError) {
self.loadCustomScrollbar();
$("#notifBox").show(); // [GR] ADD
if (isMobile) {
var titleSelector = selector.find(".nTitle");
var realHeightNotificationShade = (titleSelector.height() + parseInt(titleSelector.css("padding-top")));
var heightNotifDialog = ($(window).height() - realHeightNotificationShade);
selector.find("#notifBoxContainer").css("height", "auto");
selector.find("#more").find("a").click();
}
}
$("#tickNotif").show();
});
}
return false;
}
UserNotifications.prototype.getNotificationsStructure = function (mobile, isFirstLoadNotifications, isSettings) {
"use strict"
var arrow_left = [
'<a href="javascript:void();" onclick="BidooCnf.instances.user.notifications.back();" id="arrow_left">',
'<img src="images/arrow-left.png" width="12">',
'</a>'
].join("");
var structure = [
'<div class="nTitle">',
mobile || isSettings ? arrow_left : "",
'<p style="display: inline-block;">' + (isSettings ? "Impostazioni" : "Notifiche") + '</p>',
'<span class="sAudio glyphicon glyphicon-volume-up" onclick="BidooCnf.instances.user.notifications.toggleAudio();"></span>',
'<span class="sNotif glyphicon glyphicon-cog" onclick="BidooCnf.instances.user.notifications.toggleSettings();"></span>',
'</div>',
'<div id="notifBoxContainer">',
isFirstLoadNotifications ? "<img src='/images/loader_card.gif' class='loader-notifications'>" : "",
'<ul class="not"></ul>',
'</div>'
]
return structure.join("");
}
UserNotifications.prototype.composeNotificationsUI = function (mobile, callback) {
"use strict"
var self = this;
var selector = self.getCorrectNotifSelector();
selector.html(self.getNotificationsStructure(mobile, true));
$.get(self.HTTP_ENDPOINT, function (r) {
$(".bubble_desktop, .bubble_mobile, .toggle_bar_mobile").hide();
self.delivReadReq();
var mobile = $(window).width() <= 991;
var selectorList = selector.find("ul");
selector.find(".loader-notifications").remove();
if (r !== null) {
var list = self._renderN(r.elements);
if (Object.keys(r.elements).length > 0) {
var footer = self._renderFoot(r.shexc, r.elements[Object.keys(r.elements).length - 1].id);
selectorList.append(footer);
}
if (typeof list != "undefined" && list.length > 0) {
self.sendReadReq(list);
}
self.loadSettings();
} else {
selectorList.html(getSessionExpired());
}
callback();
}).fail(callback);
}
UserNotifications.prototype.sendReadReq = function (list) {
"use strict"
var self = this;
if (typeof list !== undefined && list.length > 0) {
$.get(self.HTTP_ENDPOINT, {_r: 1, l: list.join(',')});
}
}
UserNotifications.prototype.delivReadReq = function () {
"use strict"
$.get(this.HTTP_ENDPOINT, {_d: 1});
}
UserNotifications.prototype.getSettings = function () {
"use strict"
var html = [
'<div class="settingBox">',
'<form role="form" style="opacity: 1;">',
'<div class="title-settings"><b>Notifiche Email</b></div>',
'<div class="checkbox">',
'<label for="ticketMail">',
'<input type="checkbox" name="ticketMail" id="ticketMail">',
'<span class="notif-settings-label">Ricevi email per nuovi Ticket</span>',
'</label>',
'</div>',
'<div class="checkbox">',
'<label for="packageMail">',
'<input type="checkbox" name="packageMail" id="packageMail">',
'<span class="notif-settings-label">Ricevi Email per aggiornamenti spedizione</span>',
'</label>',
'</div>',
'<div class="checkbox">',
'<label for="creditMail">',
'<input type="checkbox" name="creditMail" id="creditMail">',
'<span class="notif-settings-label">Ricevi Email per accrediti di Puntate Gratis</span>',
'</label>',
'</div>',
'<a class="btn btn-block btn-primary" href="javascript:void(0);" onclick="BidooCnf.instances.user.notifications.saveSettings();"><b>Salva Impostazioni</b></a>',
'</form>',
'</div>'
];
return html.join("");
}
UserNotifications.prototype.showSettingNotification = function () {
"use strict"
var self = this;
var selector = self.getCorrectNotifSelector();
if (selector.length) {
self.notifBoxHtml = selector.html();
selector.html(self.getNotificationsStructure(true, false, true))
.find("#notifBoxContainer")
.append(self.getSettings());
self.loadSettings(true);
document.querySelector('#notifBoxMobile #notifBoxContainer .not').remove();
}
}
UserNotifications.prototype.back = function () {
"use strict"
var self = this;
var selector = self.getCorrectNotifSelector();
if ($(window).width() <= 991 && !selector.find(".settingBox").length) {
self.hideModalHeaderNotifications(false);
backMobile();
return;
}
selector.html(self.notifBoxHtml);
self.loadCustomScrollbar(true);
}
UserNotifications.prototype.toggleSettings = function () {
"use strict"
var self = this;
var selector = self.getCorrectNotifSelector();
if (!selector.is(":visible")) {
selector.show();
self.loadNotification();
} else {
self.showSettingNotification();
}
return true;
}
UserNotifications.prototype.saveSettings = function () {
"use strict"
var self = this;
var mail = +$("#ticketMail").is(":checked");
var pack = +$("#packageMail").is(":checked");
var accr = +$("#creditMail").is(":checked");
var data = [
'm', mail,
'p', pack,
'a', accr
];
$.get(self.HTTP_ENDPOINT, {_set: data.join("|")}, function () {
self.back();
});
}
UserNotifications.prototype.loadCustomScrollbar = function (forceReload) {
"use strict"
var self = this;
var notif_box_selector = self.getCorrectNotifSelector().find("#notifBoxContainer");
if ($(window).width() <= 991) {
notif_box_selector.off("scroll").scroll(function () {
if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) {
self.topNotif = $(this).scrollTop();
//notif_box_selector.find("#more").find("a").click();
}
});
notif_box_selector.scrollTop(self.topNotif);
} else if (forceReload || !notif_box_selector.hasClass("mCustomScrollbar")) {
if (forceReload) {
var list = notif_box_selector.find("ul").clone();
notif_box_selector.empty().append(list);
self.totalScrollHeight = 0;
}
notif_box_selector.mCustomScrollbar({
documentTouchScroll: true,
contentTouchScroll: 1,
callbacks: {
onTotalScroll: function () {
var more_notif_selector = notif_box_selector.find("#more");
if (more_notif_selector.is(":visible") && more_notif_selector.children().length) {
// more_notif_selector.find("a").click();
self.totalScrollHeight += 5 * 70;
}
},
onInit: function () {
if (self.totalScrollHeight != 0) {
notif_box_selector.mCustomScrollbar("scrollTo", self.totalScrollHeight, {
scrollInertia: 0
});
}
}
}
});
}
notif_box_selector
.off("mouseover")
.mouseover(true, stopBodyScroll)
.off("mouseout")
.mouseout(false, stopBodyScroll);
bindModalCall("#notifBoxContainer", true);
}
UserNotifications.prototype.getCorrectNotifSelector = function () {
"use strict"
var notifMobile = $("#notifBoxMobile");
return $(window).width() <= 991 ? notifMobile : $("#notifBox");
}
UserNotifications.prototype.hideModalHeaderNotifications = function (shouldHide) {
"use strict"
var self = this;
self.getCorrectNotifSelector().parent()
.parent()
.find(".modal-header")
.toggleClass("hidden", shouldHide);
}
UserNotifications.prototype.closeAll = function () {
"use strict"
var self = this;
var selector = self.getCorrectNotifSelector();
if (!selector.is(":visible"))
return;
if (selector.find(".settingBox").is(":visible"))
self.back();
self.back();
}
function bidping() {
"use strict"
if (BidooCnf.modules.exist(UserNotifications))
BidooCnf.instances.user.notifications.bidping(getBidsBonus());
}
$(document).ready(function () {
"use strict"
BidooCnf.modules.notifications = UserNotifications;
BidooCnf.instances.user.notifications = new UserNotifications();
});

View File

@@ -0,0 +1,56 @@
#onesignal-slidedown-container #onesignal-slidedown-dialog .slidedown-body-message{
font-size: 20px !important;
}
#onesignal-slidedown-container #onesignal-slidedown-dialog .primary.slidedown-button+.secondary.slidedown-button, #slidedown-footer #onesignal-slidedown-cancel-button {
color: #666666 !important;
}
#onesignal-slidedown-container #onesignal-slidedown-dialog .slidedown-button.primary, #slidedown-footer #onesignal-slidedown-allow-button {
background: #00CC66 !important;
}
@media(max-width:576px){
#onesignal-slidedown-container #onesignal-slidedown-dialog .primary.slidedown-button+.secondary.slidedown-button, #slidedown-footer #onesignal-slidedown-cancel-button {
padding: 10px;
}
#onesignal-slidedown-container #onesignal-slidedown-dialog .slidedown-button.primary, #slidedown-footer #onesignal-slidedown-allow-button {
padding: 10px;
}
#onesignal-slidedown-container #onesignal-slidedown-dialog .slidedown-body-message{
font-size: 16px !important;
}
#onesignal-slidedown-container #onesignal-slidedown-dialog .slidedown-body-icon{
width: 60px;
height: 70px;
}
}
#modalExplainForMac .modal-body{
padding: 30px 50px 0px;
}
#modalExplainForMac .logo{
width: 40px;
margin-top: -7px;
margin-left: 5px;
}
#modalExplainForMac .intestazione{
font-size: 18px;
font-weight: bold;
}
#modalExplainForMac p.sottotitolo{
font-size: 16px;
}
#modalExplainForMac ol{
padding-left: 15px;
line-height: 23px;
}
#modalExplainForMac .modal-footer{
border-top: none;
padding-top: 5px;
padding-right: 30px;
}
#modalExplainForMac .modal-footer .btn-custom{
background-color: #0c6;
color: #fff;
font-weight: bold;
font-size: 16px;
padding: 5px 30px;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#2196F3;}
</style>
<g>
<g>
<g>
<g>
<g>
<g>
<path class="st0" d="M13.38,38.44c-2.22,0-4.05,1.83-4.05,4.05c0,2.22,1.83,4.05,4.05,4.05c2.28,0,4.05-1.83,4.05-4.05
C17.44,40.27,15.6,38.44,13.38,38.44z"/>
<path class="st0" d="M43.7,38.44c-2.22,0-4.05,1.83-4.05,4.05c0,2.22,1.83,4.05,4.05,4.05c2.28,0,4.05-1.83,4.05-4.05
C47.76,40.27,45.92,38.44,43.7,38.44z"/>
<path class="st0" d="M44.54,34.05c0-0.5-0.39-0.83-0.83-0.83H21.44c-0.17,0-0.33,0.06-0.5,0.17l-3.55,2.67
c-0.39,0.22-0.44,0.78-0.17,1.11c0.17,0.22,0.44,0.33,0.67,0.33c0.17,0,0.33-0.06,0.5-0.11l3.33-2.5H43.7
C44.2,34.88,44.54,34.55,44.54,34.05z"/>
<path class="st0" d="M49.87,15.23c-0.11-0.17-0.33-0.28-0.56-0.33L9.88,8.95L9.61,7.79C9,4.73,6.44,3.45,0.83,3.45
C0.33,3.45,0,3.84,0,4.29c0,0.5,0.39,0.83,0.83,0.83c4.05,0,6.66,0.5,7.22,3.05L8.44,9.9c0,0.06,0,0.06,0,0.06l3.11,14.49
c0.39,2.44,2.5,4.28,4.94,4.28h26.32c2.44,0,4.5-1.72,4.89-4.28l2.28-8.55C50.03,15.67,49.98,15.39,49.87,15.23z"/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 80 50" style="enable-background:new 0 0 80 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#016FD0;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#016FD0;}
</style>
<g>
<path class="st0" d="M80,47.33c0,1.47-1.19,2.67-2.67,2.67H2.67C1.19,50,0,48.81,0,47.33V2.67C0,1.19,1.19,0,2.67,0h74.67
C78.81,0,80,1.19,80,2.67V47.33z"/>
<g>
<path class="st1" d="M19.5,37.15V26.63h11.14l1.2,1.56l1.23-1.56h40.44v9.8c0,0-1.06,0.72-2.28,0.73H48.84l-1.35-1.66v1.66h-4.42
v-2.83c0,0-0.6,0.4-1.91,0.4h-1.5v2.44h-6.69l-1.19-1.59l-1.21,1.59L19.5,37.15L19.5,37.15z"/>
<path class="st1" d="M6.49,18.7L9,12.85h4.34l1.43,3.28v-3.28h5.4l0.85,2.37l0.82-2.37h24.24v1.19c0,0,1.27-1.19,3.37-1.19
l7.87,0.03l1.4,3.24v-3.27h4.52l1.24,1.86v-1.86h4.56v10.52h-4.56L63.3,21.5v1.87h-6.64l-0.67-1.66h-1.79l-0.66,1.66h-4.5
c-1.8,0-2.95-1.17-2.95-1.17v1.17H39.3l-1.35-1.66v1.66H12.7l-0.67-1.66h-1.78l-0.66,1.66h-3.1V18.7L6.49,18.7z"/>
<path class="st2" d="M9.89,14.14L6.5,22.02h2.21l0.63-1.58h3.63l0.62,1.58h2.25l-3.39-7.88H9.89L9.89,14.14z M11.15,15.98
l1.11,2.76h-2.22L11.15,15.98L11.15,15.98z"/>
<polygon class="st2" points="16.08,22.02 16.08,14.14 19.21,14.15 21.04,19.23 22.82,14.14 25.93,14.14 25.93,22.02 23.96,22.02
23.96,16.21 21.87,22.02 20.14,22.02 18.05,16.21 18.05,22.02 16.08,22.02 "/>
<polygon class="st2" points="27.28,22.02 27.28,14.14 33.7,14.14 33.7,15.9 29.27,15.9 29.27,17.25 33.6,17.25 33.6,18.91
29.27,18.91 29.27,20.31 33.7,20.31 33.7,22.02 27.28,22.02 "/>
<path class="st2" d="M34.84,14.14v7.88h1.97v-2.8h0.83l2.36,2.8h2.41l-2.59-2.9c1.06-0.09,2.16-1,2.16-2.42
c0-1.66-1.3-2.56-2.75-2.56H34.84L34.84,14.14z M36.81,15.9h2.25c0.54,0,0.93,0.42,0.93,0.83c0,0.52-0.51,0.83-0.9,0.83h-2.28
L36.81,15.9L36.81,15.9L36.81,15.9z"/>
<polygon class="st2" points="44.79,22.02 42.78,22.02 42.78,14.14 44.79,14.14 44.79,22.02 "/>
<path class="st2" d="M49.56,22.02h-0.43c-2.1,0-3.38-1.65-3.38-3.91c0-2.31,1.26-3.97,3.91-3.97h2.18v1.87h-2.26
c-1.08,0-1.84,0.84-1.84,2.13c0,1.53,0.87,2.17,2.13,2.17h0.52L49.56,22.02L49.56,22.02z"/>
<path class="st2" d="M53.85,14.14l-3.39,7.88h2.21l0.63-1.58h3.63l0.62,1.58h2.25l-3.39-7.88H53.85L53.85,14.14z M55.1,15.98
l1.11,2.76h-2.22L55.1,15.98L55.1,15.98z"/>
<polygon class="st2" points="60.03,22.02 60.03,14.14 62.54,14.14 65.74,19.09 65.74,14.14 67.7,14.14 67.7,22.02 65.28,22.02
62,16.94 62,22.02 60.03,22.02 "/>
<polygon class="st2" points="20.85,35.81 20.85,27.93 27.28,27.93 27.28,29.69 22.84,29.69 22.84,31.04 27.17,31.04 27.17,32.7
22.84,32.7 22.84,34.1 27.28,34.1 27.28,35.81 20.85,35.81 "/>
<polygon class="st2" points="52.34,35.81 52.34,27.93 58.77,27.93 58.77,29.69 54.33,29.69 54.33,31.04 58.64,31.04 58.64,32.7
54.33,32.7 54.33,34.1 58.77,34.1 58.77,35.81 52.34,35.81 "/>
<polygon class="st2" points="27.52,35.81 30.65,31.92 27.45,27.93 29.93,27.93 31.84,30.39 33.75,27.93 36.14,27.93 32.98,31.87
36.11,35.81 33.63,35.81 31.78,33.38 29.97,35.81 27.52,35.81 "/>
<path class="st2" d="M36.35,27.93v7.88h2.02v-2.49h2.07c1.75,0,3.08-0.93,3.08-2.74c0-1.5-1.04-2.65-2.83-2.65H36.35L36.35,27.93z
M38.37,29.71h2.18c0.57,0,0.97,0.35,0.97,0.91c0,0.53-0.4,0.91-0.98,0.91h-2.18V29.71L38.37,29.71L38.37,29.71z"/>
<path class="st2" d="M44.38,27.93v7.88h1.97v-2.8h0.83l2.36,2.8h2.41l-2.59-2.9c1.06-0.09,2.16-1,2.16-2.42
c0-1.66-1.3-2.56-2.75-2.56L44.38,27.93L44.38,27.93L44.38,27.93z M46.35,29.69h2.25c0.54,0,0.93,0.42,0.93,0.83
c0,0.52-0.51,0.83-0.9,0.83h-2.28V29.69L46.35,29.69z"/>
<path class="st2" d="M59.68,35.81V34.1h3.94c0.58,0,0.84-0.32,0.84-0.66c0-0.33-0.25-0.67-0.84-0.67h-1.78
c-1.55,0-2.41-0.94-2.41-2.36c0-1.26,0.79-2.48,3.09-2.48h3.84l-0.83,1.77h-3.32c-0.63,0-0.83,0.33-0.83,0.65
c0,0.33,0.24,0.69,0.73,0.69h1.87c1.73,0,2.47,0.98,2.47,2.26c0,1.38-0.83,2.51-2.57,2.51L59.68,35.81L59.68,35.81z"/>
<path class="st2" d="M66.91,35.81V34.1h3.78c0.58,0,0.84-0.32,0.84-0.66c0-0.33-0.25-0.67-0.84-0.67h-1.61
c-1.55,0-2.41-0.94-2.41-2.36c0-1.26,0.79-2.48,3.09-2.48h3.76l-0.83,1.77h-3.24c-0.63,0-0.83,0.33-0.83,0.65
c0,0.33,0.24,0.69,0.73,0.69h1.7c1.73,0,2.48,0.98,2.48,2.26c0,1.38-0.83,2.51-2.57,2.51L66.91,35.81L66.91,35.81z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 80 50" style="enable-background:new 0 0 80 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F9F9F9;}
.st1{fill:#6C6BBD;}
.st2{fill:#D32011;}
.st3{fill:#0099DF;}
.st4{fill:#110F0D;}
</style>
<g>
<path class="st0" d="M76.56,50H3.44C1.55,50,0,48.45,0,46.56V3.44C0,1.55,1.55,0,3.44,0h73.12C78.45,0,80,1.55,80,3.44v43.12
C80,48.45,78.45,50,76.56,50z"/>
<g>
<polygon class="st1" points="46.47,32.85 33.53,32.85 33.53,9.6 46.47,9.6 "/>
<path class="st2" d="M34.35,21.22c0-4.72,2.21-8.92,5.65-11.63c-2.51-1.98-5.69-3.16-9.14-3.16c-8.17,0-14.79,6.62-14.79,14.79
s6.62,14.79,14.79,14.79c3.45,0,6.62-1.18,9.14-3.16C36.56,30.14,34.35,25.94,34.35,21.22"/>
<path class="st3" d="M63.92,21.22c0,8.17-6.62,14.79-14.79,14.79c-3.45,0-6.62-1.18-9.14-3.16c3.44-2.71,5.65-6.91,5.65-11.63
S43.44,12.3,40,9.6c2.52-1.98,5.69-3.16,9.14-3.16C57.3,6.43,63.92,13.05,63.92,21.22"/>
<path class="st4" d="M50.85,39.42c0.17,0,0.42,0.03,0.61,0.11l-0.26,0.8c-0.18-0.07-0.36-0.1-0.53-0.1
c-0.56,0-0.84,0.36-0.84,1.01v2.2h-0.85v-3.93h0.85v0.48C50.03,39.65,50.35,39.42,50.85,39.42L50.85,39.42z M47.69,40.3h-1.4v1.77
c0,0.39,0.14,0.66,0.57,0.66c0.22,0,0.5-0.07,0.75-0.22l0.25,0.73c-0.27,0.19-0.7,0.3-1.07,0.3c-1.01,0-1.36-0.54-1.36-1.45V40.3
h-0.8v-0.78h0.8v-1.19h0.86v1.19h1.4V40.3L47.69,40.3z M36.76,41.13c0.09-0.57,0.44-0.95,1.04-0.95c0.55,0,0.9,0.35,0.99,0.95
H36.76z M39.68,41.48c-0.01-1.22-0.76-2.06-1.87-2.06c-1.15,0-1.95,0.84-1.95,2.06c0,1.25,0.84,2.06,2.01,2.06
c0.59,0,1.13-0.15,1.61-0.55l-0.42-0.63c-0.33,0.26-0.75,0.41-1.14,0.41c-0.55,0-1.05-0.25-1.17-0.96h2.92
C39.67,41.7,39.68,41.59,39.68,41.48L39.68,41.48z M43.43,40.52c-0.24-0.15-0.72-0.34-1.22-0.34c-0.47,0-0.75,0.17-0.75,0.46
c0,0.26,0.3,0.34,0.66,0.39l0.4,0.06c0.85,0.12,1.37,0.49,1.37,1.18c0,0.75-0.66,1.28-1.79,1.28c-0.64,0-1.23-0.16-1.7-0.51
l0.4-0.67c0.29,0.22,0.72,0.41,1.31,0.41c0.58,0,0.89-0.17,0.89-0.48c0-0.22-0.22-0.35-0.69-0.41l-0.4-0.06
c-0.88-0.12-1.36-0.52-1.36-1.16c0-0.78,0.64-1.26,1.63-1.26c0.62,0,1.19,0.14,1.6,0.41L43.43,40.52L43.43,40.52z M53.97,40.23
c-0.18,0-0.34,0.03-0.49,0.09c-0.15,0.06-0.28,0.15-0.39,0.26c-0.11,0.11-0.2,0.24-0.26,0.4c-0.06,0.16-0.09,0.33-0.09,0.51
c0,0.19,0.03,0.36,0.09,0.51c0.06,0.16,0.15,0.29,0.26,0.4c0.11,0.11,0.24,0.2,0.39,0.26c0.15,0.06,0.31,0.09,0.49,0.09
c0.18,0,0.34-0.03,0.49-0.09c0.15-0.06,0.28-0.15,0.39-0.26c0.11-0.11,0.2-0.24,0.26-0.4c0.06-0.16,0.09-0.33,0.09-0.51
c0-0.19-0.03-0.36-0.09-0.51c-0.06-0.16-0.15-0.29-0.26-0.4c-0.11-0.11-0.24-0.2-0.39-0.26C54.31,40.26,54.14,40.23,53.97,40.23
L53.97,40.23z M53.97,39.42c0.3,0,0.59,0.05,0.85,0.16c0.26,0.11,0.48,0.25,0.67,0.44c0.19,0.19,0.34,0.4,0.44,0.66
c0.11,0.25,0.16,0.53,0.16,0.82c0,0.3-0.05,0.57-0.16,0.82c-0.11,0.25-0.25,0.47-0.44,0.66c-0.19,0.19-0.41,0.33-0.67,0.44
c-0.26,0.11-0.54,0.16-0.85,0.16s-0.59-0.05-0.85-0.16c-0.26-0.11-0.48-0.25-0.67-0.44c-0.19-0.19-0.34-0.41-0.44-0.66
c-0.11-0.25-0.16-0.53-0.16-0.82c0-0.3,0.05-0.57,0.16-0.82c0.11-0.25,0.25-0.47,0.44-0.66c0.19-0.19,0.41-0.33,0.67-0.44
C53.38,39.47,53.66,39.42,53.97,39.42L53.97,39.42z M31.77,41.48c0-0.69,0.45-1.26,1.19-1.26c0.71,0,1.18,0.54,1.18,1.26
c0,0.71-0.48,1.26-1.18,1.26C32.22,42.73,31.77,42.17,31.77,41.48L31.77,41.48z M34.95,41.48v-1.96h-0.85v0.48
c-0.27-0.35-0.68-0.58-1.24-0.58c-1.1,0-1.96,0.86-1.96,2.06c0,1.2,0.86,2.06,1.96,2.06c0.56,0,0.97-0.22,1.24-0.58v0.48h0.85
V41.48z M30.13,43.44v-2.46c0-0.93-0.59-1.55-1.54-1.56c-0.5-0.01-1.02,0.15-1.38,0.7c-0.27-0.44-0.7-0.7-1.3-0.7
c-0.42,0-0.83,0.12-1.15,0.58v-0.48h-0.85v3.93h0.86v-2.18c0-0.68,0.38-1.04,0.96-1.04c0.57,0,0.85,0.37,0.85,1.04v2.18h0.86
v-2.18c0-0.68,0.39-1.04,0.96-1.04c0.58,0,0.86,0.37,0.86,1.04v2.18H30.13L30.13,43.44z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 80 50" style="enable-background:new 0 0 80 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F9F9F9;}
.st1{fill:#FF5F00;}
.st2{fill:#EB001B;}
.st3{fill:#F79E1B;}
</style>
<g>
<path class="st0" d="M76.56,50H3.44C1.55,50,0,48.45,0,46.56V3.44C0,1.55,1.55,0,3.44,0h73.12C78.45,0,80,1.55,80,3.44v43.12
C80,48.45,78.45,50,76.56,50z"/>
<g>
<path d="M24.81,43.45v-2.46c0-0.94-0.57-1.56-1.56-1.56c-0.49,0-1.03,0.16-1.39,0.7c-0.29-0.45-0.7-0.7-1.31-0.7
c-0.41,0-0.82,0.12-1.15,0.57v-0.49h-0.86v3.94h0.86v-2.17c0-0.7,0.37-1.03,0.94-1.03s0.86,0.37,0.86,1.03v2.17h0.86v-2.17
c0-0.7,0.41-1.03,0.94-1.03c0.57,0,0.86,0.37,0.86,1.03v2.17H24.81L24.81,43.45z M37.56,39.52h-1.39v-1.19H35.3v1.19h-0.78v0.78
h0.78v1.8c0,0.9,0.37,1.44,1.35,1.44c0.37,0,0.78-0.12,1.07-0.29l-0.25-0.74c-0.25,0.16-0.53,0.21-0.74,0.21
c-0.41,0-0.57-0.25-0.57-0.66V40.3h1.39V39.52L37.56,39.52z M44.86,39.43c-0.49,0-0.82,0.25-1.03,0.57v-0.49h-0.86v3.94h0.86
v-2.21c0-0.66,0.29-1.03,0.82-1.03c0.16,0,0.37,0.04,0.53,0.08l0.25-0.82C45.27,39.43,45.02,39.43,44.86,39.43L44.86,39.43
L44.86,39.43z M33.83,39.84c-0.41-0.29-0.98-0.41-1.6-0.41c-0.98,0-1.64,0.49-1.64,1.27c0,0.66,0.49,1.03,1.35,1.15l0.41,0.04
c0.45,0.08,0.7,0.21,0.7,0.41c0,0.29-0.33,0.49-0.9,0.49c-0.57,0-1.03-0.21-1.31-0.41l-0.41,0.66c0.45,0.33,1.07,0.49,1.68,0.49
c1.15,0,1.8-0.53,1.8-1.27c0-0.7-0.53-1.07-1.35-1.19l-0.41-0.04c-0.37-0.04-0.66-0.12-0.66-0.37c0-0.29,0.29-0.45,0.74-0.45
c0.49,0,0.98,0.21,1.23,0.33L33.83,39.84L33.83,39.84z M56.71,39.43c-0.49,0-0.82,0.25-1.03,0.57v-0.49h-0.86v3.94h0.86v-2.21
c0-0.66,0.29-1.03,0.82-1.03c0.16,0,0.37,0.04,0.53,0.08l0.25-0.82C57.12,39.43,56.87,39.43,56.71,39.43L56.71,39.43L56.71,39.43z
M45.72,41.49c0,1.19,0.82,2.05,2.09,2.05c0.57,0,0.98-0.12,1.39-0.45l-0.41-0.7c-0.33,0.25-0.66,0.37-1.03,0.37
c-0.7,0-1.19-0.49-1.19-1.27c0-0.74,0.49-1.23,1.19-1.27c0.37,0,0.7,0.12,1.03,0.37l0.41-0.7c-0.41-0.33-0.82-0.45-1.39-0.45
C46.54,39.43,45.72,40.3,45.72,41.49L45.72,41.49L45.72,41.49z M53.68,41.49v-1.97h-0.86v0.49c-0.29-0.37-0.7-0.57-1.23-0.57
c-1.11,0-1.97,0.86-1.97,2.05c0,1.19,0.86,2.05,1.97,2.05c0.57,0,0.98-0.21,1.23-0.57v0.49h0.86V41.49z M50.52,41.49
c0-0.7,0.45-1.27,1.19-1.27c0.7,0,1.19,0.53,1.19,1.27c0,0.7-0.49,1.27-1.19,1.27C50.97,42.72,50.52,42.18,50.52,41.49
L50.52,41.49z M40.23,39.43c-1.15,0-1.97,0.82-1.97,2.05s0.82,2.05,2.01,2.05c0.57,0,1.15-0.16,1.6-0.53l-0.41-0.62
c-0.33,0.25-0.74,0.41-1.15,0.41c-0.53,0-1.07-0.25-1.19-0.94h2.91v-0.33C42.07,40.26,41.33,39.43,40.23,39.43L40.23,39.43
L40.23,39.43z M40.23,40.17c0.53,0,0.9,0.33,0.98,0.94h-2.05C39.24,40.58,39.61,40.17,40.23,40.17L40.23,40.17z M61.59,41.49
v-3.53h-0.86v2.05c-0.29-0.37-0.7-0.57-1.23-0.57c-1.11,0-1.97,0.86-1.97,2.05c0,1.19,0.86,2.05,1.97,2.05
c0.57,0,0.98-0.21,1.23-0.57v0.49h0.86V41.49z M58.43,41.49c0-0.7,0.45-1.27,1.19-1.27c0.7,0,1.19,0.53,1.19,1.27
c0,0.7-0.49,1.27-1.19,1.27C58.88,42.72,58.43,42.18,58.43,41.49L58.43,41.49z M29.65,41.49v-1.97h-0.86v0.49
c-0.29-0.37-0.7-0.57-1.23-0.57c-1.11,0-1.97,0.86-1.97,2.05c0,1.19,0.86,2.05,1.97,2.05c0.57,0,0.98-0.21,1.23-0.57v0.49h0.86
V41.49z M26.45,41.49c0-0.7,0.45-1.27,1.19-1.27c0.7,0,1.19,0.53,1.19,1.27c0,0.7-0.49,1.27-1.19,1.27
C26.9,42.72,26.45,42.18,26.45,41.49z"/>
<rect x="33.54" y="9.62" class="st1" width="12.92" height="23.21"/>
<path class="st2" d="M34.36,21.23c0-4.72,2.21-8.9,5.62-11.61c-2.5-1.97-5.66-3.16-9.1-3.16c-8.16,0-14.76,6.6-14.76,14.76
s6.6,14.76,14.76,14.76c3.44,0,6.6-1.19,9.1-3.16C36.58,30.17,34.36,25.94,34.36,21.23z"/>
<path class="st3" d="M63.89,21.23c0,8.16-6.6,14.76-14.76,14.76c-3.44,0-6.6-1.19-9.1-3.16c3.44-2.71,5.62-6.89,5.62-11.61
s-2.21-8.9-5.62-11.61c2.5-1.97,5.66-3.16,9.1-3.16C57.28,6.46,63.89,13.11,63.89,21.23z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 80 50" style="enable-background:new 0 0 80 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#009EE3;}
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#113984;}
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#172C70;}
</style>
<g>
<path class="st0" d="M76.56,50H3.44C1.55,50,0,48.45,0,46.56V3.44C0,1.55,1.55,0,3.44,0h73.12C78.45,0,80,1.55,80,3.44v43.12
C80,48.45,78.45,50,76.56,50z"/>
<g>
<path class="st1" d="M14.63,21.06h4.2c2.26,0,3.1,1.14,2.97,2.82c-0.22,2.77-1.89,4.3-4.11,4.3h-1.12c-0.3,0-0.51,0.2-0.59,0.75
L15.5,32.1c-0.03,0.21-0.14,0.33-0.3,0.34h-2.64c-0.25,0-0.34-0.19-0.27-0.6l1.61-10.18C13.96,21.25,14.19,21.06,14.63,21.06z"/>
<path class="st2" d="M32.87,20.87c1.42,0,2.72,0.77,2.55,2.68c-0.22,2.28-1.44,3.54-3.36,3.54h-1.68c-0.24,0-0.36,0.2-0.42,0.6
l-0.33,2.07c-0.05,0.31-0.21,0.47-0.45,0.47h-1.56c-0.25,0-0.34-0.16-0.28-0.52l1.29-8.29c0.06-0.41,0.22-0.56,0.5-0.56H32.87
L32.87,20.87z M30.32,25.31h1.27c0.8-0.03,1.33-0.58,1.38-1.58c0.03-0.61-0.38-1.05-1.04-1.05l-1.2,0.01L30.32,25.31L30.32,25.31z
M39.67,29.6c0.14-0.13,0.29-0.2,0.27-0.04l-0.05,0.38c-0.03,0.2,0.05,0.31,0.24,0.31h1.39c0.23,0,0.35-0.09,0.41-0.46l0.86-5.38
c0.04-0.27-0.02-0.4-0.23-0.4h-1.53c-0.14,0-0.2,0.08-0.24,0.29l-0.06,0.33c-0.03,0.17-0.11,0.2-0.18,0.03
c-0.26-0.61-0.92-0.89-1.84-0.87c-2.14,0.04-3.59,1.67-3.74,3.76c-0.12,1.61,1.04,2.88,2.56,2.88
C38.62,30.44,39.11,30.11,39.67,29.6L39.67,29.6L39.67,29.6z M38.5,28.77c-0.92,0-1.57-0.74-1.43-1.64s1-1.64,1.92-1.64
s1.57,0.74,1.43,1.64S39.42,28.77,38.5,28.77L38.5,28.77z M45.49,24h-1.41c-0.29,0-0.41,0.22-0.32,0.48l1.75,5.12l-1.72,2.44
c-0.14,0.2-0.03,0.39,0.17,0.39h1.58c0.19,0.02,0.37-0.07,0.47-0.23l5.38-7.72C51.57,24.25,51.5,24,51.22,24h-1.5
c-0.26,0-0.36,0.1-0.51,0.32l-2.24,3.25l-1-3.26C45.91,24.11,45.77,24,45.49,24L45.49,24z"/>
<path class="st1" d="M57.01,20.87c1.42,0,2.72,0.77,2.55,2.68c-0.22,2.28-1.44,3.54-3.36,3.54h-1.68c-0.24,0-0.36,0.2-0.42,0.6
l-0.33,2.07c-0.05,0.31-0.21,0.47-0.45,0.47h-1.56c-0.25,0-0.34-0.16-0.28-0.52l1.29-8.29c0.06-0.41,0.22-0.56,0.5-0.56
L57.01,20.87L57.01,20.87z M54.46,25.31h1.27c0.8-0.03,1.33-0.58,1.38-1.58c0.03-0.61-0.38-1.05-1.04-1.05l-1.2,0.01L54.46,25.31
L54.46,25.31z M63.81,29.6c0.14-0.13,0.29-0.2,0.27-0.04l-0.05,0.38c-0.03,0.2,0.05,0.31,0.24,0.31h1.39
c0.23,0,0.35-0.09,0.41-0.46l0.86-5.38c0.04-0.27-0.02-0.4-0.23-0.4h-1.53c-0.14,0-0.2,0.08-0.24,0.29l-0.06,0.33
c-0.03,0.17-0.11,0.2-0.18,0.03c-0.26-0.61-0.92-0.89-1.84-0.87c-2.14,0.04-3.59,1.67-3.74,3.76c-0.12,1.61,1.04,2.88,2.56,2.88
C62.76,30.44,63.26,30.11,63.81,29.6L63.81,29.6L63.81,29.6z M62.64,28.77c-0.92,0-1.57-0.74-1.43-1.64s1-1.64,1.92-1.64
c0.92,0,1.57,0.74,1.43,1.64S63.57,28.77,62.64,28.77L62.64,28.77z M69.05,30.26h-1.6c-0.1,0-0.19-0.08-0.2-0.18
c0-0.01,0-0.02,0-0.04l1.41-8.93c0.03-0.13,0.14-0.22,0.27-0.22h1.6c0.1,0,0.19,0.08,0.2,0.18c0,0.01,0,0.02,0,0.04l-1.41,8.93
C69.29,30.17,69.18,30.26,69.05,30.26L69.05,30.26z"/>
<path class="st2" d="M12,17.55h4.2c1.18,0,2.59,0.04,3.53,0.87c0.63,0.55,0.96,1.44,0.88,2.39c-0.26,3.21-2.18,5.01-4.75,5.01
h-2.07c-0.35,0-0.59,0.23-0.69,0.87l-0.58,3.69c-0.04,0.24-0.14,0.38-0.33,0.4H9.61c-0.29,0-0.39-0.22-0.31-0.7l1.86-11.82
C11.23,17.78,11.49,17.55,12,17.55z"/>
<path class="st3" d="M13.17,26.31l0.73-4.65c0.06-0.41,0.29-0.6,0.73-0.6h4.2c0.69,0,1.26,0.11,1.7,0.31
c-0.42,2.86-2.27,4.45-4.69,4.45h-2.07C13.49,25.81,13.29,25.95,13.17,26.31z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 80 50" style="enable-background:new 0 0 80 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FBE200;}
.st1{fill:#004A99;}
</style>
<g>
<g>
<path class="st0" d="M80,47.33c0,1.47-1.19,2.67-2.67,2.67H2.67C1.19,50,0,48.81,0,47.33V2.67C0,1.19,1.19,0,2.67,0h74.67
C78.81,0,80,1.19,80,2.67V47.33z"/>
</g>
<g>
<path class="st1" d="M14.1,20.45c-0.38,0-0.8,0.06-1.15,0.21c-0.09,0.03-0.21,0.06-0.3,0.12c-0.44,0.21-0.89,0.56-1.33,1
l0.12-1.21h-1.42C10,20.92,9.97,21.25,9.94,21.6c-0.06,0.35-0.12,0.68-0.18,1.03l-2.04,8.95h1.57l0.95-4.11
c0.3,0.41,0.65,0.74,1.03,0.95c0.41,0.21,0.86,0.33,1.42,0.33c0.09,0,0.18,0,0.27,0c0.59-0.06,1.12-0.21,1.6-0.5
c0.59-0.33,1.06-0.8,1.42-1.42c0.32-0.5,0.56-1.09,0.71-1.77c0.18-0.68,0.24-1.33,0.18-1.92c-0.09-0.83-0.35-1.51-0.86-1.98
C15.52,20.69,14.87,20.45,14.1,20.45z M15.14,24.73c-0.15,0.56-0.35,1.06-0.62,1.54c-0.27,0.47-0.59,0.83-0.97,1.06
c-0.18,0.09-0.38,0.18-0.59,0.24c-0.21,0.06-0.44,0.09-0.68,0.09c-0.47,0-0.86-0.15-1.15-0.41c-0.3-0.3-0.47-0.65-0.5-1.12
c-0.03-0.41,0-0.92,0.15-1.57c0.15-0.62,0.35-1.18,0.62-1.65c0.24-0.47,0.56-0.86,0.95-1.12c0.21-0.12,0.41-0.24,0.62-0.3
c0.18-0.06,0.38-0.09,0.59-0.09c0.47,0,0.89,0.15,1.21,0.47c0.3,0.33,0.47,0.74,0.53,1.27C15.32,23.64,15.29,24.17,15.14,24.73z"
/>
<path class="st1" d="M53.78,21.04c-0.44-0.44-1.06-0.68-1.83-0.68c-0.5,0-0.97,0.09-1.39,0.3c-0.06,0.03-0.12,0.06-0.21,0.09
c-0.35,0.21-0.68,0.47-1.03,0.8l0.06-0.97h-2.22c-0.06,0.53-0.21,1.36-0.44,2.45l-1.89,8.57h2.45l0.95-4.22
c0.24,0.44,0.56,0.8,0.97,1c0.32,0.18,0.71,0.3,1.15,0.33c0.09,0,0.21,0.03,0.3,0.03c1.24,0,2.25-0.56,2.98-1.68
c0.77-1.09,1.06-2.45,0.92-4.05C54.49,22.13,54.23,21.48,53.78,21.04z M52.04,24.53c-0.12,0.53-0.3,1.03-0.5,1.48
c-0.21,0.41-0.41,0.71-0.68,0.92c-0.15,0.12-0.32,0.21-0.5,0.24c-0.12,0.03-0.24,0.06-0.35,0.06c-0.41,0-0.74-0.15-0.97-0.41
c-0.27-0.27-0.38-0.65-0.44-1.15c-0.09-0.97,0.09-1.86,0.56-2.66c0.32-0.56,0.74-0.95,1.21-1.09c0.18-0.03,0.32-0.06,0.5-0.06
c0.38,0,0.68,0.12,0.92,0.35c0.21,0.21,0.35,0.53,0.38,0.97C52.19,23.55,52.16,24,52.04,24.53z"/>
<path class="st1" d="M61.91,20.95c-0.56-0.35-1.33-0.5-2.36-0.5c-0.33,0-0.65,0-0.95,0.06c-0.62,0.09-1.12,0.27-1.57,0.53
c-0.59,0.41-0.95,0.97-1,1.71h2.33c0.06-0.24,0.12-0.44,0.24-0.59c0.03-0.09,0.09-0.12,0.15-0.18c0.18-0.15,0.44-0.24,0.8-0.24
c0.3,0,0.53,0.06,0.68,0.18c0.18,0.12,0.27,0.3,0.3,0.53c0,0.12,0,0.24-0.03,0.38c0,0.18-0.06,0.38-0.12,0.68
c-0.09,0-0.18,0-0.27,0s-0.24,0-0.41,0c-0.38,0-0.77,0-1.09,0.03c-1.15,0.09-2.04,0.35-2.69,0.77c-0.83,0.53-1.21,1.3-1.12,2.3
c0.06,0.65,0.3,1.15,0.74,1.54c0.44,0.38,1,0.59,1.71,0.59c0.5,0,0.92-0.12,1.3-0.33l0.06-0.03c0.35-0.18,0.71-0.5,1-0.92
c0,0.21-0.03,0.38-0.03,0.59c0,0.21,0,0.38,0,0.56h2.25c0-0.35,0-0.68,0.03-1.03c0.06-0.35,0.09-0.68,0.18-1l0.62-2.72
c0.06-0.27,0.12-0.53,0.15-0.74c0.03-0.24,0.03-0.44,0-0.65C62.73,21.81,62.44,21.31,61.91,20.95z M59.31,26.6
c-0.24,0.27-0.47,0.44-0.71,0.56c-0.18,0.09-0.38,0.12-0.59,0.12c-0.27,0-0.47-0.06-0.62-0.21c-0.18-0.15-0.27-0.35-0.27-0.62
c-0.06-0.47,0.15-0.89,0.65-1.21c0.24-0.18,0.5-0.3,0.83-0.38c0.3-0.09,0.65-0.12,1.03-0.12c0.12,0,0.18,0,0.27,0
c0.06,0,0.12,0,0.18,0.03C59.96,25.5,59.69,26.12,59.31,26.6z"/>
<polygon class="st1" points="69.97,20.51 66.84,26.06 66.16,20.51 63.74,20.51 65.16,28.6 63.21,31.56 65.81,31.56 67.25,28.93
72.28,20.51 "/>
<path class="st1" d="M23.91,21.04c-0.56-0.44-1.3-0.68-2.25-0.68c-0.27,0-0.53,0-0.77,0.03c-0.47,0.06-0.95,0.18-1.33,0.33
c-0.59,0.27-1.06,0.62-1.45,1.12c-0.41,0.56-0.71,1.21-0.92,1.98c-0.24,0.77-0.3,1.48-0.24,2.19c0.06,0.86,0.38,1.54,0.97,2.01
c0.56,0.5,1.33,0.74,2.27,0.74c0.24,0,0.47-0.03,0.68-0.03c0.59-0.06,1.09-0.18,1.51-0.38c0.59-0.27,1.06-0.71,1.48-1.33
c0.35-0.53,0.62-1.18,0.8-1.92c0.21-0.74,0.27-1.45,0.21-2.1C24.8,22.16,24.5,21.51,23.91,21.04z M23.12,24.76
c-0.15,0.62-0.35,1.18-0.65,1.68c-0.27,0.44-0.56,0.77-0.92,0.97c-0.18,0.12-0.41,0.21-0.65,0.27c-0.18,0.03-0.35,0.06-0.56,0.06
c-0.53,0-0.95-0.15-1.27-0.44c-0.3-0.3-0.5-0.68-0.53-1.21c-0.03-0.47,0-1.03,0.15-1.68s0.35-1.18,0.62-1.62
c0.27-0.47,0.59-0.83,0.95-1.09c0.21-0.12,0.44-0.21,0.65-0.27s0.38-0.09,0.59-0.09c0.56,0,0.98,0.15,1.27,0.44
c0.3,0.27,0.47,0.71,0.53,1.33C23.32,23.58,23.26,24.11,23.12,24.76z"/>
<path class="st1" d="M31.06,20.78c-0.44-0.27-1.12-0.41-2.04-0.41c-1,0-1.8,0.24-2.39,0.68c-0.56,0.47-0.83,1.03-0.77,1.74
c0.03,0.41,0.21,0.8,0.56,1.09c0.32,0.33,0.92,0.68,1.74,1.06c0.65,0.3,1.06,0.53,1.27,0.71c0.21,0.18,0.32,0.38,0.32,0.62
c0.03,0.38-0.12,0.71-0.47,0.97c-0.35,0.24-0.83,0.35-1.45,0.35c-0.47,0-0.8-0.06-1.03-0.24c-0.24-0.15-0.35-0.38-0.38-0.71
c-0.03-0.09-0.03-0.18,0-0.3c0-0.12,0.03-0.24,0.09-0.38h-1.6c-0.03,0.18-0.06,0.35-0.09,0.5c-0.03,0.18-0.03,0.32,0,0.44
c0.06,0.59,0.32,1.03,0.83,1.36c0.53,0.3,1.21,0.47,2.1,0.47c1.12,0,2.04-0.27,2.72-0.77c0.71-0.5,1-1.15,0.95-1.89
c-0.03-0.44-0.21-0.83-0.47-1.12c-0.27-0.3-0.92-0.68-1.86-1.12c-0.68-0.32-1.12-0.56-1.3-0.74c-0.21-0.15-0.3-0.35-0.32-0.56
c-0.03-0.35,0.09-0.65,0.38-0.86c0.27-0.21,0.65-0.33,1.15-0.33c0.44,0,0.77,0.09,0.97,0.24c0.24,0.15,0.35,0.38,0.38,0.68
c0,0.06,0,0.15,0,0.21s0,0.15,0,0.24h1.45c0.03-0.21,0.03-0.35,0.03-0.44c0-0.12,0-0.21,0-0.3
C31.77,21.43,31.54,21.04,31.06,20.78z"/>
<path class="st1" d="M35.55,27.6c-0.35,0-0.62-0.06-0.77-0.18c-0.15-0.09-0.24-0.24-0.24-0.47c-0.03-0.09,0-0.21,0.03-0.38
c0-0.15,0.06-0.38,0.15-0.71l0.89-4.2h1.74l0.24-1.03h-1.74l0.47-2.22l-1.57,0.38l-0.41,1.83h-1.45l-0.27,1.03h1.48l-0.92,4.02
c-0.06,0.38-0.15,0.74-0.18,1.09c-0.03,0.33-0.06,0.59-0.03,0.74c0.03,0.44,0.18,0.77,0.47,0.95c0.27,0.21,0.71,0.3,1.3,0.3
c0.21,0,0.44-0.03,0.68-0.03c0.24-0.03,0.5-0.06,0.8-0.09l0.27-1.18c-0.15,0.03-0.32,0.09-0.47,0.09
C35.85,27.57,35.67,27.6,35.55,27.6z"/>
<path class="st1" d="M39.01,24.76h2.33h3.43c0.09-0.35,0.15-0.71,0.15-1.03c0.03-0.32,0.03-0.65,0-0.95
c-0.06-0.86-0.38-1.48-0.89-1.86c-0.53-0.38-1.33-0.59-2.36-0.59c-0.12,0-0.21,0-0.32,0c-0.62,0.06-1.15,0.18-1.62,0.44
c-0.56,0.27-1.03,0.71-1.39,1.24c-0.32,0.56-0.62,1.24-0.8,2.01c-0.21,0.8-0.27,1.51-0.21,2.13c0.06,0.83,0.38,1.48,0.92,1.92
c0.56,0.44,1.3,0.68,2.25,0.68c0.3,0,0.59-0.03,0.86-0.06c0.65-0.09,1.21-0.3,1.68-0.62c0.68-0.44,1.12-1.06,1.33-1.86h-1.74
c-0.15,0.44-0.41,0.8-0.77,1.03c-0.15,0.09-0.32,0.18-0.5,0.24c-0.21,0.09-0.44,0.12-0.68,0.12c-0.56,0-0.97-0.15-1.3-0.41
c-0.3-0.27-0.47-0.65-0.53-1.15c0-0.18,0-0.38,0.03-0.59C38.89,25.21,38.92,25,39.01,24.76z M40.13,21.9
c0.33-0.35,0.74-0.53,1.21-0.59c0.09,0,0.21-0.03,0.3-0.03c0.53,0,0.95,0.15,1.27,0.38c0.3,0.24,0.47,0.56,0.5,1
c0.03,0.12,0.03,0.24,0,0.38c0,0.15-0.03,0.35-0.06,0.62h-2.01h-2.07C39.42,22.87,39.72,22.28,40.13,21.9z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Livello_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 80 50" style="enable-background:new 0 0 80 50;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:#FFFFFF;}
</style>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="25" x2="80" y2="25">
<stop offset="0" style="stop-color:#222357"/>
<stop offset="1" style="stop-color:#254AA5"/>
</linearGradient>
<path class="st0" d="M76.56,50H3.44C1.55,50,0,48.45,0,46.56V3.44C0,1.55,1.55,0,3.44,0h73.12C78.45,0,80,1.55,80,3.44v43.12
C80,48.45,78.45,50,76.56,50z"/>
<g>
<path class="st1" d="M41.01,21.58c-0.03,2.65,2.36,4.12,4.16,5c1.85,0.9,2.47,1.48,2.47,2.28c-0.01,1.23-1.48,1.78-2.85,1.8
c-2.39,0.04-3.78-0.64-4.88-1.16l-0.86,4.02c1.11,0.51,3.16,0.96,5.28,0.97c4.99,0,8.26-2.46,8.27-6.28
c0.02-4.85-6.71-5.12-6.66-7.28c0.02-0.66,0.64-1.36,2.02-1.54c0.68-0.09,2.56-0.16,4.69,0.82l0.84-3.89
c-1.14-0.42-2.62-0.82-4.45-0.82C44.34,15.5,41.04,18,41.01,21.58 M61.51,15.84c-0.91,0-1.68,0.53-2.02,1.35l-7.13,17.02h4.99
l0.99-2.74h6.09l0.58,2.74h4.4l-3.84-18.37H61.51 M62.21,20.8l1.44,6.9h-3.94L62.21,20.8 M34.96,15.84l-3.93,18.37h4.75
l3.93-18.37H34.96 M27.93,15.84l-4.95,12.5l-2-10.63c-0.23-1.19-1.16-1.87-2.19-1.87h-8.09l-0.11,0.53
c1.66,0.36,3.55,0.94,4.69,1.56c0.7,0.38,0.9,0.71,1.13,1.61l3.79,14.66h5.02l7.7-18.37H27.93"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,180 @@
/* cyrillic-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* hebrew */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
/* math */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2) format('woff2');
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* hebrew */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2) format('woff2');
unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
/* math */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2) format('woff2');
unicode-range: U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333, U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1, U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071, U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F, U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B, U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF, U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11, U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2) format('woff2');
unicode-range: U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199, U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF, U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB, U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3, U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E, U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2, U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F, U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3, U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6, U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513, U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD, U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC, U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB, U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C, U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: 100%;
src: url(https://fonts.gstatic.com/s/opensans/v44/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@@ -0,0 +1,6 @@
/**
*
* detectIncognito v1.0.0 - (c) 2022 Joe Rutkowski <Joe@dreggle.com> (https://github.com/Joe12387/detectIncognito)
*
**/
var detectIncognito=function(){return new Promise(function(o,n){var e,t="Unknown";function i(e){o({isPrivate:e,browserName:t})}function r(e){return e===eval.toString().length}function a(){var e,o=window;void 0!==navigator.maxTouchPoints?void 0!==o.safari&&void 0===o.DeviceMotionEvent?(t="Safari for macOS",function(){try{window.safari.pushNotification.requestPermission("https://example.com","private",{},function(){})}catch(e){return i(!new RegExp("gesture").test(e))}i(!1)}()):void 0!==o.DeviceMotionEvent?(e=!(t="Safari for iOS"),(o=document.createElement("iframe")).style.display="none",document.body.appendChild(o),o.contentWindow.applicationCache.addEventListener("error",function(){return i(e=!0)}),setTimeout(function(){e||i(!1)},100)):n(new Error("detectIncognito Could not identify this version of Safari")):(t="Safari",function(){var e=window.openDatabase,o=window.localStorage;try{e(null,null,null,null)}catch(e){return i(!0)}try{o.setItem("test","1"),o.removeItem("test")}catch(e){return i(!0)}i(!1)}())}function c(){navigator.webkitTemporaryStorage.queryUsageAndQuota(function(e,o){i(o<(void 0!==(o=window).performance&&void 0!==o.performance.memory&&void 0!==o.performance.memory.jsHeapSizeLimit?performance.memory.jsHeapSizeLimit:1073741824))},function(e){n(new Error("detectIncognito somehow failed to query storage quota: "+e.message))})}function d(){void 0!==Promise&&void 0!==Promise.allSettled?c():(0,window.webkitRequestFileSystem)(0,1,function(){i(!1)},function(){i(!0)})}void 0!==(e=navigator.vendor)&&0===e.indexOf("Apple")&&r(37)?a():void 0!==(e=navigator.vendor)&&0===e.indexOf("Google")&&r(33)?(e=navigator.userAgent,t=e.match(/Chrome/)?void 0!==navigator.brave?"Brave":e.match(/Edg/)?"Edge":e.match(/OPR/)?"Opera":"Chrome":"Chromium",d()):void 0!==document.documentElement&&void 0!==document.documentElement.style.MozAppearance&&r(37)?(t="Firefox",i(void 0===navigator.serviceWorker)):void 0!==navigator.msSaveBlob&&r(39)?(t="Internet Explorer",i(void 0===window.indexedDB)):n(new Error("detectIncognito cannot determine the browser"))})};

View File

@@ -0,0 +1,107 @@
(function(g){var window=this;'use strict';var BaX=function(A){A.mutedAutoplay=!1;A.endSeconds=NaN;A.limitedPlaybackDurationInSeconds=NaN;g.SC(A)},fZK=function(){return{Z:"svg",
C:{height:"100%",version:"1.1",viewBox:"0 0 110 26",width:"100%"},B:[{Z:"path",bq:!0,j:"ytp-svg-fill",C:{d:"M 16.68,.99 C 13.55,1.03 7.02,1.16 4.99,1.68 c -1.49,.4 -2.59,1.6 -2.99,3 -0.69,2.7 -0.68,8.31 -0.68,8.31 0,0 -0.01,5.61 .68,8.31 .39,1.5 1.59,2.6 2.99,3 2.69,.7 13.40,.68 13.40,.68 0,0 10.70,.01 13.40,-0.68 1.5,-0.4 2.59,-1.6 2.99,-3 .69,-2.7 .68,-8.31 .68,-8.31 0,0 .11,-5.61 -0.68,-8.31 -0.4,-1.5 -1.59,-2.6 -2.99,-3 C 29.11,.98 18.40,.99 18.40,.99 c 0,0 -0.67,-0.01 -1.71,0 z m 72.21,.90 0,21.28 2.78,0 .31,-1.37 .09,0 c .3,.5 .71,.88 1.21,1.18 .5,.3 1.08,.40 1.68,.40 1.1,0 1.99,-0.49 2.49,-1.59 .5,-1.1 .81,-2.70 .81,-4.90 l 0,-2.40 c 0,-1.6 -0.11,-2.90 -0.31,-3.90 -0.2,-0.89 -0.5,-1.59 -1,-2.09 -0.5,-0.4 -1.10,-0.59 -1.90,-0.59 -0.59,0 -1.18,.19 -1.68,.49 -0.49,.3 -1.01,.80 -1.21,1.40 l 0,-7.90 -3.28,0 z m -49.99,.78 3.90,13.90 .18,6.71 3.31,0 0,-6.71 3.87,-13.90 -3.37,0 -1.40,6.31 c -0.4,1.89 -0.71,3.19 -0.81,3.99 l -0.09,0 c -0.2,-1.1 -0.51,-2.4 -0.81,-3.99 l -1.37,-6.31 -3.40,0 z m 29.59,0 0,2.71 3.40,0 0,17.90 3.28,0 0,-17.90 3.40,0 c 0,0 .00,-2.71 -0.09,-2.71 l -9.99,0 z m -53.49,5.12 8.90,5.18 -8.90,5.09 0,-10.28 z m 89.40,.09 c -1.7,0 -2.89,.59 -3.59,1.59 -0.69,.99 -0.99,2.60 -0.99,4.90 l 0,2.59 c 0,2.2 .30,3.90 .99,4.90 .7,1.1 1.8,1.59 3.5,1.59 1.4,0 2.38,-0.3 3.18,-1 .7,-0.7 1.09,-1.69 1.09,-3.09 l 0,-0.5 -2.90,-0.21 c 0,1 -0.08,1.6 -0.28,2 -0.1,.4 -0.5,.62 -1,.62 -0.3,0 -0.61,-0.11 -0.81,-0.31 -0.2,-0.3 -0.30,-0.59 -0.40,-1.09 -0.1,-0.5 -0.09,-1.21 -0.09,-2.21 l 0,-0.78 5.71,-0.09 0,-2.62 c 0,-1.6 -0.10,-2.78 -0.40,-3.68 -0.2,-0.89 -0.71,-1.59 -1.31,-1.99 -0.7,-0.4 -1.48,-0.59 -2.68,-0.59 z m -50.49,.09 c -1.09,0 -2.01,.18 -2.71,.68 -0.7,.4 -1.2,1.12 -1.49,2.12 -0.3,1 -0.5,2.27 -0.5,3.87 l 0,2.21 c 0,1.5 .10,2.78 .40,3.78 .2,.9 .70,1.62 1.40,2.12 .69,.5 1.71,.68 2.81,.78 1.19,0 2.08,-0.28 2.78,-0.68 .69,-0.4 1.09,-1.09 1.49,-2.09 .39,-1 .49,-2.30 .49,-3.90 l 0,-2.21 c 0,-1.6 -0.2,-2.87 -0.49,-3.87 -0.3,-0.89 -0.8,-1.62 -1.49,-2.12 -0.7,-0.5 -1.58,-0.68 -2.68,-0.68 z m 12.18,.09 0,11.90 c -0.1,.3 -0.29,.48 -0.59,.68 -0.2,.2 -0.51,.31 -0.81,.31 -0.3,0 -0.58,-0.10 -0.68,-0.40 -0.1,-0.3 -0.18,-0.70 -0.18,-1.40 l 0,-10.99 -3.40,0 0,11.21 c 0,1.4 .18,2.39 .68,3.09 .49,.7 1.21,1 2.21,1 1.4,0 2.48,-0.69 3.18,-2.09 l .09,0 .31,1.78 2.59,0 0,-14.99 c 0,0 -3.40,.00 -3.40,-0.09 z m 17.31,0 0,11.90 c -0.1,.3 -0.29,.48 -0.59,.68 -0.2,.2 -0.51,.31 -0.81,.31 -0.3,0 -0.58,-0.10 -0.68,-0.40 -0.1,-0.3 -0.21,-0.70 -0.21,-1.40 l 0,-10.99 -3.40,0 0,11.21 c 0,1.4 .21,2.39 .71,3.09 .5,.7 1.18,1 2.18,1 1.39,0 2.51,-0.69 3.21,-2.09 l .09,0 .28,1.78 2.62,0 0,-14.99 c 0,0 -3.40,.00 -3.40,-0.09 z m 20.90,2.09 c .4,0 .58,.11 .78,.31 .2,.3 .30,.59 .40,1.09 .1,.5 .09,1.21 .09,2.21 l 0,1.09 -2.5,0 0,-1.09 c 0,-1 -0.00,-1.71 .09,-2.21 0,-0.4 .11,-0.8 .31,-1 .2,-0.3 .51,-0.40 .81,-0.40 z m -50.49,.12 c .5,0 .8,.18 1,.68 .19,.5 .28,1.30 .28,2.40 l 0,4.68 c 0,1.1 -0.08,1.90 -0.28,2.40 -0.2,.5 -0.5,.68 -1,.68 -0.5,0 -0.79,-0.18 -0.99,-0.68 -0.2,-0.5 -0.31,-1.30 -0.31,-2.40 l 0,-4.68 c 0,-1.1 .11,-1.90 .31,-2.40 .2,-0.5 .49,-0.68 .99,-0.68 z m 39.68,.09 c .3,0 .61,.10 .81,.40 .2,.3 .27,.67 .37,1.37 .1,.6 .12,1.51 .12,2.71 l .09,1.90 c 0,1.1 .00,1.99 -0.09,2.59 -0.1,.6 -0.19,1.08 -0.49,1.28 -0.2,.3 -0.50,.40 -0.90,.40 -0.3,0 -0.51,-0.08 -0.81,-0.18 -0.2,-0.1 -0.39,-0.29 -0.59,-0.59 l 0,-8.5 c .1,-0.4 .29,-0.7 .59,-1 .3,-0.3 .60,-0.40 .90,-0.40 z"}}]}},
KqI=function(){return{Z:"svg",
C:{fill:"none",height:"100%",viewBox:"0 0 143 51",width:"100%"},B:[{Z:"path",C:{d:"M58.37 41.39H62.79V27.23C62.79 23.03 62.69 18.69 62.43 13.59H62.93L63.69 16.89L68.67 41.39H73.17L78.07 16.89L78.89 13.59H79.37C79.15 18.45 79.03 22.89 79.03 27.23V41.39H83.45V8.79H75.95L73.41 20.81C72.35 25.85 71.51 32.01 71.01 35.19H70.73C70.33 31.95 69.49 25.81 68.41 20.85L65.81 8.79H58.37V41.39Z",fill:"white"}},{Z:"path",C:{d:"M91.45 41.73C93.91 41.73 95.83 40.59 97.17 38.13H97.35L97.69 41.39H101.43V17.73H96.47V36.61C95.91 37.67 94.81 38.29 93.73 38.29C92.33 38.29 91.89 37.17 91.89 35.13V17.73H86.93V35.43C86.93 39.49 88.19 41.73 91.45 41.73Z",
fill:"white"}},{Z:"path",C:{d:"M110.79 41.89C115.15 41.89 117.75 39.83 117.75 35.65C117.75 31.79 115.93 30.39 111.85 27.47C109.67 25.91 108.39 25.09 108.39 22.95C108.39 21.47 109.27 20.61 110.89 20.61C112.69 20.61 113.33 21.81 113.33 25.29L117.45 25.07C117.77 19.57 115.71 17.23 110.97 17.23C106.57 17.23 104.17 19.27 104.17 23.45C104.17 27.25 105.97 28.83 108.93 31.03C111.89 33.23 113.55 34.53 113.55 36.23C113.55 37.75 112.51 38.61 111.01 38.61C109.13 38.61 108.11 36.97 108.29 34.41L104.21 34.49C103.51 39.25 105.89 41.89 110.79 41.89Z",
fill:"white"}},{Z:"path",C:{d:"M122.5 14.59C124.22 14.59 125.04 13.99 125.04 11.59C125.04 9.33 124.16 8.65 122.5 8.65C120.84 8.65 119.94 9.27 119.94 11.59C119.94 13.99 120.82 14.59 122.5 14.59ZM120.2 41.39H125V17.73H120.2V41.39Z",fill:"white"}},{Z:"path",C:{d:"M134.95 41.79C137.31 41.79 138.63 41.49 139.71 40.47C141.31 39.01 141.97 36.63 141.85 33.11L137.41 32.87C137.41 36.87 136.81 38.45 135.03 38.45C133.13 38.45 132.77 36.45 132.77 31.97V27.21C132.77 22.41 133.23 20.51 135.07 20.51C136.67 20.51 137.29 22.01 137.29 26.47L141.65 26.15C141.97 22.93 141.59 20.29 140.09 18.83C139.01 17.77 137.37 17.29 135.15 17.29C129.65 17.29 127.75 20.73 127.75 28.03V31.17C127.75 38.47 129.23 41.79 134.95 41.79Z",
fill:"white"}},{Z:"path",C:{"clip-rule":"evenodd",d:"M24.99 49C29.74 49.00 34.38 47.59 38.32 44.95C42.27 42.32 45.35 38.57 47.17 34.18C48.98 29.80 49.46 24.97 48.53 20.32C47.61 15.66 45.32 11.38 41.97 8.03C38.61 4.67 34.33 2.38 29.68 1.46C25.02 .53 20.20 1.01 15.81 2.82C11.43 4.64 7.68 7.71 5.04 11.66C2.40 15.61 1 20.25 1 25C0.99 28.15 1.61 31.27 2.82 34.18C4.03 37.09 5.79 39.74 8.02 41.97C10.25 44.19 12.89 45.96 15.81 47.17C18.72 48.37 21.84 49 24.99 49ZM24.99 12.36C27.49 12.36 29.94 13.10 32.02 14.48C34.10 15.87 35.72 17.84 36.68 20.15C37.64 22.46 37.89 25.01 37.41 27.46C36.92 29.91 35.72 32.17 33.95 33.94C32.18 35.70 29.93 36.91 27.48 37.40C25.02 37.89 22.48 37.64 20.17 36.68C17.86 35.72 15.88 34.10 14.50 32.02C13.11 29.94 12.37 27.50 12.37 25C12.37 21.65 13.70 18.44 16.07 16.07C18.43 13.70 21.64 12.37 24.99 12.36ZM24.99 10.43C22.11 10.43 19.29 11.28 16.89 12.88C14.50 14.48 12.63 16.76 11.53 19.42C10.42 22.09 10.13 25.02 10.70 27.85C11.26 30.67 12.65 33.27 14.69 35.31C16.73 37.35 19.32 38.73 22.15 39.30C24.98 39.86 27.91 39.57 30.57 38.46C33.23 37.36 35.51 35.49 37.11 33.09C38.71 30.70 39.57 27.88 39.56 25C39.56 23.08 39.19 21.19 38.46 19.42C37.72 17.65 36.65 16.04 35.30 14.69C33.94 13.34 32.34 12.27 30.57 11.53C28.80 10.80 26.90 10.43 24.99 10.43ZM32.63 24.99L20.36 32.09V17.91L32.63 24.99Z",
fill:"white","fill-rule":"evenodd"}}]}},V7t=function(A){g.q.call(this,{Z:"div",
j:"ytp-related-on-error-overlay"});var L=this;this.api=A;this.D=this.W=0;this.U=new g.dN(this);this.N=[];this.suggestionData=[];this.columns=this.containerWidth=0;this.title=new g.q({Z:"h2",j:"ytp-related-title",Ir:"{{title}}"});this.previous=new g.q({Z:"button",Rr:["ytp-button","ytp-previous"],C:{"aria-label":"Mostra i video consigliati in precedenza"},B:[g.jN()]});this.G=new g.x4(function(V){L.suggestions.element.scrollLeft=-V});
this.V=this.scrollPosition=0;this.T=!0;this.next=new g.q({Z:"button",Rr:["ytp-button","ytp-next"],C:{"aria-label":"Mostra altri video consigliati"},B:[g.gq()]});g.W(this,this.U);A=A.K();this.X=A.U;g.W(this,this.title);this.title.DM(this.element);this.suggestions=new g.q({Z:"div",j:"ytp-suggestions"});g.W(this,this.suggestions);this.suggestions.DM(this.element);g.W(this,this.previous);this.previous.DM(this.element);this.previous.listen("click",this.jX,this);g.W(this,this.G);for(var B={Kj:0};B.Kj<16;B=
{Kj:B.Kj},B.Kj++){var f=new g.q({Z:"a",j:"ytp-suggestion-link",C:{href:"{{link}}",target:A.yj,"aria-label":"{{aria_label}}"},B:[{Z:"div",j:"ytp-suggestion-image",B:[{Z:"div",C:{"data-is-live":"{{is_live}}"},j:"ytp-suggestion-duration",Ir:"{{duration}}"}]},{Z:"div",j:"ytp-suggestion-title",C:{title:"{{hover_title}}"},Ir:"{{title}}"},{Z:"div",j:"ytp-suggestion-author",Ir:"{{views_or_author}}"}]});g.W(this,f);f.DM(this.suggestions.element);var K=f.m4("ytp-suggestion-link");g.Kv(K,"transitionDelay",B.Kj/
20+"s");this.U.Y(K,"click",function(V){return function(J){var R=V.Kj,Z=L.suggestionData[R],N=Z.sessionData;g.MM(L.api.K())&&L.api.J("web_player_log_click_before_generating_ve_conversion_params")?(L.api.logClick(L.N[R].element),R=Z.Ej(),Z={},g.Mm(L.api,Z),R=g.ip(R,Z),g.wC(R,L.api,J)):g.If(J,L.api,L.X,N||void 0)&&L.api.Dl(Z.videoId,N,Z.playlistId)}}(B));
this.N.push(f)}g.W(this,this.next);this.next.DM(this.element);this.next.listen("click",this.TF,this);this.U.Y(this.api,"videodatachange",this.onVideoDataChange);this.resize(this.api.Pn().getPlayerSize());this.onVideoDataChange();this.show()},JdK=function(A,L){if(A.api.K().J("web_player_log_click_before_generating_ve_conversion_params"))for(var B=Math.floor(-A.scrollPosition/(A.V+A.W)),f=Math.min(B+A.columns,A.suggestionData.length)-1;B<=f;B++)A.api.logVisibility(A.N[B].element,L)},SGR=function(A){A.next.element.style.bottom=
A.D+"px";
A.previous.element.style.bottom=A.D+"px";var L=A.scrollPosition,B=A.containerWidth-A.suggestionData.length*(A.V+A.W);g.D1(A.element,"ytp-scroll-min",L>=0);g.D1(A.element,"ytp-scroll-max",L<=B)},RKd=function(A){for(var L=0;L<A.suggestionData.length;L++){var B=A.suggestionData[L],f=A.N[L],K=B.shortViewCount?B.shortViewCount:B.author,V=B.Ej(),J=A.api.K();
if(g.MM(J)&&!J.J("web_player_log_click_before_generating_ve_conversion_params")){var R={};g.jg(A.api,"addEmbedsConversionTrackingParams",[R]);V=g.ip(V,R)}f.element.style.display="";R=f.m4("ytp-suggestion-title");g.yd.test(B.title)?R.dir="rtl":g.r1I.test(B.title)&&(R.dir="ltr");R=f.m4("ytp-suggestion-author");g.yd.test(K)?R.dir="rtl":g.r1I.test(K)&&(R.dir="ltr");f.update({views_or_author:K,duration:B.isLivePlayback?"Dal vivo":B.lengthSeconds?g.hG(B.lengthSeconds):"",link:V,hover_title:B.title,title:B.title,
aria_label:B.ariaLabel||null,is_live:B.isLivePlayback});K=B.g1();f.m4("ytp-suggestion-image").style.backgroundImage=K?"url("+K+")":"";J.J("web_player_log_click_before_generating_ve_conversion_params")&&(A.api.createServerVe(f.element,f),(B=(B=B.sessionData)&&B.itct)&&A.api.setTrackingParams(f.element,B))}for(;L<A.N.length;L++)A.N[L].element.style.display="none";SGR(A)},zs=function(A){g.ig.call(this,A);
var L=this;this.N=null;var B=A.K(),f={target:B.yj},K=["ytp-small-redirect"];if(B.V)K.push("no-link");else{var V=g.wd(B);f.href=V;f["aria-label"]="Visita YouTube per cercare altri video"}var J=new g.q({Z:"a",Rr:K,C:f,B:[{Z:"svg",C:{fill:"#fff",height:"100%",viewBox:"0 0 24 24",width:"100%"},B:[{Z:"path",C:{d:"M0 0h24v24H0V0z",fill:"none"}},{Z:"path",C:{d:"M21.58 7.19c-.23-.86-.91-1.54-1.77-1.77C18.25 5 12 5 12 5s-6.25 0-7.81.42c-.86.23-1.54.91-1.77 1.77C2 8.75 2 12 2 12s0 3.25.42 4.81c.23.86.91 1.54 1.77 1.77C5.75 19 12 19 12 19s6.25 0 7.81-.42c.86-.23 1.54-.91 1.77-1.77C22 15.25 22 12 22 12s0-3.25-.42-4.81zM10 15V9l5.2 3-5.2 3z"}}]}]});
J.DM(this.element);A.createClientVe(J.element,this,178053);this.Y(J.element,"click",function(R){Zuf(L,R,J.element)});
g.W(this,J);B.V||B.disableOrganicUi||(this.N=new V7t(A),this.N.DM(this.element),g.W(this,this.N));this.Y(A,"videodatachange",function(){L.show()});
this.resize(this.api.Pn().getPlayerSize())},Zuf=function(A,L,B){L.preventDefault();
A.api.logClick(B);L=B.getAttribute("href");B={};g.jg(A.api,"addEmbedsConversionTrackingParams",[B]);L=g.mi(B)?L:g.ip(L,B);g.QR(window,L)},NaK=function(A,L){A.m4("ytp-error-content").style.paddingTop="0px";
var B=A.m4("ytp-error-content"),f=B.clientHeight;A.N&&A.N.resize(L,L.height-f);B.style.paddingTop=(L.height-(A.N?A.N.element.clientHeight:0))/2-f/2+"px"},d$t=function(A,L){var B=A.api.K(),f;
L.reason&&(Fqw(L.reason)?f=g.p1(L.reason):f=g.$S(g.wq(L.reason)),A.setContent(f,"content"));var K;L.subreason&&(Fqw(L.subreason)?K=g.p1(L.subreason):K=g.$S(g.wq(L.subreason)),A.setContent(K,"subreason"));if(L.proceedButton&&L.proceedButton.buttonRenderer){f=A.m4("ytp-error-content-wrap-subreason");L=L.proceedButton.buttonRenderer;var V=g.TO("A");if(L.text&&L.text.simpleText&&(K=L.text.simpleText,V.textContent=K,!D$I(f,K)&&(!B.V||B.embedsErrorLinks))){var J;B=(J=g.y(L==null?void 0:L.navigationEndpoint,
g.Mt))==null?void 0:J.url;var R;J=(R=g.y(L==null?void 0:L.navigationEndpoint,g.Mt))==null?void 0:R.target;B&&(V.setAttribute("href",B),A.api.createClientVe(V,A,178424),A.Y(V,"click",function(Z){Zuf(A,Z,V)}));
J&&V.setAttribute("target",J);R=g.TO("DIV");R.appendChild(V);f.appendChild(R)}}},Fqw=function(A){if(A.runs)for(var L=0;L<A.runs.length;L++)if(A.runs[L].navigationEndpoint)return!0;
return!1},D$I=function(A,L){A=g.jr("A",A);
for(var B=0;B<A.length;B++)if(A[B].textContent===L)return!0;return!1},IZK=function(A,L){g.q.call(this,{Z:"a",
Rr:["ytp-impression-link"],C:{target:"{{target}}",href:"{{url}}","aria-label":"Guarda su YouTube"},B:[{Z:"div",j:"ytp-impression-link-content",C:{"aria-hidden":"true"},B:[{Z:"div",j:"ytp-impression-link-text",Ir:"Guarda su"},{Z:"div",j:"ytp-impression-link-logo",Ir:"{{logoSvg}}"}]}]});this.api=A;this.N=L;this.updateValue("target",A.K().yj);this.Y(A,"videodatachange",this.onVideoDataChange);this.Y(this.api,"presentingplayerstatechange",this.qP);this.Y(this.api,"videoplayerreset",this.gH);this.Y(this.element,
"click",this.onClick);this.onVideoDataChange();this.gH()},wGR=function(A){var L={};
g.jg(A.api,"addEmbedsConversionTrackingParams",[L]);A=A.api.getVideoUrl();return A=g.ip(A,L)},u2=function(A){g.q.call(this,{Z:"div",
Rr:["ytp-mobile-a11y-hidden-seek-button"],B:[{Z:"button",Rr:["ytp-mobile-a11y-hidden-seek-button-rewind","ytp-button"],C:{"aria-label":"Indietro di 10 secondi","aria-hidden":"false"}},{Z:"button",Rr:["ytp-mobile-a11y-hidden-seek-button-forward","ytp-button"],C:{"aria-label":"Avanti veloce di 10 secondi","aria-hidden":"false"}}]});this.api=A;this.N=this.m4("ytp-mobile-a11y-hidden-seek-button-rewind");this.forwardButton=this.m4("ytp-mobile-a11y-hidden-seek-button-forward");this.api.createClientVe(this.N,
this,141902);this.api.createClientVe(this.forwardButton,this,141903);this.Y(this.api,"presentingplayerstatechange",this.qP);this.Y(this.N,"click",this.W);this.Y(this.forwardButton,"click",this.V);this.qP()},ae=function(A){g.q.call(this,{Z:"div",
j:"ytp-muted-autoplay-endscreen-overlay",B:[{Z:"div",j:"ytp-muted-autoplay-end-panel",B:[{Z:"button",Rr:["ytp-muted-autoplay-end-text","ytp-button"],Ir:"{{text}}"}]}]});this.api=A;this.U=this.m4("ytp-muted-autoplay-end-panel");this.W=!1;this.api.createClientVe(this.element,this,52428);this.Y(this.api,"presentingplayerstatechange",this.V);this.Y(A,"onMutedAutoplayStarts",this.onMutedAutoplayStarts);this.listen("click",this.onClick);this.hide()},AM=function(A){var L=A.K();
g.q.call(this,{Z:"a",Rr:["ytp-watermark","yt-uix-sessionlink"],C:{target:L.yj,href:"{{url}}","aria-label":g.B$("Guarda su $WEBSITE",{WEBSITE:g.BN(L)}),"data-sessionlink":"feature=player-watermark"},Ir:"{{logoSvg}}"});this.api=A;this.N=null;this.W=!1;this.state=A.getPlayerStateObject();this.Y(A,"videodatachange",this.onVideoDataChange);this.Y(A,"presentingplayerstatechange",this.onStateChange);this.Y(A,"appresize",this.Bz);this.onVideoDataChange();this.Y6(this.state);this.Bz(A.Pn().getPlayerSize())},
pGR=function(A){var L=A.api.getVideoData(),B=A.api.K().TZ&&!g.x(A.state,2)&&!A.api.getVideoData(1).OE;
L.mutedAutoplay||A.xP(B);A.api.logVisibility(A.element,B)},gb5=function(A){g.q.call(this,{Z:"div",
j:"ytp-muted-autoplay-overlay",B:[{Z:"div",j:"ytp-muted-autoplay-bottom-buttons",B:[{Z:"button",Rr:["ytp-muted-autoplay-equalizer","ytp-button"],C:{"aria-label":"Indicatore di riproduzione con audio disattivato"},B:[{Z:"div",Rr:["ytp-muted-autoplay-equalizer-icon"],B:[{Z:"svg",C:{height:"100%",version:"1.1",viewBox:"-4 -4 24 24",width:"100%"},B:[{Z:"g",C:{fill:"#fff"},B:[{Z:"rect",j:"ytp-equalizer-bar-left",C:{height:"9",width:"4",x:"1",y:"7"}},{Z:"rect",j:"ytp-equalizer-bar-middle",C:{height:"14",
width:"4",x:"6",y:"2"}},{Z:"rect",j:"ytp-equalizer-bar-right",C:{height:"12",width:"4",x:"11",y:"4"}}]}]}]}]}]}]});var L=this;this.api=A;this.bottomButtons=this.m4("ytp-muted-autoplay-bottom-buttons");this.V=new g.aa(this.YxT,4E3,this);this.W=!1;A.createClientVe(this.element,this,39306);this.Y(A,"presentingplayerstatechange",this.K1);this.Y(A,"onMutedAutoplayStarts",function(){ydK(L);L.K1();jg9(L);L.W=!1});
this.Y(A,"onAutoplayBlocked",this.onAutoplayBlocked);this.listen("click",this.onClick);this.Y(A,"onMutedAutoplayEnds",this.onMutedAutoplayEnds);this.hide();A.isMutedByEmbedsMutedAutoplay()&&(ydK(this),this.K1(),jg9(this));g.W(this,this.V)},jg9=function(A){A.bC&&A.N&&(A.N.show(),A.V.start())},ydK=function(A){A.watermark||(A.watermark=new AM(A.api),g.W(A,A.watermark),A.watermark.DM(A.bottomButtons,0),g.D1(A.watermark.element,"ytp-muted-autoplay-watermark",!0),A.N=new g.KL(A.watermark,0,!0,100),g.W(A,
A.N))},L7=function(A){g.q.call(this,{Z:"div",
j:"ytp-pause-overlay",C:{tabIndex:"-1"}});var L=this;this.api=A;this.V=new g.dN(this);this.fade=new g.KL(this,1E3,!1,100,function(){L.N.W=!1},function(){L.N.W=!0});
this.W=!1;this.expandButton=new g.q({Z:"button",Rr:["ytp-button","ytp-expand"],Ir:this.api.isEmbedsShortsMode()?"Altri Short":"Altri video"});A.K().controlsType==="0"&&g.R1(A.getRootNode(),"ytp-pause-overlay-controls-hidden");g.W(this,this.V);g.W(this,this.fade);var B=new g.q({Z:"button",Rr:["ytp-button","ytp-collapse"],C:{"aria-label":this.api.isEmbedsShortsMode()?"Nascondi la sezione Altri Short":"Nascondi Altri video"},B:[{Z:"div",j:"ytp-collapse-icon",B:[g.C1()]}]});g.W(this,B);B.DM(this.element);
B.listen("click",this.U,this);g.W(this,this.expandButton);this.expandButton.DM(this.element);this.expandButton.listen("click",this.D,this);this.N=new g.ep(A);g.W(this,this.N);this.N.W=!1;this.N.DM(this.element);this.api.isEmbedsShortsMode()?this.api.createClientVe(this.element,this,157212):this.api.createClientVe(this.element,this,172777);this.V.Y(this.api,"presentingplayerstatechange",this.zL);this.V.Y(this.api,"videodatachange",this.zL);this.hide()},on=function(A){g.q.call(this,{Z:"div",
Rr:["ytp-player-content","ytp-iv-player-content"],B:[{Z:"div",j:"ytp-countdown-timer",B:[{Z:"svg",C:{height:"100%",version:"1.1",viewBox:"0 0 72 72",width:"100%"},B:[{Z:"circle",j:"ytp-svg-countdown-timer-ring",C:{cx:"-36",cy:"36","fill-opacity":"0",r:"33.5",stroke:"#FFFFFF","stroke-dasharray":"211","stroke-dashoffset":"-211","stroke-width":"4",transform:"rotate(-90)"}},{Z:"circle",j:"ytp-svg-countdown-timer-background",C:{cx:"-36",cy:"36","fill-opacity":"0",r:"33.5",stroke:"#FFFFFF","stroke-opacity":"0.3",
"stroke-width":"4",transform:"rotate(-90)"}}]},{Z:"span",j:"ytp-countdown-timer-time",Ir:"{{duration}}"}]}]});this.api=A;this.T=this.m4("ytp-svg-countdown-timer-ring");this.N=null;this.U=this.V=0;this.W=!1;this.D=0;this.api.createClientVe(this.element,this,159628)},rdI=function(A){A.N||(A.V=5E3,A.U=(0,g.bc)(),A.N=new g.uN(function(){Gw5(A)},null),Gw5(A))},Gw5=function(A){if(!A.W){var L=Math.min((0,g.bc)()-A.U,A.V);
var B=A.V-L;L=A.V===0?0:Math.max(B/A.V,0);B=Math.round(B/1E3);A.T.setAttribute("stroke-dashoffset",""+-211*(L+1));A.updateValue("duration",B);L<=0&&A.N?A.stopTimer():A.N&&A.N.start()}},HuK=function(A){g.FB.call(this,A);
this.S=A;this.N=new g.dN(this);this.W=null;this.X=!1;this.countdownTimer=null;this.yj=!1;sgd(this);g.W(this,this.N);this.load()},buK=function(A){var L=g.wzy(A.S);
L!==A.yj&&(A.yj=L,A.D&&(A.D.dispose(),A.D=null),A.V&&(A.V.dispose(),A.V=null),A.U&&(A.U.dispose(),A.U=null),A.W&&(A.W.stop(),A.W.dispose(),A.W=null),L&&(L=g.Hh(A.S),A.S.isEmbedsShortsMode()&&(A.U=new g.q({Z:"div",j:"ytp-pause-overlay-backdrop",C:{tabIndex:"-1"}}),g.W(A,A.U),g.Wh(A.S,A.U.element,4),A.W=new g.KL(A.U,1E3,!1,100),g.W(A,A.W),A.U.hide()),A.D=new g.q({Z:"div",j:"ytp-pause-overlay-container",C:{tabIndex:"-1"}}),g.W(A,A.D),A.V=new L7(A.S,L),g.W(A,A.V),A.V.DM(A.D.element),g.Wh(A.S,A.D.element,
4),hKI(A,A.S.getPlayerStateObject())))},hKI=function(A,L){A.W&&(!g.x(L,4)&&!g.x(L,2)||g.x(L,1024)?A.W.hide():A.W.show())},sgd=function(A){var L=A.S;
A=!!L.isEmbedsShortsMode();g.D1(L.getRootNode(),"ytp-shorts-mode",A);if(L=L.getVideoData())L.g4=A},Bx=function(A,L){var B=A.S.K();
A={adSource:"EMBEDS_AD_SOURCE_YOUTUBE",breakType:A.S.getCurrentTime()===0?"EMBEDS_AD_BREAK_TYPE_PRE_ROLL":A.S.getPlayerState()===0?"EMBEDS_AD_BREAK_TYPE_POST_ROLL":"EMBEDS_AD_BREAK_TYPE_MID_ROLL",embedUrl:g.Zvk(A.S.K().loaderUrl),eventType:L,youtubeHost:g.tW(A.S.K().vI)||""};A.embeddedPlayerMode=B.wT;g.pE("embedsAdEvent",A)};
g.G(V7t,g.q);g.p=V7t.prototype;g.p.hide=function(){this.T=!0;g.q.prototype.hide.call(this);JdK(this,!1)};
g.p.show=function(){this.T=!1;g.q.prototype.show.call(this);JdK(this,!0)};
g.p.isHidden=function(){return this.T};
g.p.TF=function(){this.scrollTo(this.scrollPosition-this.containerWidth)};
g.p.jX=function(){this.scrollTo(this.scrollPosition+this.containerWidth)};
g.p.resize=function(A,L){var B=this.api.K(),f=16/9,K=A.width>=650,V=A.width<480||A.height<290,J=Math.min(this.suggestionData.length,this.N.length);if(Math.min(A.width,A.height)<=150||J===0||!B.k6)this.hide();else{var R;if(K){var Z=R=28;this.W=16}else this.W=Z=R=8;if(V){var N=6;K=14;var F=12;V=24;B=12}else N=8,K=18,F=16,V=36,B=16;A=A.width-(48+R+Z);R=Math.ceil(A/150);R=Math.min(3,R);Z=A/R-this.W;var D=Math.floor(Z/f);L&&D+100>L&&Z>50&&(D=Math.max(L,50/f),R=Math.ceil(A/(f*(D-100)+this.W)),Z=A/R-this.W,
D=Math.floor(Z/f));Z<50||g.ch(this.api)?this.hide():this.show();for(L=0;L<J;L++){f=this.N[L];var I=f.m4("ytp-suggestion-image");I.style.width=Z+"px";I.style.height=D+"px";f.m4("ytp-suggestion-title").style.width=Z+"px";f.m4("ytp-suggestion-author").style.width=Z+"px";f=f.m4("ytp-suggestion-duration");f.style.display=f&&Z<100?"none":""}J=K+N+F+4;this.D=J+B+(D-V)/2;this.suggestions.element.style.height=D+J+"px";this.V=Z;this.containerWidth=A;this.columns=R;this.scrollPosition=0;this.suggestions.element.scrollLeft=
-0;SGR(this)}};
g.p.onVideoDataChange=function(){var A=this.api.getVideoData(),L=this.api.K();this.X=A.OE?!1:L.U;A.suggestions?this.suggestionData=g.Mi(A.suggestions,function(B){return B&&!B.playlistId}):this.suggestionData.length=0;
RKd(this);A.OE?this.title.update({title:g.B$("Altri video da $DNI_RELATED_CHANNEL",{DNI_RELATED_CHANNEL:A.author})}):this.title.update({title:"Altri video su YouTube"})};
g.p.scrollTo=function(A){A=g.B4(A,this.containerWidth-this.suggestionData.length*(this.V+this.W),0);this.G.start(this.scrollPosition,A,1E3);this.scrollPosition=A;SGR(this);JdK(this,!0)};g.G(zs,g.ig);zs.prototype.show=function(){g.ig.prototype.show.call(this);NaK(this,this.api.Pn().getPlayerSize())};
zs.prototype.resize=function(A){g.ig.prototype.resize.call(this,A);this.N&&(NaK(this,A),g.D1(this.element,"related-on-error-overlay-visible",!this.N.isHidden()))};
zs.prototype.W=function(A){g.ig.prototype.W.call(this,A);var L=this.api.getVideoData();if(L.Kt||L.playerErrorMessageRenderer)(A=L.Kt)?d$t(this,A):L.playerErrorMessageRenderer&&d$t(this,L.playerErrorMessageRenderer);else{var B;A.Qr&&(L.ZE?Fqw(L.ZE)?B=g.p1(L.ZE):B=g.$S(g.wq(L.ZE)):B=g.$S(A.Qr),this.setContent(B,"subreason"))}};g.G(IZK,g.q);g.p=IZK.prototype;g.p.onVideoDataChange=function(){var A=this.api.getVideoData(),L=fZK(),B=96714;g.Nm(A)?(L=KqI(),B=216165,g.R1(this.element,"ytp-music-impression-link")):g.NH(this.element,"ytp-music-impression-link");this.updateValue("logoSvg",L);this.api.hasVe(this.element)&&this.api.destroyVe(this.element);this.api.createClientVe(this.element,this,B)};
g.p.qP=function(){this.api.getPlayerStateObject().isCued()||(this.hide(),this.api.logVisibility(this.element,!1))};
g.p.gH=function(){var A=this.api.getVideoData(),L=this.api.K(),B=this.api.getVideoData().OE,f=!L.k6,K=this.N.Gy(),V=L.V;L.TZ||K||B||f||V||this.api.isEmbedsShortsMode()||!A.videoId?(this.hide(),this.api.logVisibility(this.element,!1)):(A=wGR(this),this.updateValue("url",A),this.show())};
g.p.onClick=function(A){this.api.J("web_player_log_click_before_generating_ve_conversion_params")&&this.api.logClick(this.element);var L=wGR(this);g.wC(L,this.api,A);this.api.J("web_player_log_click_before_generating_ve_conversion_params")||this.api.logClick(this.element)};
g.p.show=function(){this.api.getPlayerStateObject().isCued()&&(g.q.prototype.show.call(this),this.api.hasVe(this.element)&&this.api.logVisibility(this.element,!0))};g.G(u2,g.q);u2.prototype.qP=function(){var A=this.api.getPlayerStateObject();!this.api.Kw()||g.x(A,2)&&g.Xr(this.api)||g.x(A,64)?(this.api.logVisibility(this.N,!1),this.api.logVisibility(this.forwardButton,!1),this.hide()):(this.show(),this.api.logVisibility(this.N,!0),this.api.logVisibility(this.forwardButton,!0))};
u2.prototype.W=function(){this.api.seekBy(-10*this.api.getPlaybackRate(),void 0,void 0,83);this.api.logClick(this.N)};
u2.prototype.V=function(){this.api.seekBy(10*this.api.getPlaybackRate(),void 0,void 0,82);this.api.logClick(this.forwardButton)};g.G(ae,g.q);
ae.prototype.V=function(){var A=this.api.getPlayerStateObject(),L=this.api.getVideoData();g.D1(this.element,"ytp-shorts-mode",this.api.isEmbedsShortsMode());!L.mutedAutoplay||L.limitedPlaybackDurationInSeconds===0&&L.endSeconds===0&&L.mutedAutoplayDurationMode===2||(g.x(A,2)&&!this.bC?(this.show(),this.N||(this.N=new g.Q2(this.api),g.W(this,this.N),this.N.DM(this.U,0),this.N.show()),A=this.api.getVideoData(),this.updateValue("text",A.Tz),g.D1(this.element,"ytp-muted-autoplay-show-end-panel",!0),this.api.logVisibility(this.element,
this.bC),this.api.Wo("onMutedAutoplayEnds")):this.hide())};
ae.prototype.onClick=function(){if(!this.W){this.N&&(this.N.l1(),this.N=null);g.D1(this.api.getRootNode(),"ytp-muted-autoplay",!1);var A=this.api.getVideoData(),L=this.api.getCurrentTime();BaX(A);this.api.loadVideoById(A.videoId,L);this.api.S9();this.api.logClick(this.element);this.hide();this.W=!0}};
ae.prototype.onMutedAutoplayStarts=function(){this.W=!1;this.N&&(this.N.l1(),this.N=null)};g.G(AM,g.q);g.p=AM.prototype;g.p.onStateChange=function(A){this.Y6(A.state)};
g.p.Y6=function(A){this.state!==A&&(this.state=A);pGR(this)};
g.p.onVideoDataChange=function(){var A=this.api.K();A.V&&g.R1(this.element,"ytp-no-hover");var L=this.api.getVideoData();L.videoId&&!A.V?(A=this.api.getVideoUrl(!0,!1,!1,!0),this.updateValue("url",A),this.N||(this.N=this.listen("click",this.onClick))):this.N&&(this.updateValue("url",null),this.J$(this.N),this.N=null);A=fZK();var B=76758;g.Nm(L)&&(A=KqI(),B=216164);this.updateValue("logoSvg",A);this.api.hasVe(this.element)&&this.api.destroyVe(this.element);this.api.createClientVe(this.element,this,
B);pGR(this)};
g.p.onClick=function(A){this.api.J("web_player_log_click_before_generating_ve_conversion_params")&&this.api.logClick(this.element);var L=this.api.getVideoUrl(!g.bV(A),!1,!0,!0);if(this.api.J("web_player_log_click_before_generating_ve_conversion_params")){var B={};g.jg(this.api,"addEmbedsConversionTrackingParams",[B]);L=g.ip(L,B)}g.wC(L,this.api,A);this.api.J("web_player_log_click_before_generating_ve_conversion_params")||this.api.logClick(this.element)};
g.p.Bz=function(A){if((A=A.width<480)&&!this.W||!A&&this.W){var L=new g.q(fZK()),B=this.m4("ytp-watermark");g.D1(B,"ytp-watermark-small",A);g.Ql(B);L.DM(B);this.W=A}};g.G(gb5,g.q);g.p=gb5.prototype;g.p.K1=function(){var A=this.api.getPlayerStateObject();!this.api.getVideoData().mutedAutoplay||g.x(A,2)?this.hide():this.bC||(g.q.prototype.show.call(this),this.api.logVisibility(this.element,this.bC))};
g.p.YxT=function(){this.N&&this.N.hide()};
g.p.onAutoplayBlocked=function(){this.hide();BaX(this.api.getVideoData())};
g.p.onClick=function(){if(!this.W){g.D1(this.api.getRootNode(),"ytp-muted-autoplay",!1);var A=this.api.getVideoData(),L=this.api.getCurrentTime();BaX(A);this.api.loadVideoById(A.videoId,L);this.api.S9();this.api.logClick(this.element);this.api.Wo("onMutedAutoplayEnds");this.W=!0}};
g.p.onMutedAutoplayEnds=function(){this.watermark&&(this.watermark.l1(),this.watermark=null)};g.G(L7,g.q);L7.prototype.hide=function(){g.NH(this.api.getRootNode(),"ytp-expand-pause-overlay");g.q.prototype.hide.call(this)};
L7.prototype.U=function(){this.W=!0;g.NH(this.api.getRootNode(),"ytp-expand-pause-overlay");this.api.isEmbedsShortsMode()&&this.api.logVisibility(this.element,!1);this.expandButton.focus()};
L7.prototype.D=function(){this.W=!1;g.R1(this.api.getRootNode(),"ytp-expand-pause-overlay");this.api.isEmbedsShortsMode()&&this.api.logVisibility(this.element,!0);this.focus()};
L7.prototype.zL=function(){var A=this.api.getPlayerStateObject();g.x(A,1)||g.x(A,16)||g.x(A,32)||(!g.x(A,4)||g.x(A,2)||g.x(A,1024)?(this.W||this.api.logVisibility(this.element,!1),this.fade.hide()):this.N.hasSuggestions()&&(this.W||(g.R1(this.api.getRootNode(),"ytp-expand-pause-overlay"),g.nY(this.N),this.N.show(),this.api.logVisibility(this.element,!0)),this.fade.show()))};g.G(on,g.q);on.prototype.show=function(){g.q.prototype.show.call(this);this.api.logVisibility(this.element,!0)};
on.prototype.stopTimer=function(){this.N&&(this.N.dispose(),this.N=null,this.W=!1)};
on.prototype.l1=function(){this.stopTimer();g.q.prototype.l1.call(this)};g.G(HuK,g.FB);g.p=HuK.prototype;g.p.Pg=function(){return!1};
g.p.create=function(){var A=this.S.K(),L=g.Hh(this.S),B,f=(B=this.S.getVideoData())==null?void 0:B.clientPlaybackNonce;f&&g.Qm({clientPlaybackNonce:f});A.sx&&!A.disableOrganicUi&&buK(this);var K;(K=A.getWebPlayerContextConfig())!=null&&K.embedsEnableEmc3ds||(this.G=new gb5(this.S),g.W(this,this.G),g.Wh(this.S,this.G.element,4),this.qp=new ae(this.S),g.W(this,this.qp),g.Wh(this.S,this.qp.element,4));A.TZ&&(this.watermark=new AM(this.S),g.W(this,this.watermark),g.Wh(this.S,this.watermark.element,8));
L&&!A.disableOrganicUi&&(this.T=new IZK(this.S,L),g.W(this,this.T),g.Wh(this.S,this.T.element,8),this.S.isMutedByEmbedsMutedAutoplay()&&(this.onMutedAutoplayStarts(),this.T.hide()));A.W&&!A.disableOrganicUi&&(this.Wn=new u2(this.S),g.W(this,this.Wn),g.Wh(this.S,this.Wn.element,4));this.N.Y(this.S,"appresize",this.Bz);this.N.Y(this.S,"presentingplayerstatechange",this.qP);this.N.Y(this.S,"videodatachange",this.onVideoDataChange);this.N.Y(this.S,"videoplayerreset",this.onReset);this.N.Y(this.S,"onMutedAutoplayStarts",
this.onMutedAutoplayStarts);this.N.Y(this.S,"onAdStart",this.onAdStart);this.N.Y(this.S,"onAdComplete",this.onAdComplete);this.N.Y(this.S,"onAdSkip",this.onAdSkip);this.N.Y(this.S,"onAdStateChange",this.onAdStateChange);if(this.X=g.IX(g.nM(A)))this.countdownTimer=new on(this.S),g.W(this,this.countdownTimer),g.Wh(this.S,this.countdownTimer.element,4),this.countdownTimer.hide(),this.N.Y(this.S,g.qR("embeds"),this.onCueRangeEnter),this.N.Y(this.S,g.PR("embeds"),this.onCueRangeExit);this.q8(this.S.getPlayerStateObject());
var V,J;((V=this.S.K().getWebPlayerContextConfig())==null?0:(J=V.embedsHostFlags)==null?0:J.allowOverridingVisitorDataPlayerVars)&&(A=g.A_("IDENTITY_MEMENTO"))&&this.S.X3("onMementoChange",A)};
g.p.onCueRangeEnter=function(A){A.getId()==="countdown timer"&&this.countdownTimer&&(this.countdownTimer.show(),rdI(this.countdownTimer))};
g.p.onCueRangeExit=function(A){A.getId()==="countdown timer"&&this.countdownTimer&&(this.countdownTimer.stopTimer(),this.countdownTimer.hide())};
g.p.Bz=function(){var A=this.S.Pn().getPlayerSize();this.Xb&&this.Xb.resize(A)};
g.p.onReset=function(){sgd(this)};
g.p.qP=function(A){this.q8(A.state)};
g.p.q8=function(A){g.x(A,128)?(this.Xb||(this.Xb=new zs(this.S),g.W(this,this.Xb),g.Wh(this.S,this.Xb.element,4)),this.Xb.W(A.nh),this.Xb.show(),g.R1(this.S.getRootNode(),"ytp-embed-error")):this.Xb&&(this.Xb.dispose(),this.Xb=null,g.NH(this.S.getRootNode(),"ytp-embed-error"));if(this.countdownTimer&&this.countdownTimer.N)if(g.x(A,64))this.countdownTimer.hide(),this.countdownTimer.stopTimer();else if(A.isPaused()){var L=this.countdownTimer;L.W||(L.W=!0,L.D=(0,g.bc)())}else A.isPlaying()&&this.countdownTimer.W&&
(L=this.countdownTimer,L.W&&(L.U+=(0,g.bc)()-L.D,L.W=!1,Gw5(L)));hKI(this,A)};
g.p.onMutedAutoplayStarts=function(){this.S.getVideoData().mutedAutoplay&&this.G&&g.D1(this.S.getRootNode(),"ytp-muted-autoplay",!0)};
g.p.onVideoDataChange=function(A,L){var B=this.PT!==L.videoId;A=!B&&A==="dataloaded";var f={isShortsModeEnabled:!!this.S.isEmbedsShortsMode()};g.pE("embedsVideoDataDidChange",{clientPlaybackNonce:L.clientPlaybackNonce,isReload:A,runtimeEnabledFeatures:f});B&&(this.PT=L.videoId,this.countdownTimer&&(this.countdownTimer.show(),this.countdownTimer.hide()),this.X&&(this.S.Jf("embeds"),L.isAd()||L.limitedPlaybackDurationInSeconds<5||g.ch(this.S)||(L=Math.max((L.startSeconds+L.limitedPlaybackDurationInSeconds-
5)*1E3,0),L=new g.WR(L,L+5E3,{id:"countdown timer",namespace:"embeds"}),this.S.dX([L]))),this.S.K().sx&&!this.S.K().disableOrganicUi&&(sgd(this),buK(this)));this.S.K().V&&this.V&&this.V.detach()};
g.p.onAdStart=function(){Bx(this,"EMBEDS_AD_EVENT_TYPE_AD_STARTED")};
g.p.onAdComplete=function(){Bx(this,"EMBEDS_AD_EVENT_TYPE_AD_COMPLETED")};
g.p.onAdSkip=function(){Bx(this,"EMBEDS_AD_EVENT_TYPE_AD_SKIPPED")};
g.p.onAdStateChange=function(A){A===2&&Bx(this,"EMBEDS_AD_EVENT_TYPE_AD_PAUSED")};g.Np("embed",HuK);})(_yt_player);

View File

@@ -0,0 +1 @@
/* PLEASE DO NOT COPY AND PASTE THIS CODE. */(function(){var w=window,C='___grecaptcha_cfg',cfg=w[C]=w[C]||{},N='grecaptcha';var E='enterprise',a=w[N]=w[N]||{},gr=a[E]=a[E]||{};gr.ready=gr.ready||function(f){(cfg['fns']=cfg['fns']||[]).push(f);};w['__recaptcha_api']='https://www.google.com/recaptcha/enterprise/';(cfg['enterprise']=cfg['enterprise']||[]).push(true);(cfg['enterprise2fa']=cfg['enterprise2fa']||[]).push(true);(cfg['render']=cfg['render']||[]).push('6LcjhUMpAAAAADxcuxrNs1Ou0iKbz2h3dn58Egnw');(cfg['clr']=cfg['clr']||[]).push('true');(cfg['anchor-ms']=cfg['anchor-ms']||[]).push(20000);(cfg['execute-ms']=cfg['execute-ms']||[]).push(15000);w['__google_recaptcha_client']=true;var d=document,po=d.createElement('script');po.type='text/javascript';po.async=true; po.charset='utf-8';var v=w.navigator,m=d.createElement('meta');m.httpEquiv='origin-trial';m.content='A7vZI3v+Gz7JfuRolKNM4Aff6zaGuT7X0mf3wtoZTnKv6497cVMnhy03KDqX7kBz/q/iidW7srW31oQbBt4VhgoAAACUeyJvcmlnaW4iOiJodHRwczovL3d3dy5nb29nbGUuY29tOjQ0MyIsImZlYXR1cmUiOiJEaXNhYmxlVGhpcmRQYXJ0eVN0b3JhZ2VQYXJ0aXRpb25pbmczIiwiZXhwaXJ5IjoxNzU3OTgwODAwLCJpc1N1YmRvbWFpbiI6dHJ1ZSwiaXNUaGlyZFBhcnR5Ijp0cnVlfQ==';if(v&&v.cookieDeprecationLabel){v.cookieDeprecationLabel.getValue().then(function(l){if(l!=='treatment_1.1'&&l!=='treatment_1.2'&&l!=='control_1.1'){d.head.prepend(m);}});}else{d.head.prepend(m);}po.src='https://www.gstatic.com/recaptcha/releases/TkacYOdEJbdB_JjX802TMer9/recaptcha__it.js';po.crossOrigin='anonymous';po.integrity='sha384-jBr1c0i/lBALGFjGRa0UkLw5oDOPevN9KOlmNFGKHe5+D+3OpoTeZdS00+BHr2oZ';var e=d.querySelector('script[nonce]'),n=e&&(e['nonce']||e.getAttribute('nonce'));if(n){po.setAttribute('nonce',n);}var s=d.getElementsByTagName('script')[0];s.parentNode.insertBefore(po, s);})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,124 @@
function setFavoriteHandler(){
"use strict"
var lockRequest = false;
$(".favorite").on({
click: function(e) {
var element = $(this);
e.preventDefault(e);
e.stopImmediatePropagation();
if(element.attr('disabled')) {
if(isMobileDevice()) {
element.tooltip('show');
setTimeout(function(){
element.tooltip('hide');
}, 3000);
}
return;
}
if (lockRequest) {
return;
}
lockRequest = true;
$.ajax({
url: 'favorite.php',
data: {
id: element.attr("data-id")
},
type: "GET"
}).success(function(data) {
lockRequest = false;
if (data.result) window.parent.updateFavoriteCounter(element);
}).fail(function(){
lockRequest = false;
});
}
});
}
function animateAddToFavorite(favoriteSelector){
"use strict"
//if(!$(".select-bids").length) return; // REM FOR TAG
if(!$("#CategoryMenu").length) return; // ADD FOR TAG
// var targetSelector = ".select-bids .bi-favorite"; // REM FOR TAG
var targetSelector = "#CategoryMenu .bi-favorite"; // ADD FOR TAG
var body = $("body");
var preferredPositionTab = $(targetSelector).offset();
var categoryMenuPosition = $("#CategoryMenu").offset(); // ADD FOR TAG
if (preferredPositionTab.left < categoryMenuPosition.left) { // ADD FOR TAG
preferredPositionTab.left = categoryMenuPosition.left -16;
}
var cloneFavorite = favoriteSelector
.clone()
.addClass("bi-clone")
.addClass("fixed-zindex-high");
cloneFavorite = body.append(cloneFavorite)
.find(".bi-clone");
var favoritePosition = favoriteSelector.offset();
cloneFavorite.css({
"position": "absolute",
"left": favoritePosition.left,
"top": favoritePosition.top
});
cloneFavorite
.animate({
left: preferredPositionTab.left+"px",
top: preferredPositionTab.top+"px"
},600,function(){
cloneFavorite.remove();
});
}
$(function() {
"use strict"
window.updateFavoriteCounter = function(element) {
"use strict"
var id = element.data('id');
var preferredCount = $('.preferredCount');
var count = parseInt(preferredCount.eq(0).text());
if(element.length > 1) return;
element.toggleClass("active");
var hasElementActive = element.hasClass("active");
if (hasElementActive) {
count += 1;
animateAddToFavorite(element);
} else {
count = count < 0 ? 0 : --count;
}
var preferredCount = $('.preferredCount').text(count);
preferredCount.parent().toggleClass("active", count > 0);
setFavoriteTabTooltipVisibility(0 == count);
var asta = $("#divAsta" + id);
var data_favorite = parseInt(asta.attr('data-favorited'));
var des_text = (hasElementActive ? "Rimuovi quest\'asta dalle tue preferite" : "Metti quest\'asta tra le tue preferite"); // data_favorite -> hasElementActive
asta.attr('data-favorited', !data_favorite | 0)
if($("#modal").is(":visible")){
asta
.find(".favorite")
.toggleClass("active");
}
var id_product = getUrlParam("a").split("_").reverse()[0];
if (id_product > 0) {
element.attr('title', des_text);
} else {
element.attr('data-original-title', des_text);
}
//$('.auction-[data-favorited=0]').toggleClass('hide', !hasElementActive && bidSelected == 2); // REMOVED for bidSelect not defined
}
//this is the js that is working for favorites bids
setFavoriteHandler();
});

Some files were not shown because too many files have changed in this diff Show More