Skip to content

Commit 4fceda1

Browse files
Perf/professional hardening (#4)
* Improve background refresh and process detection * Harden affinity and power plan automation * Fix passive process refresh failures * Improve UX terminology and process layout * Polish UX layout and empty states * Expand core service test coverage
1 parent 2382c47 commit 4fceda1

40 files changed

Lines changed: 3243 additions & 790 deletions

MainWindow.Behaviors.partial.cs

Lines changed: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -782,23 +782,23 @@ private async Task OnMonitoringToggleRequestedAsync(MonitoringToggleEventArgs e)
782782
{
783783
await this.processMonitorManagerService.StartAsync();
784784
await this.notificationService.ShowSuccessNotificationAsync(
785-
"Monitoring Enabled",
786-
"Process monitoring and power plan management has been enabled");
785+
"Automation Monitoring Enabled",
786+
"Process rule automation and power plan management have been enabled.");
787787
}
788788
else
789789
{
790790
await this.processMonitorManagerService.StopAsync();
791791
await this.notificationService.ShowNotificationAsync(
792-
"Monitoring Disabled",
793-
"Process monitoring and power plan management has been disabled",
792+
"Automation Monitoring Disabled",
793+
"Process rule automation and power plan management have been disabled.",
794794
Models.NotificationType.Warning);
795795
}
796796
}
797797
catch (Exception ex)
798798
{
799799
await this.notificationService.ShowErrorNotificationAsync(
800-
"Monitoring Error",
801-
"Failed to toggle process monitoring",
800+
"Automation Monitoring Error",
801+
"Failed to toggle automation monitoring.",
802802
ex);
803803
}
804804
}
@@ -969,10 +969,7 @@ private async Task HandleShortcutActionAsync(string actionName)
969969
{
970970
this.ShowInTaskbar = false;
971971
this.Hide();
972-
this.SuspendHiddenModeRefreshes();
973-
this.processViewModel.PauseRefresh();
974-
this.processViewModel.SetProcessViewActive(false);
975-
_ = this.performanceViewModel.SuspendBackgroundMonitoringAsync();
972+
this.ApplyAppRefreshPolicy(AppActivityState.TrayHidden);
976973
}
977974
else
978975
{
@@ -1273,8 +1270,8 @@ private void OnMonitoringStatusChanged(object? sender, MonitoringStatusEventArgs
12731270
if (e.Error != null && this.settingsService.Settings.EnableErrorNotifications)
12741271
{
12751272
this.notificationService.ShowErrorNotificationAsync(
1276-
"Monitoring Error",
1277-
e.StatusMessage ?? "An error occurred with process monitoring",
1273+
"Automation Monitoring Error",
1274+
e.StatusMessage ?? "An error occurred with automation monitoring.",
12781275
e.Error);
12791276
}
12801277
}
@@ -1288,8 +1285,8 @@ private void OnProcessMonitorManagerStatusChanged(object? sender, ServiceStatusE
12881285
if (!e.IsRunning && e.Error != null && this.settingsService.Settings.EnableErrorNotifications)
12891286
{
12901287
this.notificationService.ShowErrorNotificationAsync(
1291-
"Process Monitoring Error",
1292-
e.Details ?? "Process monitoring manager encountered an error",
1288+
"Automation Monitoring Error",
1289+
e.Details ?? "Automation monitoring encountered an error.",
12931290
e.Error);
12941291
}
12951292
}
@@ -1300,42 +1297,22 @@ protected override void OnStateChanged(EventArgs e)
13001297
{
13011298
if (this.WindowState == WindowState.Minimized)
13021299
{
1300+
var activityState = AppActivityState.Minimized;
13031301
if (this.settingsService.Settings.MinimizeToTray)
13041302
{
13051303
this.ShowInTaskbar = false;
13061304
this.Hide();
13071305
this.systemTrayService.Show();
1306+
activityState = AppActivityState.TrayHidden;
13081307
}
13091308

1310-
this.SuspendHiddenModeRefreshes();
1311-
1312-
if (this.processViewModel != null)
1313-
{
1314-
this.processViewModel.PauseRefresh();
1315-
this.processViewModel.SetProcessViewActive(false);
1316-
}
1317-
1318-
if (this.performanceViewModel != null)
1319-
{
1320-
_ = this.performanceViewModel.SuspendBackgroundMonitoringAsync();
1321-
}
1309+
this.ApplyAppRefreshPolicy(activityState);
13221310
}
13231311
else if (this.WindowState == WindowState.Normal || this.WindowState == WindowState.Maximized)
13241312
{
13251313
this.ShowInTaskbar = true;
13261314

1327-
this.ResumeForegroundRefreshes();
1328-
1329-
if (this.processViewModel != null)
1330-
{
1331-
this.processViewModel.SetProcessViewActive(this.ProcessManagementTab.Visibility == Visibility.Visible);
1332-
this.processViewModel.ResumeRefresh();
1333-
}
1334-
1335-
if (this.performanceViewModel != null)
1336-
{
1337-
_ = this.performanceViewModel.ResumeBackgroundMonitoringAsync();
1338-
}
1315+
this.ApplyAppRefreshPolicy(this.GetForegroundActivityState());
13391316
}
13401317
}
13411318
catch (Exception ex)
@@ -1364,7 +1341,6 @@ private void ResumeForegroundRefreshes()
13641341
this.systemTrayUpdateTimer.Interval = SystemTrayUpdateBaseIntervalMs;
13651342
}
13661343
this.systemTrayUpdateTimer?.Start();
1367-
this.powerPlanViewModel.ResumeAutoRefresh(refreshImmediately: true);
13681344

