UI overhaul: minimal top bar, license-first settings, footer-pinned check

Top bar (3-column layout)
-------------------------
- Col 1: PROSERVE Launcher wordmark.
- Col 2: license badge centered, the badge IS the click target now (a
  Border with an InputBindings MouseBinding LeftClick to OpenLicense).
  No more separate "🔑 Activer / changer" button cluttering the right.
- Col 3: ⚙ Paramètres + window chrome (min/max/close).
- "📁 Dossier" button removed from the top bar — install root is still
  reachable from Settings.

Footer (always visible)
-----------------------
- Row 1: "🔄 Vérifier les MAJ" pinned bottom-left, always shown. The
  optional "Annuler" button stays bottom-right while a download runs.
- Row 2: status text + progress bar, only shown when busy or after a
  status message — the previous "footer entirely hidden when idle"
  hid the check button too.

License flow split in two
-------------------------
Click on the license badge:
- License is active (valid / expired / revoked) → LicenseDetailsDialog
  opens. Header pill in matching status color (green/amber/red), shows
  owner, validity, issued date, machine ID with copy-to-clipboard. Two
  buttons: "🗑 Désactiver la license" (with confirmation) and Close.
- No license OR after deactivation → falls through to the existing
  OnboardingDialog for re-keying.

Settings rework
---------------
LICENSE section is now first in SettingsDialog with the same
green/amber/red colored chrome as the top bar — at a glance the user
sees the same status everywhere. Machine ID copy moved into this card.

Sign-manifest no longer needs exec()
------------------------------------
The "🔁 Sync" button in admin/versions.php previously shelled out to
`php tools/sign-manifest.php` via exec(). OVH mutualisé often disables
exec(), causing silent no-ops and the symptom the user just hit: the
ZIP changed (new size 469,657,770 vs manifest's stale 469,831,428) and
the launcher rejected it as size mismatch.

Refactor:
- New PSLauncher\Tools\SignManifest class with ->run() that does the
  hashing, latest-bump and Ed25519 signing in-process.
- tools/sign-manifest.php is now a 6-line wrapper for the class.
- admin/versions.php's 'sync' action calls the class directly via
  require_once + new — works on any host, no exec dependency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 09:24:01 +02:00
parent 74f48419e6
commit b10a3fbabf
9 changed files with 609 additions and 246 deletions

View File

@@ -0,0 +1,113 @@
<Window x:Class="PSLauncher.App.Views.LicenseDetailsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="License"
Width="500" Height="480"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
Background="{StaticResource Brush.Bg.Window}">
<Grid Margin="32,28">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Header avec badge couleur -->
<Border Grid.Row="0" CornerRadius="8" Padding="20,16"
BorderThickness="2"
x:Name="HeaderBorder">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="StatusIconText"
FontSize="32" FontWeight="Bold"
VerticalAlignment="Center" Margin="0,0,16,0" />
<StackPanel VerticalAlignment="Center">
<TextBlock x:Name="StatusTitleText"
FontSize="18" FontWeight="SemiBold"
Foreground="{StaticResource Brush.Text.Primary}" />
<TextBlock x:Name="StatusSubtitleText"
FontSize="13"
Foreground="{StaticResource Brush.Text.Secondary}"
Margin="0,2,0,0" />
</StackPanel>
</StackPanel>
</Border>
<!-- Détails -->
<Border Grid.Row="2" Background="{StaticResource Brush.Bg.Card}"
BorderBrush="{StaticResource Brush.Border}" BorderThickness="1"
CornerRadius="6" Padding="20" Margin="0,16,0,0">
<StackPanel>
<Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Client"
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
<TextBlock Grid.Column="1" x:Name="OwnerText"
FontWeight="SemiBold"
Foreground="{StaticResource Brush.Text.Primary}" />
</Grid>
<Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Validité téléchargements"
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
<TextBlock Grid.Column="1" x:Name="UntilText"
FontWeight="SemiBold"
Foreground="{StaticResource Brush.Text.Primary}" />
</Grid>
<Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Activée le"
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12" />
<TextBlock Grid.Column="1" x:Name="IssuedText"
Foreground="{StaticResource Brush.Text.Primary}" />
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="ID machine"
Foreground="{StaticResource Brush.Text.Secondary}" FontSize="12"
VerticalAlignment="Center" />
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="MachineIdText"
FontFamily="Consolas" FontSize="11"
Foreground="{StaticResource Brush.Text.Primary}"
TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
<Button Grid.Column="1" Style="{StaticResource SecondaryButton}"
Content="📋"
ToolTip="Copier"
Click="OnCopyMachineId" />
</Grid>
</Grid>
</StackPanel>
</Border>
<!-- Footer actions -->
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
<Button Style="{StaticResource SecondaryButton}"
Content="🗑 Désactiver la license"
Click="OnDeactivate"
Margin="0,0,12,0" />
<Button Style="{StaticResource AccentButton}"
Content="Fermer"
IsCancel="True" IsDefault="True"
Padding="32,8"
Click="OnClose" />
</StackPanel>
</Grid>
</Window>