Files
Mimante/Mimante/Controls/BrowserControl.xaml
T
Alby96 7ca504a70a Add utility classes for theme management, waiting, watched products, and notifications
- Implement ThemeManager for dynamic light/dark theme switching in the application.
- Create Wait class for cancellable delays without exceptions for smoother user experience.
- Introduce WatchedProductsStore to manage and persist watched products in JSON format.
- Add WindowsNotifier for system notifications to inform users of important events.
- Develop ProductViewModel to encapsulate product data and manage UI interactions effectively.
2026-08-04 21:49:53 +02:00

320 lines
20 KiB
XML

<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="{DynamicResource Brush.Bg}">
<UserControl.Resources>
<Style x:Key="Glyph" TargetType="TextBlock">
<Setter Property="FontFamily" Value="Segoe MDL2 Assets"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
<!-- Scheda di una singola asta del catalogo -->
<DataTemplate x:Key="AuctionCardTemplate">
<Border Style="{StaticResource AuctionCard}" Width="250">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Immagine prodotto: arriva dalla rete, quindi puo' mancare -->
<Border Grid.Row="0" Height="110" CornerRadius="8"
Background="{DynamicResource Brush.SurfaceAlt}" Margin="0,0,0,8">
<Image Source="{Binding ImageUrl}" Stretch="Uniform" Margin="6"
RenderOptions.BitmapScalingMode="HighQuality"/>
</Border>
<TextBlock Grid.Row="1" Text="{Binding Name}" ToolTip="{Binding Name}"
FontWeight="SemiBold" TextTrimming="CharacterEllipsis"
MaxHeight="34" TextWrapping="Wrap"
Foreground="{DynamicResource Brush.Text}" Margin="0,0,0,6"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,0,0,6">
<TextBlock Text="{Binding PriceDisplay}" FontWeight="Bold"
Foreground="{DynamicResource Brush.Accent}" Margin="0,0,10,0"/>
<TextBlock Text="{Binding TimerDisplay}" Margin="0,0,10,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Brush.TextMuted}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding TimerUrgency}" Value="warn">
<Setter Property="Foreground" Value="{DynamicResource Brush.Warning}"/>
</DataTrigger>
<DataTrigger Binding="{Binding TimerUrgency}" Value="danger">
<Setter Property="Foreground" Value="{DynamicResource Brush.Danger}"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding BuyNowDisplay}"
FontSize="{StaticResource Font.Size.Sm}"
Foreground="{DynamicResource Brush.TextFaint}"
ToolTip="Valore del prodotto (Compra Subito)"/>
</StackPanel>
<Grid Grid.Row="3">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{Binding LastBidderDisplay}"
FontSize="{StaticResource Font.Size.Sm}"
Foreground="{DynamicResource Brush.TextMuted}"
TextTrimming="CharacterEllipsis" MaxWidth="90"/>
<!-- Solo l'icona della mano: la parola "manuale" mangiava spazio
al nome dell'ultimo puntatore, che è il dato che si legge
davvero. Il significato resta nel suggerimento. -->
<Border Background="{DynamicResource Brush.WarningSubtle}" CornerRadius="5"
Padding="4,1" Margin="6,0,0,0"
Visibility="{Binding ManualBadgeVisibility}"
ToolTip="Asta solo manuale: non accetta puntate automatiche">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE815;" FontSize="10"
Foreground="{DynamicResource Brush.Warning}"/>
</Border>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<!-- Segui il prodotto: le aste future dello stesso articolo
entreranno nel monitor da sole. -->
<Button Style="{StaticResource MiniIconButton}"
ToolTip="{Binding WatchTooltip}"
Command="{Binding DataContext.CatalogWatchCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="{Binding WatchGlyph}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Brush.TextFaint}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsWatched}" Value="True">
<Setter Property="Foreground" Value="{DynamicResource Brush.Gold}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<!-- Mette il prodotto nella scheda Prodotti e ci porta sopra:
serve a dargli limiti propri anche senza seguirlo. -->
<Button Style="{StaticResource MiniIconButton}"
ToolTip="{Binding ConfigureTooltip}"
Command="{Binding DataContext.CatalogConfigureCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE713;">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Brush.TextFaint}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsListed}" Value="True">
<Setter Property="Foreground" Value="{DynamicResource Brush.Accent}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Button>
<Button Style="{StaticResource MiniIconButton}"
ToolTip="Apri su Bidoo"
Command="{Binding DataContext.CatalogOpenCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE8A7;"/>
</Button>
<Button Style="{StaticResource MiniIconButton}"
Foreground="{DynamicResource Brush.Accent}"
ToolTip="Aggiungi al monitor"
Command="{Binding DataContext.CatalogAddCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}">
<TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE710;"/>
</Button>
</StackPanel>
</Grid>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- ═══ Barra strumenti ═══ -->
<Border Grid.Row="0" Background="{DynamicResource Brush.Surface}" Padding="10,7"
BorderBrush="{DynamicResource Brush.Border}" BorderThickness="0,0,0,1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Catalogo e Browser ora sono due schede separate nella barra laterale
("Cerca" e "Browser"): l'interruttore interno resta solo come stato
pilotato da fuori, non più visibile all'utente. -->
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center"
Visibility="Collapsed">
<RadioButton x:Name="ModeCatalogRadio" Style="{StaticResource SegmentedButton}"
GroupName="ExploreMode" IsChecked="True" Content="Catalogo"
Checked="ModeCatalogRadio_Checked"
ToolTip="Griglia delle aste: veloce, senza caricare pagine"/>
<RadioButton x:Name="ModeBrowserRadio" Style="{StaticResource SegmentedButton}"
GroupName="ExploreMode" Content="Browser"
Checked="ModeBrowserRadio_Checked"
ToolTip="Browser Bidoo integrato: serve per il login (il cookie viene importato da solo)"/>
<Border Width="1" Background="{DynamicResource Brush.Border}" Margin="8,4"/>
</StackPanel>
<StackPanel Grid.Column="1" x:Name="CatalogToolbarLeft" Orientation="Horizontal"
VerticalAlignment="Center">
<Button x:Name="CatalogRefreshButton" Style="{StaticResource IconButton}"
ToolTip="Ricarica categorie e prezzi" Click="CatalogRefreshButton_Click">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE72C;"/>
</Button>
<CheckBox x:Name="CatalogAutoRefresh" Content="Prezzi in tempo reale"
Margin="10,0,0,0" VerticalAlignment="Center"
Checked="CatalogAutoRefresh_Changed" Unchecked="CatalogAutoRefresh_Changed"
ToolTip="Aggiorna prezzi e timer sul posto. Spento di default: acceso, i valori cambiano mentre stai leggendo."/>
<CheckBox x:Name="CatalogHideManual" Content="Nascondi aste manuali"
Margin="14,0,0,0" VerticalAlignment="Center"
Checked="CatalogFilterChanged" Unchecked="CatalogFilterChanged"
ToolTip="Le aste manuali non accettano puntate automatiche"/>
</StackPanel>
<!-- Barra indirizzi del browser: occupa lo stesso posto dei filtri -->
<Border Grid.Column="1" Grid.ColumnSpan="2" x:Name="BrowserToolbar"
Visibility="Collapsed" Margin="0,0,10,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center">
<Button x:Name="BrowserBackButton" Style="{StaticResource IconButton}"
ToolTip="Indietro" Click="BrowserBackButton_Click">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE72B;"/>
</Button>
<Button x:Name="BrowserForwardButton" Style="{StaticResource IconButton}"
ToolTip="Avanti" Click="BrowserForwardButton_Click">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE72A;"/>
</Button>
<Button x:Name="BrowserRefreshButton" Style="{StaticResource IconButton}"
ToolTip="Ricarica" Click="BrowserRefreshButton_Click">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE72C;"/>
</Button>
<Button x:Name="BrowserHomeButton" Style="{StaticResource IconButton}"
ToolTip="Homepage Bidoo" Click="BrowserHomeButton_Click">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE80F;"/>
</Button>
</StackPanel>
<Border Grid.Column="1" Background="{DynamicResource Brush.Bg}"
BorderBrush="{DynamicResource Brush.Border}" BorderThickness="1"
CornerRadius="8" Margin="8,0,0,0">
<TextBox x:Name="BrowserAddress" VerticalAlignment="Center"
BorderThickness="0" Background="Transparent"
Foreground="{DynamicResource Brush.Text}" Padding="10,0"
IsReadOnly="True" Cursor="Arrow"
ToolTip="Indirizzo della pagina corrente"/>
</Border>
</Grid>
</Border>
<!-- Campo di ricerca con suggerimento: senza, un riquadro vuoto in barra
non si capisce a cosa serva. -->
<Grid Grid.Column="2" x:Name="CatalogSearchHost" Margin="16,0,10,0"
Width="240" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBox x:Name="CatalogSearchBox"
TextChanged="CatalogSearchBox_TextChanged"
ToolTip="Filtra per nome prodotto"/>
<TextBlock x:Name="CatalogSearchHint" Text="Filtra per nome…"
IsHitTestVisible="False" Margin="10,0,0,0"
VerticalAlignment="Center"
Foreground="{DynamicResource Brush.TextFaint}"/>
</Grid>
<StackPanel Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Center">
<Border Style="{StaticResource Pill}">
<TextBlock x:Name="CatalogCountText" Text="0 aste"
FontSize="{StaticResource Font.Size.Sm}"
Foreground="{DynamicResource Brush.TextMuted}"/>
</Border>
<Button x:Name="BrowserAddAuctionButton" Style="{StaticResource IconButton}"
Foreground="{DynamicResource Brush.Accent}" Visibility="Collapsed"
ToolTip="Aggiungi al monitor l'asta aperta nel browser"
Click="BrowserAddAuctionButton_Click">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE710;"/>
</Button>
</StackPanel>
</Grid>
</Border>
<!-- Riga vuota: tiene la struttura a tre righe leggibile -->
<Border Grid.Row="1" Height="0"/>
<!-- ═══ Catalogo ═══ -->
<Grid Grid.Row="2" x:Name="CatalogPanel">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Categorie -->
<Border Grid.Column="0" Width="190" Background="{DynamicResource Brush.Surface}"
BorderBrush="{DynamicResource Brush.Border}" BorderThickness="0,0,1,0">
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="6,8">
<ItemsControl x:Name="CatalogCategoryList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Style="{StaticResource CategoryButton}"
GroupName="CatalogCategories"
Content="{Binding DisplayName}"
IsChecked="{Binding IsSelected, Mode=TwoWay}"
Checked="CategoryButton_Checked"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
<!-- Schede -->
<Grid Grid.Column="1">
<ScrollViewer x:Name="CatalogScroller" VerticalScrollBarVisibility="Auto" Padding="12,12,2,12">
<ItemsControl x:Name="CatalogItems" ItemTemplate="{StaticResource AuctionCardTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<!-- Stato vuoto / caricamento -->
<StackPanel x:Name="CatalogEmptyState" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Style="{StaticResource Glyph}" Text="&#xE721;" FontSize="34"
Foreground="{DynamicResource Brush.TextFaint}"/>
<TextBlock x:Name="CatalogEmptyText" Text="Caricamento categorie…"
Margin="0,10,0,0" HorizontalAlignment="Center"
Foreground="{DynamicResource Brush.TextMuted}"/>
</StackPanel>
</Grid>
</Grid>
<!-- ═══ Browser integrato ═══ -->
<Border Grid.Row="2" x:Name="BrowserPanel" Background="{DynamicResource Brush.Bg}" Visibility="Collapsed">
<wv2:WebView2 x:Name="EmbeddedWebView"
PreviewMouseRightButtonUp="EmbeddedWebView_PreviewMouseRightButtonUp"/>
</Border>
</Grid>
</UserControl>