diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fecf40d..b3ac4501 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). end-to-start, eliminating O(n²) array shifting (CQ-001). - **Shortcut Cleaner** — COM objects (`IShellLink`, `IPersistFile`) now released via `Marshal.ReleaseComObject` in finally block (SEC-006). +- **Models** — deduplicated `FormatSize` from `DiskUsageEntry`, `InstalledApp`, + and `ProcessEntry`; all now use `CleanupCategory.HumanSize` (CQ-002). +- **Console** — batch-remove excess lines from end-to-start instead of + repeated `RemoveAt(0)`, reducing O(n) per append to amortized O(1) (CQ-008). ### Security - **Speed Test** — improved download integrity comment and added diff --git a/SysManager/SysManager.Tests/ProcessManagerServiceTests.cs b/SysManager/SysManager.Tests/ProcessManagerServiceTests.cs index ee67a502..ae3d1985 100644 --- a/SysManager/SysManager.Tests/ProcessManagerServiceTests.cs +++ b/SysManager/SysManager.Tests/ProcessManagerServiceTests.cs @@ -117,7 +117,7 @@ public void OpenFileLocation_NonExistentPath_DoesNotThrow() public void ProcessEntry_MemoryDisplay_FormatsCorrectly() { var entry = new ProcessEntry { MemoryBytes = 52_428_800 }; // 50 MB - Assert.Equal("50.0 MB", entry.MemoryDisplay); + Assert.Equal("50 MB", entry.MemoryDisplay); } [Fact] diff --git a/SysManager/SysManager/Models/DiskUsageEntry.cs b/SysManager/SysManager/Models/DiskUsageEntry.cs index 8f05ebe6..f83fd728 100644 --- a/SysManager/SysManager/Models/DiskUsageEntry.cs +++ b/SysManager/SysManager/Models/DiskUsageEntry.cs @@ -21,13 +21,5 @@ public partial class DiskUsageEntry : ObservableObject [ObservableProperty] private bool _isAccessDenied; /// Formatted size for display. - public string SizeDisplay => FormatSize(SizeBytes); - - private static string FormatSize(long bytes) => bytes switch - { - >= 1L << 30 => $"{bytes / (double)(1L << 30):F1} GB", - >= 1L << 20 => $"{bytes / (double)(1L << 20):F1} MB", - >= 1L << 10 => $"{bytes / (double)(1L << 10):F1} KB", - _ => $"{bytes} B" - }; + public string SizeDisplay => CleanupCategory.HumanSize(SizeBytes); } diff --git a/SysManager/SysManager/Models/InstalledApp.cs b/SysManager/SysManager/Models/InstalledApp.cs index 839ff7e7..af493cda 100644 --- a/SysManager/SysManager/Models/InstalledApp.cs +++ b/SysManager/SysManager/Models/InstalledApp.cs @@ -23,13 +23,5 @@ public partial class InstalledApp : ObservableObject [ObservableProperty] private ImageSource? _icon; /// Formatted size for display. - public string SizeDisplay => SizeBytes > 0 ? FormatSize(SizeBytes) : "—"; - - private static string FormatSize(long bytes) => bytes switch - { - >= 1L << 30 => $"{bytes / (double)(1L << 30):F1} GB", - >= 1L << 20 => $"{bytes / (double)(1L << 20):F1} MB", - >= 1L << 10 => $"{bytes / (double)(1L << 10):F1} KB", - _ => $"{bytes} B" - }; + public string SizeDisplay => SizeBytes > 0 ? CleanupCategory.HumanSize(SizeBytes) : "—"; } diff --git a/SysManager/SysManager/Models/ProcessEntry.cs b/SysManager/SysManager/Models/ProcessEntry.cs index 42611cac..9727933d 100644 --- a/SysManager/SysManager/Models/ProcessEntry.cs +++ b/SysManager/SysManager/Models/ProcessEntry.cs @@ -33,13 +33,5 @@ public partial class ProcessEntry : ObservableObject && System.IO.File.Exists(FilePath); /// Formatted memory for display. - public string MemoryDisplay => FormatSize(MemoryBytes); - - private static string FormatSize(long bytes) => bytes switch - { - >= 1L << 30 => $"{bytes / (double)(1L << 30):F1} GB", - >= 1L << 20 => $"{bytes / (double)(1L << 20):F1} MB", - >= 1L << 10 => $"{bytes / (double)(1L << 10):F1} KB", - _ => $"{bytes} B" - }; + public string MemoryDisplay => CleanupCategory.HumanSize(MemoryBytes); } diff --git a/SysManager/SysManager/ViewModels/ConsoleViewModel.cs b/SysManager/SysManager/ViewModels/ConsoleViewModel.cs index 88126016..3c7d0b00 100644 --- a/SysManager/SysManager/ViewModels/ConsoleViewModel.cs +++ b/SysManager/SysManager/ViewModels/ConsoleViewModel.cs @@ -36,7 +36,12 @@ public void Append(PowerShellLine line) lock (_gate) { Lines.Add(line); - while (Lines.Count > MaxLines) Lines.RemoveAt(0); + if (Lines.Count > MaxLines) + { + var excess = Lines.Count - MaxLines; + for (int i = excess - 1; i >= 0; i--) + Lines.RemoveAt(i); + } } }