UI: license summary becomes a colored badge in the top bar
The license info was rendered as plain secondary-grey text, easy to miss. Now it's a rounded pill (CornerRadius=14) with traffic-light colors driven by the new MainViewModel.LicenseSeverity property: - Ok → green pill (Brush.Status.Installed) with ✓ icon - Warning → amber pill (Brush.Status.Busy) with ⏰ icon, fires when entitlement is < 30 days away from expiry - Error → red pill (#EF4444 / #2A1414 bg) with 🔒/⚠/🚫 icon depending on whether license is missing, expired, revoked Two new VM properties accompany LicenseSummary: - LicenseIcon: emoji glyph for the pill - LicenseSeverity: enum-like string Ok/Warning/Error driving DataTriggers Both are kept in sync via NotifyLicenseChanged(), called wherever _license used to trigger only OnPropertyChanged(LicenseSummary). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,13 +69,66 @@ public sealed partial class MainViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_license is null) return "License : non configurée";
|
if (_license is null) return "Aucune license";
|
||||||
if (_license.Status == "valid")
|
if (_license.Status == "valid")
|
||||||
return $"License : {_license.OwnerName} • exp. {_license.DownloadEntitlementUntil:dd/MM/yyyy}";
|
{
|
||||||
if (_license.Status == "expired")
|
var until = _license.DownloadEntitlementUntil;
|
||||||
return $"License expirée le {_license.DownloadEntitlementUntil:dd/MM/yyyy}";
|
if (until is { } u && (u - DateTime.UtcNow).TotalDays < 30)
|
||||||
return $"License : {_license.Status}";
|
return $"{_license.OwnerName} • exp. {u:dd/MM/yyyy}";
|
||||||
|
return $"{_license.OwnerName} • exp. {until:dd/MM/yyyy}";
|
||||||
}
|
}
|
||||||
|
if (_license.Status == "expired")
|
||||||
|
return $"Expirée le {_license.DownloadEntitlementUntil:dd/MM/yyyy}";
|
||||||
|
if (_license.Status == "revoked")
|
||||||
|
return "Révoquée";
|
||||||
|
return _license.Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LicenseIcon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_license is null) return "🔒";
|
||||||
|
return _license.Status switch
|
||||||
|
{
|
||||||
|
"valid" when IsLicenseExpiringSoon() => "⏰",
|
||||||
|
"valid" => "✓",
|
||||||
|
"expired" => "⚠",
|
||||||
|
"revoked" => "🚫",
|
||||||
|
_ => "❓",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Catégorie utilisée par la UI pour piloter la couleur du badge license.
|
||||||
|
/// </summary>
|
||||||
|
public string LicenseSeverity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_license is null) return "Error";
|
||||||
|
return _license.Status switch
|
||||||
|
{
|
||||||
|
"valid" when IsLicenseExpiringSoon() => "Warning",
|
||||||
|
"valid" => "Ok",
|
||||||
|
_ => "Error",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsLicenseExpiringSoon()
|
||||||
|
{
|
||||||
|
if (_license?.DownloadEntitlementUntil is not { } until) return false;
|
||||||
|
return (until - DateTime.UtcNow).TotalDays < 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyLicenseChanged()
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(LicenseSummary));
|
||||||
|
OnPropertyChanged(nameof(LicenseIcon));
|
||||||
|
OnPropertyChanged(nameof(LicenseSeverity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EmptyHint =>
|
public string EmptyHint =>
|
||||||
@@ -257,7 +310,7 @@ public sealed partial class MainViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
// Au retour, l'URL serveur ou l'installRoot ont pu changer → refresh
|
// Au retour, l'URL serveur ou l'installRoot ont pu changer → refresh
|
||||||
_license = _licenseService.GetCached();
|
_license = _licenseService.GetCached();
|
||||||
OnPropertyChanged(nameof(LicenseSummary));
|
NotifyLicenseChanged();
|
||||||
RebuildList();
|
RebuildList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,7 +323,7 @@ public sealed partial class MainViewModel : ObservableObject
|
|||||||
if (dialog.LicenseActivated)
|
if (dialog.LicenseActivated)
|
||||||
{
|
{
|
||||||
_license = _licenseService.GetCached();
|
_license = _licenseService.GetCached();
|
||||||
OnPropertyChanged(nameof(LicenseSummary));
|
NotifyLicenseChanged();
|
||||||
RebuildList();
|
RebuildList();
|
||||||
}
|
}
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
|
|||||||
@@ -170,9 +170,69 @@
|
|||||||
Content="📁 Dossier"
|
Content="📁 Dossier"
|
||||||
Command="{Binding OpenInstallRootCommand}"
|
Command="{Binding OpenInstallRootCommand}"
|
||||||
Margin="0,0,12,0" />
|
Margin="0,0,12,0" />
|
||||||
|
<!-- Badge license -->
|
||||||
|
<Border CornerRadius="14" Padding="10,4"
|
||||||
|
VerticalAlignment="Center" Margin="0,0,8,0">
|
||||||
|
<Border.Style>
|
||||||
|
<Style TargetType="Border">
|
||||||
|
<!-- Default: error (rouge) -->
|
||||||
|
<Setter Property="Background" Value="#2A1414" />
|
||||||
|
<Setter Property="BorderBrush" Value="{StaticResource Brush.Status.AvailableBg}" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Ok">
|
||||||
|
<Setter Property="Background" Value="{StaticResource Brush.Status.InstalledBg}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{StaticResource Brush.Status.Installed}" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Warning">
|
||||||
|
<Setter Property="Background" Value="{StaticResource Brush.Status.BusyBg}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{StaticResource Brush.Status.Busy}" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Error">
|
||||||
|
<Setter Property="Background" Value="#2A1414" />
|
||||||
|
<Setter Property="BorderBrush" Value="#EF4444" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Style>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="{Binding LicenseIcon}"
|
||||||
|
FontSize="14" FontWeight="Bold"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,0,8,0">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="#EF4444" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Ok">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource Brush.Status.Installed}" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Warning">
|
||||||
|
<Setter Property="Foreground" Value="{StaticResource Brush.Status.Busy}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
<TextBlock Text="{Binding LicenseSummary}"
|
<TextBlock Text="{Binding LicenseSummary}"
|
||||||
Foreground="{StaticResource Brush.Text.Secondary}"
|
FontSize="12" FontWeight="SemiBold"
|
||||||
VerticalAlignment="Center" Margin="0,0,8,0" />
|
VerticalAlignment="Center">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="#FCA5A5" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Ok">
|
||||||
|
<Setter Property="Foreground" Value="#86EFAC" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding LicenseSeverity}" Value="Warning">
|
||||||
|
<Setter Property="Foreground" Value="#FCD34D" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
<Button Style="{StaticResource SecondaryButton}"
|
<Button Style="{StaticResource SecondaryButton}"
|
||||||
Content="🔑 Activer / changer"
|
Content="🔑 Activer / changer"
|
||||||
Command="{Binding ActivateLicenseCommand}"
|
Command="{Binding ActivateLicenseCommand}"
|
||||||
|
|||||||
Reference in New Issue
Block a user