Footer shows recording drive free space
Some checks failed
CI / build-and-test (push) Failing after 32s
Some checks failed
CI / build-and-test (push) Failing after 32s
Operators recording long shows previously had to open File Explorer to check disk pressure. New '· 245 GB free' indicator next to the REC badge polls DriveInfo on the recording drive at the existing 1Hz stats tick. Coral tint kicks in below 10GB; existing DiskSpaceWatcher still auto-disables recording at 1GB as a hard safety net. FormatBytes helper produces footer-readable strings: '1.2 TB' / '245 GB' (no decimal for 100+ GB to avoid clutter) / '8.4 GB' (decimal for the low-warning case) / '450 MB'. Polling is wrapped in try/catch — network paths occasionally throw, and disk-space display is a comfort feature, not a critical signal.
This commit is contained in:
parent
61dce2eecd
commit
5c491c9d83
2 changed files with 86 additions and 1 deletions
|
|
@ -367,12 +367,33 @@
|
|||
<TextBlock Style="{StaticResource Wd.Text.Mono}"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource Wd.Accent.Coral}"
|
||||
VerticalAlignment="Center">
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,8,0">
|
||||
<Run Text="REC "/>
|
||||
<Run Text="{Binding ActiveRecordingCount, Mode=OneWay}"/>
|
||||
<Run Text=" · "/>
|
||||
<Run Text="{Binding RecordingElapsed, Mode=OneWay}"/>
|
||||
</TextBlock>
|
||||
<!-- Free disk space on the recording drive. Coral
|
||||
tint kicks in below 10GB; existing DiskSpaceWatcher
|
||||
auto-disables recording at 1GB. -->
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
ToolTip="Free disk space on the recording drive. Recording auto-disables when free space drops below 1GB.">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock" BasedOn="{StaticResource Wd.Text.Mono}">
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource Wd.Text.Tertiary}"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsLowDiskSpace}" Value="True">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Wd.Accent.Coral}"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
<Run Text="· "/>
|
||||
<Run Text="{Binding RecordingFreeSpace, Mode=OneWay}"/>
|
||||
<Run Text=" free"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Control surface badge — cyan dot + REST/OSC string when active -->
|
||||
|
|
|
|||
|
|
@ -221,6 +221,26 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||
private string _recordingElapsed = string.Empty;
|
||||
private DateTimeOffset? _recordingStartedAt;
|
||||
|
||||
/// <summary>
|
||||
/// Free disk space on the recording drive, formatted as "245 GB" /
|
||||
/// "1.2 TB" / "8.4 GB". Empty when recording isn't enabled or the
|
||||
/// recording path is invalid. Polled at the existing 1Hz stats tick.
|
||||
/// </summary>
|
||||
public string RecordingFreeSpace
|
||||
{
|
||||
get => _recordingFreeSpace;
|
||||
private set => SetField(ref _recordingFreeSpace, value);
|
||||
}
|
||||
private string _recordingFreeSpace = string.Empty;
|
||||
|
||||
/// <summary>True when free disk space drops below 10GB — UI cues coral.</summary>
|
||||
public bool IsLowDiskSpace
|
||||
{
|
||||
get => _isLowDiskSpace;
|
||||
private set => SetField(ref _isLowDiskSpace, value);
|
||||
}
|
||||
private bool _isLowDiskSpace;
|
||||
|
||||
/// <summary>True when the REST control surface (or OSC bridge, or both) is listening.</summary>
|
||||
public bool IsControlSurfaceRunning
|
||||
{
|
||||
|
|
@ -555,6 +575,23 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||
Toast.Show($"Stopped {enabled.Length} ISO(s)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format a byte count as a human-readable string with 0-1 decimal
|
||||
/// places — e.g. "8.4 GB", "245 GB", "1.2 TB". Optimized for footer
|
||||
/// readability over precision: nobody needs to know it's 245.34 GB.
|
||||
/// </summary>
|
||||
private static string FormatBytes(long bytes)
|
||||
{
|
||||
if (bytes < 0) return "—";
|
||||
const long GB = 1024L * 1024 * 1024;
|
||||
const long TB = GB * 1024;
|
||||
if (bytes >= TB) return $"{bytes / (double)TB:0.0} TB";
|
||||
if (bytes >= GB) return bytes >= 100 * GB
|
||||
? $"{bytes / GB} GB" // 100+ GB: no decimal — clutter
|
||||
: $"{bytes / (double)GB:0.0} GB"; // < 100GB: one decimal for the low-warning case
|
||||
return $"{bytes / 1024 / 1024} MB";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pull the meaningful "meeting title" out of Teams' raw window title.
|
||||
/// Teams uses formats like:
|
||||
|
|
@ -628,11 +665,38 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||
RecordingElapsed = recElapsed.TotalHours >= 1
|
||||
? $"{(int)recElapsed.TotalHours:D2}:{recElapsed.Minutes:D2}:{recElapsed.Seconds:D2}"
|
||||
: $"{recElapsed.Minutes:D2}:{recElapsed.Seconds:D2}";
|
||||
|
||||
// Disk free on the recording drive. DriveInfo is cheap (a
|
||||
// single GetDiskFreeSpaceEx call). We tolerate any failure
|
||||
// path silently — disk-space display is a comfort feature, not
|
||||
// a critical signal, and the existing DiskSpaceWatcher already
|
||||
// handles the auto-disable-at-1GB safety net.
|
||||
try
|
||||
{
|
||||
var dir = Settings.RecordingDirectory;
|
||||
if (!string.IsNullOrEmpty(dir))
|
||||
{
|
||||
var root = System.IO.Path.GetPathRoot(dir);
|
||||
if (!string.IsNullOrEmpty(root))
|
||||
{
|
||||
var drive = new System.IO.DriveInfo(root);
|
||||
if (drive.IsReady)
|
||||
{
|
||||
var freeBytes = drive.AvailableFreeSpace;
|
||||
RecordingFreeSpace = FormatBytes(freeBytes);
|
||||
IsLowDiskSpace = freeBytes < 10L * 1024 * 1024 * 1024; // <10GB
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { /* defensive — drive enumeration occasionally throws on network paths */ }
|
||||
}
|
||||
else
|
||||
{
|
||||
_recordingStartedAt = null;
|
||||
RecordingElapsed = string.Empty;
|
||||
RecordingFreeSpace = string.Empty;
|
||||
IsLowDiskSpace = false;
|
||||
}
|
||||
|
||||
// Session timer — start on first ISO going live, reset when none are
|
||||
|
|
|
|||
Loading…
Reference in a new issue