Bump to v3.1.2: tray icon re-stamps on state change, recording shows as a flag
- Tray icon now re-registers itself (hide+re-show) whenever the meaningful
state changes — peer connect/drop, send/receive toggle, recording
start/stop — so the name a screen reader announces stays in step with
the live state. Fixes the persistent "no peers" then "1 peer" double
announcement that the old "show window then minimise again" trick used
to clear by hand. Same root cause as the v3.1.1 stuck-tooltip fix, just
exposed when the state changes a moment after the icon appears.
- Recording shows as a plain "recording" flag in the tray rather than a
live timer. A ticking timer would have either flickered the icon once a
second or left a screen reader announcing a stale time next to the live
one. Removed the now-dead FormatRecordingElapsed helper.
- Bundles the earlier Win7 updater fix (6cbde0d): a failed secure
connection is no longer mislabelled as "you're up to date".
- About box, RELEASE_NOTES.md, readme.html and MANUAL.md updated to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
6cbde0da12
commit
baf50baf73
@@ -20,6 +20,44 @@ internal sealed class AboutDialog : Form
|
||||
/// updates" path.</summary>
|
||||
private const string ReleaseNotes =
|
||||
"""
|
||||
RemSound v3.1.2
|
||||
|
||||
A small accessibility fix for the system tray
|
||||
icon, plus a clearer "check for updates" message
|
||||
for Windows 7.
|
||||
|
||||
The tray icon's double announcement: if you use a
|
||||
screen reader, the tray icon could read out two
|
||||
states one after the other — for example "no peers"
|
||||
and then "1 peer" — every time you landed on it. It
|
||||
always happened in that same order. Windows stamps
|
||||
a tray icon's name at the moment the icon appears,
|
||||
which on a fresh start is a second before your other
|
||||
machine has reconnected — so the name was frozen as
|
||||
"no peers" while only the hover text caught up to
|
||||
"1 peer". RemSound now refreshes the icon itself
|
||||
whenever something real changes — a peer connecting
|
||||
or dropping, sending or receiving switching on or
|
||||
off, a recording starting or stopping — so the
|
||||
screen reader hears a single, current state.
|
||||
|
||||
Recording in the tray: while a recording is running
|
||||
the tray now simply says "recording" rather than
|
||||
counting the seconds. A live timer would have made
|
||||
the icon flicker or read out a stale time; the exact
|
||||
length is on the main window if you need it.
|
||||
|
||||
Windows 7 update message: on a Windows 7 machine
|
||||
that can't make a secure connection to the update
|
||||
server, "Check for updates" used to say "you're on
|
||||
the latest version", which was misleading. It now
|
||||
explains that the secure connection failed and points
|
||||
to the Windows updates that fix it, with a manual
|
||||
download link as a fallback. Windows 10 and 11 were
|
||||
never affected.
|
||||
|
||||
Everything else from v3.1 is unchanged.
|
||||
|
||||
RemSound v3.1.1
|
||||
|
||||
Hot-fix for a small but annoying bug with the system
|
||||
|
||||
@@ -5292,14 +5292,15 @@ public sealed class MainForm : Form
|
||||
if (ph.State == PeerHealthState.Healthy) healthyPeers++;
|
||||
}
|
||||
}
|
||||
// Recording timer — only included when a recording is actually running. Slots in
|
||||
// right after the "RemSound" leader as Ed asked, so it reads as a status on the
|
||||
// app itself rather than a property of the peer list.
|
||||
string? recordingPart = null;
|
||||
if (recordingController.IsRecording && recordingController.RecordingStartedUtc is { } startedUtc)
|
||||
{
|
||||
recordingPart = $"recording for {FormatRecordingElapsed(DateTime.UtcNow - startedUtc)}";
|
||||
}
|
||||
// Recording status — a plain "recording" flag while a capture is running, with no
|
||||
// elapsed timer. A live timer would have to rewrite the tooltip every second, which
|
||||
// fights the tray icon's re-stamp-on-change behaviour: it would either flicker the
|
||||
// icon once a second or leave a screen reader announcing a stale time next to the live
|
||||
// one. Recording starting and stopping are real state changes that re-stamp cleanly;
|
||||
// the second-by-second count is intentionally left to the main window. Slots in right
|
||||
// after the "RemSound" leader so it reads as a status on the app itself rather than a
|
||||
// property of the peer list.
|
||||
string? recordingPart = recordingController.IsRecording ? "recording" : null;
|
||||
if (healthyPeers == 0 && !sendMyAudioCheckbox.Checked && !receiveAudioCheckbox.Checked)
|
||||
{
|
||||
return recordingPart is null
|
||||
@@ -5346,20 +5347,6 @@ public sealed class MainForm : Form
|
||||
return list.CheckedItems.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>Compact duration formatter for the tray tooltip's "recording for X" segment.
|
||||
/// Under an hour shows MM:SS; from an hour on it shows H:MM:SS — the same shape Windows
|
||||
/// uses for media-player elapsed-time displays, so it reads naturally to people who
|
||||
/// don't otherwise know it's a custom format.</summary>
|
||||
private static string FormatRecordingElapsed(TimeSpan elapsed)
|
||||
{
|
||||
// Negative elapsed (clock skew across a sleep cycle) gets clamped to zero — better
|
||||
// than displaying "-00:01" mid-tooltip.
|
||||
if (elapsed < TimeSpan.Zero) elapsed = TimeSpan.Zero;
|
||||
return elapsed.TotalHours >= 1
|
||||
? $"{(int)elapsed.TotalHours}:{elapsed.Minutes:D2}:{elapsed.Seconds:D2}"
|
||||
: $"{elapsed.Minutes:D2}:{elapsed.Seconds:D2}";
|
||||
}
|
||||
|
||||
/// <summary>Pretty-print "WASAPI", "ASIO", "WASAPI + ASIO", or "no devices" depending
|
||||
/// on which of the two flags are set. "no devices" covers the awkward case where the
|
||||
/// user has the send/receive checkbox on but hasn't ticked anything for the engine to
|
||||
|
||||
@@ -40,6 +40,13 @@ internal sealed class MainFormTrayController : IDisposable
|
||||
private readonly Func<string> buildTooltip;
|
||||
private readonly Action exit;
|
||||
|
||||
/// <summary>The tooltip text the icon was last (re-)registered with. We compare against
|
||||
/// this so we only re-register on a real state change — a peer connecting or dropping, a
|
||||
/// lane switching, a recording starting or stopping. The tray tooltip has no per-second
|
||||
/// element (recording shows a plain "recording" flag, not a ticking timer), so the text
|
||||
/// only changes on those real events and the icon never flickers. Null until first shown.</summary>
|
||||
private string? lastRegistrationText;
|
||||
|
||||
private readonly ToolStripMenuItem sendingItem;
|
||||
private readonly ToolStripMenuItem receivingItem;
|
||||
private readonly ToolStripMenuItem profilesItem;
|
||||
@@ -152,6 +159,38 @@ internal sealed class MainFormTrayController : IDisposable
|
||||
// NotifyIcon.Text throws on the same string-assigning path under some shell
|
||||
// conditions (rare race during a session-end). Best-effort: swallow.
|
||||
try { trayIcon.Text = text; } catch { /* harmless */ }
|
||||
|
||||
// Keep the icon's *registered* name — the text a screen reader announces — in step
|
||||
// with the live state. Windows stamps a tray icon's accessible name at the moment the
|
||||
// icon is added (NIM_ADD) and afterwards only refreshes the little hover bubble, not
|
||||
// that stamped name. So if the icon appears at launch before the first peer has
|
||||
// connected, the name is frozen as "no peers"; when the peer links up a second later
|
||||
// the bubble updates to "1 peer" but the frozen name stays — and NVDA reads BOTH (the
|
||||
// stale name, then the live bubble), which is the confusing double announcement.
|
||||
//
|
||||
// The cure is to re-add the icon (hide then re-show = NIM_DELETE + NIM_ADD) whenever
|
||||
// the text changes, which re-stamps the name with the current text. This is exactly
|
||||
// what the old "show the window then minimise again" workaround did by hand. The tray
|
||||
// tooltip has no per-second element (recording shows a plain "recording" flag, not a
|
||||
// ticking timer), so the text only changes on real events and this never flickers.
|
||||
if (!trayIcon.Visible)
|
||||
{
|
||||
// The first call arrives from Minimize() a moment before the icon is shown — just
|
||||
// record the baseline so the NIM_ADD that immediately follows is our reference.
|
||||
lastRegistrationText = text;
|
||||
return;
|
||||
}
|
||||
if (text == lastRegistrationText) return;
|
||||
// Don't yank the icon out from under an open right-click menu (that would dismiss it
|
||||
// mid-navigation). Leave the record stale so the next tick re-stamps once it closes.
|
||||
if (trayIcon.ContextMenuStrip?.Visible == true) return;
|
||||
lastRegistrationText = text;
|
||||
try
|
||||
{
|
||||
trayIcon.Visible = false;
|
||||
trayIcon.Visible = true;
|
||||
}
|
||||
catch { /* harmless — the 1 Hz snapshot tick will try again next second */ }
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tag_name on the latest GitHub release; bump it on every public release. The
|
||||
AssemblyVersion / FileVersion default to this value, and Assembly.GetName().Version
|
||||
is what the About dialog and the updater both read. -->
|
||||
<Version>3.1.1</Version>
|
||||
<Version>3.1.2</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user