v0.24.5 — Install Program Files, multi-PC DL reliability, polish UI

Installeur :
- Bascule en Program Files (autopf) avec PrivilegesRequired=admin.
  L'auto-update reste fonctionnel : LauncherSelfUpdater détecte le dossier
  protégé et lance PS_Launcher.Updater.exe via Verb=runas (UAC à chaque MAJ).
- build-installer.ps1 : détection ISCC.exe robuste (Program Files + LocalAppData
  pour install winget user-mode + PATH), messages d'erreur explicites avec URL
  et commande winget, suppression accents (compat PS 5.1 sans BOM).

Téléchargements multi-PC :
- DownloadManager : détection des connexions fermées prématurément (PHP-FPM
  request_terminate_timeout). Sans ça, segment marqué Completed=false sans
  exception → fichier sparse final avec trous → SHA-256 KO. Lance maintenant
  HttpResumableException(transient) pour que Polly retry au bon offset.
- ParallelDownloadSegments : 16 → 6 par défaut pour permettre plusieurs PCs
  simultanés sans saturer le pool PHP-FPM OVH (~30 workers).

UI :
- Fenêtre maximisée par défaut au démarrage (WindowState=Maximized).
- Fix maximize qui cachait le footer / barre de DL (WM_GETMINMAXINFO clamp
  sur work area, remplace le margin hack 7px imprécis).
- Sidebar : bloc info en bas avec PS_Launcher vX.Y.Z + IPv4 locale alignés.
- Copyright remonté plus près du footer (margin 28 → 8).
- Settings → Health checks : boutons ▲/▼ pour réordonner, CanExecute auto.
- HealthCheck refresh défaut : 5000 → 2000 ms.

Bug fix UI :
- MainViewModel.RebuildList preserve l'état du row actif pendant un DL.
  Sinon ouvrir Settings/License pendant un DL recréait les rows from scratch
  → UI affichait "Reprendre" + "Annuler" alors que le DL tournait. Les
  progress callbacks pointent maintenant sur _activeRow (résolution dynamique)
  au lieu de capturer le row local.

Defaults config :
- ServerBaseUrl : example.com → asterionvr.com (out-of-the-box).
- Vive Business Streaming check : HtcConnectionUtility → rrserver.

Backoffice (server/admin/licenses.php) :
- Action set_max_machines : bouton "Slots" pour ajuster max_machines à chaud
  sur une licence existante. Refus de descendre sous le nombre de machines
  déjà actives.