13691345
_ = this.Dispatcher.InvokeAsync(async () =>
13701346
{
@@ -1380,6 +1356,52 @@ private void ResumeForegroundRefreshes()
13801356
});
13811357
}
13821358

1359+
private AppActivityState GetForegroundActivityState()
1360+
{
1361+
return this.ProcessManagementTab.Visibility == Visibility.Visible
1362+
? AppActivityState.ForegroundProcessView
1363+
: AppActivityState.ForegroundOtherTab;
1364+
}
1365+
1366+
private void ApplyAppRefreshPolicy(AppActivityState state)
1367+
{
1368+
var decision = AppRefreshPolicy.Evaluate(state);
1369+
var isHiddenState = state is AppActivityState.Minimized or AppActivityState.TrayHidden;
1370+
var isProcessViewActive = state == AppActivityState.ForegroundProcessView;
1371+
1372+
if (isHiddenState)
1373+
{
1374+
this.isSystemTrayUpdatesSuspended = true;
1375+
this.systemTrayUpdateTimer?.Stop();
1376+
Interlocked.Exchange(ref this.isSystemTrayUpdateInProgress, 0);
1377+
}
1378+
else
1379+
{
1380+
this.ResumeForegroundRefreshes();
1381+
}
1382+
1383+
this.processViewModel.SetProcessViewActive(isProcessViewActive);
1384+
this.processViewModel.ApplyRefreshDecision(decision);
1385+
1386+
if (decision.PowerPlanUiRefreshEnabled)
1387+
{
1388+
this.powerPlanViewModel.ResumeAutoRefresh(refreshImmediately: state != AppActivityState.ForegroundOtherTab);
1389+
}
1390+
else
1391+
{
1392+
this.powerPlanViewModel.PauseAutoRefresh();
1393+
}
1394+
1395+
if (decision.PerformanceUiMonitoringEnabled)
1396+
{
1397+
_ = this.performanceViewModel.ResumeBackgroundMonitoringAsync();
1398+
}
1399+
else
1400+
{
1401+
_ = this.performanceViewModel.SuspendBackgroundMonitoringAsync();
1402+
}
1403+
}
1404+
13831405
protected override void OnSourceInitialized(EventArgs e)
13841406
{
13851407
base.OnSourceInitialized(e);
@@ -1447,15 +1469,16 @@ private void ShowWindowFromTray(string? tabTag = null)
14471469
this.Activate();
14481470
this.Focus();
14491471
this.Topmost = false;
1472+
this.Activate();
1473+
this.Focus();
14501474

14511475
var processViewWillBeActive = tabTag == null
14521476
? this.ProcessManagementTab.Visibility == Visibility.Visible
14531477
: string.Equals(tabTag, "Process", StringComparison.Ordinal);
14541478

1455-
this.ResumeForegroundRefreshes();
1456-
this.processViewModel.SetProcessViewActive(processViewWillBeActive);
1457-
this.processViewModel.ResumeRefresh();
1458-
_ = this.performanceViewModel.ResumeBackgroundMonitoringAsync();
1479+
this.ApplyAppRefreshPolicy(processViewWillBeActive
1480+
? AppActivityState.ForegroundProcessView
1481+
: AppActivityState.ForegroundOtherTab);
14591482

14601483
if (tabTag != null)
14611484
{
@@ -1664,10 +1687,21 @@ private void ApplySectionVisibility(string tag)
16641687
this.NavTweaks.IsActive = tag == "Tweaks";
16651688
this.NavSettings.IsActive = tag == "Settings";
16661689

1667-
this.processViewModel.SetProcessViewActive(
1668-
string.Equals(tag, "Process", StringComparison.Ordinal) &&
1669-
this.IsVisible &&
1670-
this.WindowState != WindowState.Minimized);
1690+
if (!this.IsVisible)
1691+
{
1692+
this.ApplyAppRefreshPolicy(AppActivityState.TrayHidden);
1693+
return;
1694+
}
1695+
1696+
if (this.WindowState == WindowState.Minimized)
1697+
{
1698+
this.ApplyAppRefreshPolicy(AppActivityState.Minimized);
1699+
return;
1700+
}
1701+
1702+
this.ApplyAppRefreshPolicy(string.Equals(tag, "Process", StringComparison.Ordinal)
1703+
? AppActivityState.ForegroundProcessView
1704+
: AppActivityState.ForegroundOtherTab);
16711705
}
16721706

16731707
private void NavMenuItem_Click(object sender, RoutedEventArgs e)

MainWindow.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@
323323
Margin="0,0,0,6"/>
324324

325325
<TextBlock x:Name="PerformanceIntroTip1"
326-
Text="1. Start monitoring to collect a live snapshot."
326+
Text="1. Start live metrics to collect a current system snapshot."
327327
Foreground="{DynamicResource TextFillColorSecondaryBrush}"
328328
Margin="0,0,0,4"/>
329329
<TextBlock x:Name="PerformanceIntroTip2"

Models/ProcessModel.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ namespace ThreadPilot.Models
2020
using System.Diagnostics;
2121
using CommunityToolkit.Mvvm.ComponentModel;
2222

23+
public enum ProcessClassification
24+
{
25+
ForegroundApp,
26+
VisibleWindowApp,
27+
BackgroundUser,
28+
System,
29+
ProtectedOrAccessDenied,
30+
Terminated,
31+
Unknown,
32+
}
33+
2334
public partial class ProcessModel : ObservableObject
2435
{
2536
[ObservableProperty]
@@ -52,6 +63,12 @@ public partial class ProcessModel : ObservableObject
5263
[ObservableProperty]
5364
private bool hasVisibleWindow;
5465

66+
[ObservableProperty]
67+
private bool isForeground;
68+
69+
[ObservableProperty]
70+
private ProcessClassification classification = ProcessClassification.Unknown;
71+
5572
[ObservableProperty]
5673
private bool isIdleServerDisabled;
5774

0 commit comments

Comments
 (0)