v1.0.9 — Badge channel affiché uniquement en cas de conflit de version

Feedback UX post-1.0.8 : le badge channel bleu était toujours visible dès
qu'une entrée manifest avait un channel non-default. Sur les setups
mono-channel (99 % des cas, y compris les clients firefighter/police qui
ne voient QUE leur channel + les entries default), ça polluait chaque row
avec un badge sans valeur informative — le badge ne sert qu'à distinguer
deux rows partageant un numéro de version.

Fix : nouveau flag HasVersionConflict sur VersionRowViewModel, positionné
par RebuildList après construction (group by Version, count >= 2 → true).
HasChannelBadge devient (ChannelBadge non vide AND HasVersionConflict) —
badge visible seulement quand une AUTRE row visible partage le même numéro.

Résultat :
  • Client firefighter voit v1.5.4.32 (default) → pas de badge (row unique)
  • Client firefighter voit v1.5.4.32 (default) + v1.5.4.32 (firefighter)
    → les DEUX rows affichent leur badge (« default » n'a pas de badge par
    convention, mais firefighter a le sien → distingue visuellement)
  • Client dev/opérateur voit tous les channels → badge apparaît sur toute
    row en conflit

Notification via [NotifyPropertyChangedFor(HasChannelBadge)] sur la
property auto-générée HasVersionConflict — les bindings XAML se rafraîchissent
correctement quand le flag change entre deux RebuildList (ex : upload
d'une entrée concurrente côté serveur puis refresh manifest client).

Bump : 1.0.8 → 1.0.9 (patch UX).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 17:02:26 +02:00
parent 28c5ca5877
commit 53c9e0519c
4 changed files with 31 additions and 5 deletions

View File

@@ -18,9 +18,9 @@
<Product>PROSERVE Launcher</Product>
<Copyright>© 2026 ASTERION VR — All rights reserved</Copyright>
<RootNamespace>PSLauncher.App</RootNamespace>
<Version>1.0.8</Version>
<AssemblyVersion>1.0.8.0</AssemblyVersion>
<FileVersion>1.0.8.0</FileVersion>
<Version>1.0.9</Version>
<AssemblyVersion>1.0.9.0</AssemblyVersion>
<FileVersion>1.0.9.0</FileVersion>
<!-- Single-file self-contained publish profile (used by `dotnet publish`) -->
<PublishSingleFile>true</PublishSingleFile>

View File

@@ -657,6 +657,15 @@ public sealed partial class MainViewModel : ObservableObject
}
}
// Marque les rows qui partagent un numéro de version avec au moins UNE
// autre row visible → active leur badge channel (sinon caché pour ne pas
// polluer l'UI mono-channel). Group by Version, count >= 2 → conflict.
foreach (var grp in rows.GroupBy(r => r.Version, StringComparer.OrdinalIgnoreCase))
{
bool hasConflict = grp.Count() >= 2;
foreach (var r in grp) r.HasVersionConflict = hasConflict;
}
// Featured : plus haute installée, sinon plus haute distante
var featured = rows.FirstOrDefault(r => r.IsInstalled) ?? rows.FirstOrDefault();
FeaturedVersion = featured;

View File

@@ -56,7 +56,24 @@ public sealed partial class VersionRowViewModel : ObservableObject
.FirstOrDefault(c => !string.IsNullOrWhiteSpace(c)
&& !string.Equals(c, "default", StringComparison.OrdinalIgnoreCase));
public bool HasChannelBadge => !string.IsNullOrEmpty(ChannelBadge);
/// <summary>
/// True si au moins une AUTRE row visible sur ce launcher partage le même
/// numéro de version. Positionné par <c>MainViewModel.RebuildList</c> après
/// construction des rows (group by Version, count &gt;= 2 → conflict).
/// Le badge channel n'est utile QUE dans ce cas — sinon la row est
/// univoque et le badge ajoute du bruit visuel.
/// </summary>
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(HasChannelBadge))]
private bool _hasVersionConflict;
/// <summary>
/// Le badge n'est visible QUE quand la row a un channel spécifique ET qu'une
/// autre row visible partage le même numéro de version. Ça garde l'UI propre
/// sur les setups mono-channel (99 % des cas) et affiche le distingueur
/// seulement quand il est réellement nécessaire.
/// </summary>
public bool HasChannelBadge => !string.IsNullOrEmpty(ChannelBadge) && HasVersionConflict;
/// <summary>
/// True si la version est taggée BÊTA dans le manifest (champ