feat(ui): implement Device→DB template sync view

Device→DB template sync UI wired to TemplateSyncService.
main
SYED MUSTUFA AHMED NAQVI 2026-08-27 11:12:30 +05:00
parent 87aacbea64
commit 059b667901
2 changed files with 182 additions and 13 deletions

View File

@ -1,22 +1,168 @@
<UserControl x:Class="HikvisionAttendanceManager.App.DeviceToDbView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<Style x:Key="DeviceToDbCard" TargetType="Border">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#DDE5F0"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Padding" Value="30,34"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="18" ShadowDepth="3" Opacity="0.08" Color="#4A5D78"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DeviceToDbCaption" TargetType="TextBlock">
<Setter Property="Foreground" Value="#65748C"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<Style x:Key="DeviceToDbComboBox" TargetType="ComboBox">
<Setter Property="Width" Value="520"/>
<Setter Property="Height" Value="44"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="#334155"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#CBD7E6"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="ItemTemplate" Value="{StaticResource DeviceComboItemTemplate}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<ToggleButton Background="White"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Focusable="False"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="5">
<Path Width="10"
Height="6"
Stretch="Uniform"
Fill="#526A8A"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0,0,16,0"
Data="M 0 0 L 5 5 L 10 0 Z"/>
</Border>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<ContentPresenter x:Name="ContentSite"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding ItemTemplate}"
IsHitTestVisible="False"
Margin="18,0,48,0"
VerticalAlignment="Center"
HorizontalAlignment="Left"/>
<TextBlock x:Name="PlaceholderText"
Text="Select a source device..."
Foreground="#78869A"
FontSize="{TemplateBinding FontSize}"
Margin="18,0,48,0"
VerticalAlignment="Center"
IsHitTestVisible="False"
Visibility="Collapsed"/>
<Popup Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Border Background="White"
BorderBrush="#CBD7E6"
BorderThickness="1"
CornerRadius="5"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}">
<ScrollViewer MaxHeight="260">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SelectedIndex" Value="-1">
<Setter TargetName="ContentSite" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="PlaceholderText" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="BorderBrush" Value="#7AA7F8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DeviceToDbPrimaryButton" TargetType="Button" BasedOn="{StaticResource PrimaryButton}">
<Setter Property="Height" Value="46"/>
<Setter Property="Padding" Value="18,0"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="0,28,0,0"/>
</Style>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<TextBlock Text="Device → DB" FontSize="25" FontWeight="SemiBold" Foreground="#17233B"/>
<TextBlock Text="Read Hikvision users and face templates from a device and save them to attendance_machine_user and attendance_machine_face_templates." Margin="0,6,0,22" Foreground="#66758C"/>
<Border Style="{StaticResource CardStyle}" Margin="0,0,0,14">
<StackPanel>
<TextBlock Text="SOURCE DEVICE" Style="{StaticResource CardCaption}"/>
<ComboBox x:Name="DeviceCombo" DisplayMemberPath="Name" MinWidth="320" HorizontalAlignment="Left" Margin="0,12,0,0"/>
<Button Content="Sync Device → DB" Style="{StaticResource PrimaryButton}" HorizontalAlignment="Left" Margin="0,14,0,0" Click="StartSync_Click"/>
<StackPanel Margin="8,8,8,0">
<Border Style="{StaticResource DeviceToDbCard}" MinHeight="220" Margin="0,0,0,16">
<StackPanel HorizontalAlignment="Left">
<Grid Width="520">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Text="SOURCE DEVICE" Style="{StaticResource DeviceToDbCaption}"/>
<Grid Width="16" Height="16" Margin="8,0,0,0" VerticalAlignment="Center">
<Ellipse Stroke="#6B8FC6" StrokeThickness="1.4"/>
<TextBlock Text="i"
Foreground="#6B8FC6"
FontSize="11"
FontWeight="SemiBold"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,-1,0,0"/>
</Grid>
</StackPanel>
<Button x:Name="RefreshButton" Content="↻ Refresh" Style="{StaticResource HeaderRefreshButton}" HorizontalAlignment="Right" VerticalAlignment="Center" Click="Refresh_Click"/>
</Grid>
<ComboBox x:Name="DeviceCombo"
Style="{StaticResource DeviceToDbComboBox}"
Margin="0,18,0,0"/>
<Button Style="{StaticResource DeviceToDbPrimaryButton}" Click="StartSync_Click">
<StackPanel Orientation="Horizontal">
<Path Width="18"
Height="18"
Stretch="Uniform"
Stroke="White"
StrokeThickness="1.7"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeLineJoin="Round"
Fill="Transparent"
Margin="0,0,9,0"
Data="M 9 2 V 11 M 5 7 L 9 11 L 13 7 M 3 13 V 16 H 15 V 13"/>
<TextBlock Text="Sync Device -> DB"/>
</StackPanel>
</Button>
</StackPanel>
</Border>
<Border x:Name="ProgressCard" Style="{StaticResource CardStyle}" Visibility="Collapsed">
<Border x:Name="ProgressCard" Style="{StaticResource DeviceToDbCard}" Visibility="Collapsed">
<StackPanel>
<ProgressBar x:Name="ProgressBar" Height="12" Margin="0,0,0,8"/>
<TextBlock x:Name="ProgressText" Foreground="#475569"/>
<TextBlock x:Name="CounterText" Margin="0,8,0,0" Foreground="#475569"/>
<ProgressBar x:Name="ProgressBar" Height="10" Margin="0,0,0,12"/>
<TextBlock x:Name="ProgressText" Foreground="#475569" FontSize="13" TextWrapping="Wrap"/>
<TextBlock x:Name="CounterText" Margin="0,8,0,0" Foreground="#475569" FontSize="13"/>
</StackPanel>
</Border>
</StackPanel>

View File

@ -21,9 +21,32 @@ public partial class DeviceToDbView : UserControl
{
if (_initialized) return;
_initialized = true;
DeviceCombo.ItemsSource = await _devices.LoadUnifiedAsync();
await RefreshAsync();
}
public async Task RefreshAsync()
{
var originalContent = RefreshButton.Content;
try
{
RefreshButton.IsEnabled = false;
RefreshButton.Content = "Refreshing...";
DeviceCombo.SelectedItem = null;
DeviceCombo.ItemsSource = await _devices.LoadUnifiedAsync();
ProgressCard.Visibility = Visibility.Collapsed;
ProgressBar.Value = 0;
ProgressText.Text = "";
CounterText.Text = "";
}
finally
{
RefreshButton.IsEnabled = true;
RefreshButton.Content = originalContent;
}
}
private async void Refresh_Click(object sender, RoutedEventArgs e) => await RefreshAsync();
private async void StartSync_Click(object sender, RoutedEventArgs e)
{
if (DeviceCombo.SelectedItem is not Device device) { MessageBox.Show("Select a device."); return; }