refactor(ui): alert rows are two lines of text — the heading line was redundant
Creator: system messages are limited to two lines; the label above the message ('STEAM ID NOT
PRESENT', 'STREAM') was repeating what the row already said and pushing the stack past its budget.
AttentionAlert loses Label; rows render Text only. The licence row is now exactly:
Steam ID Limit: 30fps
Click for More Info
(60fps with a close control once owned). Rows are identified by Id internally, so nothing in the UI
depends on the removed text. Tests updated to assert position/text rather than the heading.
This commit is contained in:
@@ -81,12 +81,9 @@
|
||||
Width="14" Height="14" Stretch="Uniform" VerticalAlignment="Top"
|
||||
Margin="6,2,2,0" ToolTip="Standing indicator"
|
||||
Visibility="{Binding ShowsPin, Converter={StaticResource BoolToVis}}"/>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Label}" Style="{StaticResource AppLogEntryText}"
|
||||
FontWeight="Bold" Foreground="{StaticResource Brush.Error}"/>
|
||||
<TextBlock Text="{Binding Text}" Style="{StaticResource AppLogEntryText}"
|
||||
TextWrapping="Wrap" Margin="0,2,0,0"/>
|
||||
</StackPanel>
|
||||
<TextBlock Text="{Binding Text}" Style="{StaticResource AppLogEntryText}"
|
||||
TextWrapping="Wrap" VerticalAlignment="Center"
|
||||
Foreground="{StaticResource Brush.Error}"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -8,10 +8,11 @@ namespace ytLive.Models;
|
||||
/// becomes dismissible — and its dismissal permanent — once ownership is verified).</para>
|
||||
/// <para>Clicking a row runs its action: the licence indicator opens About; an event alert opens the
|
||||
/// Logs tab with that event's lines highlighted.</para>
|
||||
/// <para>Rows are text only — a heading line above the message was redundant and pushed the stack past
|
||||
/// its two-line budget (creator, 2026-11-05).</para>
|
||||
/// </summary>
|
||||
public sealed record AttentionAlert(
|
||||
string Id,
|
||||
string Label,
|
||||
string Text,
|
||||
bool IsPinned,
|
||||
AttentionAlertAction Action,
|
||||
|
||||
@@ -46,8 +46,6 @@ public partial class MainViewModel
|
||||
return $"Steam ID Limit: {entitled}fps\nClick for More Info";
|
||||
}
|
||||
|
||||
private string SteamLicenceLabel() => IsAppOwned ? "STEAM ID PRESENT" : "STEAM ID NOT PRESENT";
|
||||
|
||||
/// <summary>Recomputes row 1 in place. Called at startup and whenever ownership changes.</summary>
|
||||
private void RefreshSteamLicenceAlert()
|
||||
{
|
||||
@@ -63,7 +61,6 @@ public partial class MainViewModel
|
||||
|
||||
var alert = new AttentionAlert(
|
||||
SteamLicenceAlertId,
|
||||
SteamLicenceLabel(),
|
||||
SteamLicenceText(),
|
||||
IsPinned: !IsAppOwned,
|
||||
AttentionAlertAction.About);
|
||||
@@ -76,9 +73,9 @@ public partial class MainViewModel
|
||||
|
||||
/// <summary>Pushes an event alert. Newest sits directly under the licence indicator; older ones
|
||||
/// stack beneath, so the newest is the one nearest the eye.</summary>
|
||||
private AttentionAlert? PushAttentionAlert(string id, string label, string text, long logFrom, long logTo)
|
||||
private AttentionAlert? PushAttentionAlert(string id, string text, long logFrom, long logTo)
|
||||
{
|
||||
var alert = new AttentionAlert(id, label, text, IsPinned: false, AttentionAlertAction.Logs, logFrom, logTo);
|
||||
var alert = new AttentionAlert(id, text, IsPinned: false, AttentionAlertAction.Logs, logFrom, logTo);
|
||||
var insertAt = _attentionAlerts.Count(alert => alert.Id == SteamLicenceAlertId);
|
||||
var existing = _attentionAlerts.FirstOrDefault(candidate => candidate.Id == id);
|
||||
if (existing != null)
|
||||
@@ -95,8 +92,8 @@ public partial class MainViewModel
|
||||
}
|
||||
|
||||
/// <summary>Test seam: pushes an event row without a stream session behind it.</summary>
|
||||
internal AttentionAlert? PushAttentionAlertForTest(string id, string label, string text, long logFrom, long logTo)
|
||||
=> PushAttentionAlert(id, label, text, logFrom, logTo);
|
||||
internal AttentionAlert? PushAttentionAlertForTest(string id, string text, long logFrom, long logTo)
|
||||
=> PushAttentionAlert(id, text, logFrom, logTo);
|
||||
|
||||
private void RemoveAttentionAlert(string id)
|
||||
{
|
||||
|
||||
@@ -87,7 +87,6 @@ public partial class MainViewModel
|
||||
: logFrom;
|
||||
PushAttentionAlert(
|
||||
"stream-recovery",
|
||||
"STREAM",
|
||||
text,
|
||||
logFrom,
|
||||
Math.Max(logFrom, to));
|
||||
|
||||
@@ -4,9 +4,11 @@ A stack of red rows at the top of the left panel, **above both mode grids** (so
|
||||
and while live) and pushing the panel's content down. Only red rows belong there — it is the surface for
|
||||
"something needs you", never chatter.
|
||||
|
||||
- **Rows are text only, two lines at most** — no heading line above the message (creator, 2026-11-05:
|
||||
the heading was redundant and pushed the stack past its budget).
|
||||
- **Row 1 is always the Steam licence indicator** and nothing displaces it. It reads as status, not a
|
||||
warning: `Entitlement 30 fps · Maximum 60 fps`, both numbers derived from `QualityOptions` and
|
||||
`HasProOutput`. It shows a **pin** (standing indicator, no close control) while higher tiers are
|
||||
warning: `Steam ID Limit: 30fps` / `Click for More Info` (60fps once owned), both numbers derived from
|
||||
`QualityOptions` and `HasProOutput`. It shows a **pin** (standing indicator, no close control) while higher tiers are
|
||||
unavailable, and a **close control once ownership is verified** — that close is persisted
|
||||
(`Steam.LicenceIndicatorDismissed`) and permanent *while ownership holds*; losing ownership restores
|
||||
the row as pinned, because that is a change of state rather than a preference. Click → About.
|
||||
|
||||
@@ -99,7 +99,7 @@ public sealed class AboutHubTests
|
||||
// The old red panel under the quality picker is gone (2026-11-05): the licence state
|
||||
// lives in the left panel's alert stack now, as a pinned status indicator.
|
||||
Assert.Null(window.FindName("EntitlementErrorPanel"));
|
||||
var licenceRow = vm.AttentionAlerts.Single(alert => alert.Label == "STEAM ID NOT PRESENT");
|
||||
var licenceRow = vm.AttentionAlerts.Single(alert => alert.Id == "steam-licence");
|
||||
Assert.True(licenceRow.IsPinned);
|
||||
Assert.Contains("Steam ID Limit: 30fps", licenceRow.Text);
|
||||
Assert.Contains("Click for More Info", licenceRow.Text);
|
||||
|
||||
@@ -32,11 +32,13 @@ public sealed class AttentionAlertStackTests
|
||||
vm.EntitlementOverride = new FakeEntitlement(false, "Steam licensing is not configured in this build.");
|
||||
|
||||
var row = Assert.Single(vm.AttentionAlerts);
|
||||
Assert.Equal("STEAM ID NOT PRESENT", row.Label);
|
||||
Assert.Equal("steam-licence", row.Id);
|
||||
Assert.True(row.IsPinned);
|
||||
Assert.True(row.ShowsPin);
|
||||
Assert.False(row.CanDismiss);
|
||||
Assert.Equal(AttentionAlertAction.About, row.Action);
|
||||
// Two lines at most: the heading above the message was redundant.
|
||||
Assert.DoesNotContain("\n\n", row.Text);
|
||||
|
||||
// Creator wording: the limit this build runs at, and where to find out why.
|
||||
Assert.Contains("Steam ID Limit: 30fps", row.Text);
|
||||
@@ -63,11 +65,11 @@ public sealed class AttentionAlertStackTests
|
||||
|
||||
// Permanent: a fresh view-model on the same profile must not bring it back…
|
||||
var reloaded = new MainViewModel();
|
||||
Assert.DoesNotContain(reloaded.AttentionAlerts, alert => alert.Label.StartsWith("STEAM ID"));
|
||||
Assert.DoesNotContain(reloaded.AttentionAlerts, alert => alert.Id == "steam-licence");
|
||||
|
||||
// …but losing ownership restores it as a pinned indicator: a change of state, not a preference.
|
||||
reloaded.EntitlementOverride = new FakeEntitlement(false, "Steam licensing is not configured in this build.");
|
||||
var restored = reloaded.AttentionAlerts.First(alert => alert.Label == "STEAM ID NOT PRESENT");
|
||||
var restored = reloaded.AttentionAlerts.First(alert => alert.Id == "steam-licence");
|
||||
Assert.True(restored.IsPinned);
|
||||
});
|
||||
}
|
||||
@@ -90,22 +92,22 @@ public sealed class AttentionAlertStackTests
|
||||
WithVm(vm =>
|
||||
{
|
||||
vm.EntitlementOverride = new FakeEntitlement(false, "Steam licensing is not configured in this build.");
|
||||
vm.PushAttentionAlertForTest("drop-1", "STREAM", "Stream dropped — reconnecting (attempt 1 of 4)", 10, 12);
|
||||
vm.PushAttentionAlertForTest("drop-2", "STREAM", "Stream dropped — reconnecting (attempt 2 of 4)", 13, 15);
|
||||
vm.PushAttentionAlertForTest("drop-1", "Stream dropped — reconnecting (attempt 1 of 4)", 10, 12);
|
||||
vm.PushAttentionAlertForTest("drop-2", "Stream dropped — reconnecting (attempt 2 of 4)", 13, 15);
|
||||
|
||||
Assert.Equal(new[] { "STEAM ID NOT PRESENT", "STREAM", "STREAM" }, vm.AttentionAlerts.Select(a => a.Label));
|
||||
Assert.Equal(new[] { "steam-licence", "drop-2", "drop-1" }, vm.AttentionAlerts.Select(a => a.Id));
|
||||
// Newest event sits directly under the indicator.
|
||||
Assert.Contains("attempt 2", vm.AttentionAlerts[1].Text);
|
||||
Assert.Contains("attempt 1", vm.AttentionAlerts[2].Text);
|
||||
|
||||
// The same event advancing updates its row instead of adding another.
|
||||
vm.PushAttentionAlertForTest("drop-2", "STREAM", "Stream recovered after 1.4 s", 13, 16);
|
||||
vm.PushAttentionAlertForTest("drop-2", "Stream recovered after 1.4 s", 13, 16);
|
||||
Assert.Equal(3, vm.AttentionAlerts.Count);
|
||||
Assert.Contains("recovered", vm.AttentionAlerts[1].Text);
|
||||
|
||||
vm.DismissAlertCommand.Execute(vm.AttentionAlerts[1]);
|
||||
Assert.Equal(2, vm.AttentionAlerts.Count);
|
||||
Assert.Equal("STEAM ID NOT PRESENT", vm.AttentionAlerts[0].Label);
|
||||
Assert.Equal("steam-licence", vm.AttentionAlerts[0].Id);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -114,7 +116,7 @@ public sealed class AttentionAlertStackTests
|
||||
{
|
||||
WithVm(vm =>
|
||||
{
|
||||
vm.PushAttentionAlertForTest("drop-1", "STREAM", "Stream dropped", 41, 47);
|
||||
vm.PushAttentionAlertForTest("drop-1", "Stream dropped", 41, 47);
|
||||
|
||||
vm.ActivateAlertCommand.Execute(vm.AttentionAlerts[1]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user