Build :
- AllowUnsafeBlocks=true sur PSLauncher.App.csproj (compat WinRT generator
  récent qui émet du code unsafe dans WinRTGenericInstantiation.g.cs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-04 12:04:36 +02:00
parent be7ccfced5
commit 9de8e95910
11 changed files with 439 additions and 83 deletions

View File

@@ -11,6 +11,7 @@
Width="1280" Height="720"
MinWidth="980" MinHeight="600"
WindowStartupLocation="CenterScreen"
WindowState="Maximized"
WindowStyle="None"
ResizeMode="CanResize"
AllowsTransparency="False"
@@ -193,22 +194,10 @@
de fenêtre. Le footer est confiné à la colonne content.
-->
<Grid Background="{StaticResource Brush.Bg.Window}">
<!-- Bug WPF connu avec WindowStyle=None + WindowChrome : en mode
Maximized, la fenêtre déborde de ~7 px sur chaque bord (le
ResizeBorderThickness physique reste). Sans compensation, le footer
(Row 3) passe sous la barre des tâches et la barre de download
devient invisible. On applique un margin de 7 px en mode Maximized
via un trigger sur WindowState. -->
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Margin" Value="0" />
<Style.Triggers>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Maximized">
<Setter Property="Margin" Value="7" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<!-- La fenêtre est correctement clampée à la work area du moniteur en mode
Maximized via WM_GETMINMAXINFO (cf. MainWindow.xaml.cs). Plus besoin
de hack via Margin sur trigger WindowState. -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
@@ -630,9 +619,11 @@
Command="{Binding CheckForUpdatesCommand}" />
<!-- Copyright flottant en bas centré, sur une pill sombre pour rester
lisible quel que soit l'arrière-plan (image, voile noir, etc.). -->
lisible quel que soit l'arrière-plan (image, voile noir, etc.).
Bottom margin volontairement faible pour rester collé au footer
(barre de DL) quand il s'affiche. -->
<Border HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="0,0,0,28"
Margin="0,0,0,8"
Background="#A0000000"
CornerRadius="10"
Padding="10,4">
@@ -677,33 +668,76 @@
Background="#0A0A0E"
BorderBrush="{StaticResource Brush.Border}"
BorderThickness="0,0,1,0">
<StackPanel Orientation="Vertical" Margin="0,16,0,0">
<!-- Style des boutons définis dans Theme.xaml (NavButton) -->
<Button Style="{StaticResource NavButton}"
Command="{Binding NavigateLibraryCommand}"
Tag="{Binding IsLibrary}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📚" FontSize="16" Margin="0,0,12,0" VerticalAlignment="Center" />
<TextBlock Text="{x:Static loc:Strings.NavLibrary}" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button Style="{StaticResource NavButton}"
Command="{Binding NavigateReportCommand}"
Tag="{Binding IsReport}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📊" FontSize="16" Margin="0,0,12,0" VerticalAlignment="Center" />
<TextBlock Text="{x:Static loc:Strings.NavReport}" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button Style="{StaticResource NavButton}"
Command="{Binding NavigateDocumentationCommand}"
Tag="{Binding IsDocumentation}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📖" FontSize="16" Margin="0,0,12,0" VerticalAlignment="Center" />
<TextBlock Text="{x:Static loc:Strings.NavDocumentation}" VerticalAlignment="Center" />
</StackPanel>
</Button>
</StackPanel>
<DockPanel LastChildFill="True">
<!-- Bloc d'info en bas de sidebar : version du launcher + IP locale.
Utilité diagnostic terrain : le support peut lire les deux infos
sans avoir à naviguer dans Windows ou About. DockPanel.Dock=Bottom
pour rester collé au bas peu importe la hauteur de la fenêtre. -->
<Border DockPanel.Dock="Bottom"
BorderBrush="{StaticResource Brush.Border}"
BorderThickness="0,1,0,0"
Padding="16,10">
<!-- Grid 2 colonnes : la colonne label (Auto) prend la largeur du
plus long ("PS_Launcher:"), la colonne valeur démarre au même X
sur les deux lignes → version et IP visuellement alignées. -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0"
Text="PS_Launcher"
Foreground="{StaticResource Brush.Text.Secondary}"
FontSize="11" Margin="0,0,8,0"
ToolTip="Version du launcher" />
<TextBlock Grid.Row="0" Grid.Column="1"
Text="{Binding AppVersion}"
Foreground="{StaticResource Brush.Text.Secondary}"
FontSize="11" />
<TextBlock Grid.Row="1" Grid.Column="0"
Text="IP"
Foreground="{StaticResource Brush.Text.Secondary}"
FontSize="11" Margin="0,2,8,0"
ToolTip="IPv4 locale du PC (interface avec gateway par défaut)" />
<TextBlock Grid.Row="1" Grid.Column="1"
Text="{Binding LocalIpAddress}"
Foreground="{StaticResource Brush.Text.Secondary}"
FontSize="11" Margin="0,2,0,0" />
</Grid>
</Border>
<StackPanel Orientation="Vertical" Margin="0,16,0,0">
<!-- Style des boutons définis dans Theme.xaml (NavButton) -->
<Button Style="{StaticResource NavButton}"
Command="{Binding NavigateLibraryCommand}"
Tag="{Binding IsLibrary}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📚" FontSize="16" Margin="0,0,12,0" VerticalAlignment="Center" />
<TextBlock Text="{x:Static loc:Strings.NavLibrary}" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button Style="{StaticResource NavButton}"
Command="{Binding NavigateReportCommand}"
Tag="{Binding IsReport}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📊" FontSize="16" Margin="0,0,12,0" VerticalAlignment="Center" />
<TextBlock Text="{x:Static loc:Strings.NavReport}" VerticalAlignment="Center" />
</StackPanel>
</Button>
<Button Style="{StaticResource NavButton}"
Command="{Binding NavigateDocumentationCommand}"
Tag="{Binding IsDocumentation}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="📖" FontSize="16" Margin="0,0,12,0" VerticalAlignment="Center" />
<TextBlock Text="{x:Static loc:Strings.NavDocumentation}" VerticalAlignment="Center" />
</StackPanel>
</Button>
</StackPanel>
</DockPanel>
</Border>
<!-- Footer : Row 3, Col 1 → cantonné à la colonne content, sous la zone