Skip to content

Commit d7b1584

Browse files
committed
fix remind config
1 parent 419ceee commit d7b1584

5 files changed

Lines changed: 365 additions & 49 deletions

File tree

App.config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@
8181
<add key="BehaviorLearningEnabled" value="true" />
8282
<add key="StuckNudgesEnabled" value="true" />
8383
<add key="LlmSkillAssistEnabled" value="true" />
84+
<!-- 低打断交互:尽量使用轻提示而不是阻塞式确认框 -->
85+
<add key="NonBlockingInteractionEnabled" value="true" />
8486
<add key="EnabledSkillIds" value="decompose,focus_sprint,priority_rebalance,risk_check,delegate_prepare,clarify_goal" />
8587
<!-- 安静时段(24小时制,跨天区间) -->
8688
<add key="QuietHoursStart" value="22" />

MainWindow.xaml.cs

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ public partial class MainWindow : Window
334334
private bool _behaviorLearningEnabled = true;
335335
private bool _stuckNudgesEnabled = true;
336336
private bool _llmSkillAssistEnabled = true;
337+
private bool _nonBlockingInteractionEnabled = true;
337338
private int _quietHoursStart = 22;
338339
private int _quietHoursEnd = 8;
339340
private const int DailyReminderLimit = 3;
@@ -905,6 +906,7 @@ private void LoadProactiveConfig()
905906
_behaviorLearningEnabled = GetAppSettingBool("BehaviorLearningEnabled", true);
906907
_stuckNudgesEnabled = GetAppSettingBool("StuckNudgesEnabled", true);
907908
_llmSkillAssistEnabled = GetAppSettingBool("LlmSkillAssistEnabled", true);
909+
_nonBlockingInteractionEnabled = GetAppSettingBool("NonBlockingInteractionEnabled", true);
908910
_quietHoursStart = GetAppSettingInt("QuietHoursStart", 22, 0, 23);
909911
_quietHoursEnd = GetAppSettingInt("QuietHoursEnd", 8, 0, 23);
910912
}
@@ -1092,6 +1094,16 @@ private void ShowGuidanceNotification(OnboardingScenario scenario)
10921094
return;
10931095
}
10941096

1097+
if (_nonBlockingInteractionEnabled)
1098+
{
1099+
ShowPassiveNotification(
1100+
scenario?.Title ?? "功能引导",
1101+
$"{scenario?.Description}\n已记录本次引导,你可在合适的时候再操作。",
1102+
System.Windows.Forms.ToolTipIcon.Info);
1103+
_smartGuidanceManager.CompleteScenario(scenario.ScenarioId);
1104+
return;
1105+
}
1106+
10951107
var result = MessageBox.Show(
10961108
$"{scenario.Description}\n\n是否现在操作?",
10971109
scenario.Title,
@@ -1142,11 +1154,21 @@ private async Task HandleScenarioActionAsync(OnboardingScenario scenario, bool a
11421154

11431155
if (autoActivated)
11441156
{
1145-
MessageBox.Show(
1146-
"已自动触发一次引导动作,帮助你快速开始使用该功能。你仍可在管理界面中继续调整。",
1147-
scenario.Title,
1148-
MessageBoxButton.OK,
1149-
MessageBoxImage.Information);
1157+
if (_nonBlockingInteractionEnabled)
1158+
{
1159+
ShowPassiveNotification(
1160+
scenario?.Title ?? "功能引导",
1161+
"已自动触发一次引导动作,你可随时继续调整。",
1162+
System.Windows.Forms.ToolTipIcon.Info);
1163+
}
1164+
else
1165+
{
1166+
MessageBox.Show(
1167+
"已自动触发一次引导动作,帮助你快速开始使用该功能。你仍可在管理界面中继续调整。",
1168+
scenario.Title,
1169+
MessageBoxButton.OK,
1170+
MessageBoxImage.Information);
1171+
}
11501172
}
11511173

11521174
_smartGuidanceManager.CompleteScenario(scenario.ScenarioId);
@@ -1285,7 +1307,27 @@ private void ConversationRecorder_ConversationEnded(ConversationSession session)
12851307
private void ShowConversationTasksNotification(ConversationSession session)
12861308
{
12871309
var taskList = string.Join("\n", session.ExtractedTasks.Take(5).Select((t, i) => $"{i + 1}. {t}"));
1288-
1310+
1311+
if (_nonBlockingInteractionEnabled)
1312+
{
1313+
var selectedTasks = session.ExtractedTasks
1314+
.Where(t => !string.IsNullOrWhiteSpace(t))
1315+
.Distinct(StringComparer.OrdinalIgnoreCase)
1316+
.Take(3)
1317+
.ToList();
1318+
1319+
if (selectedTasks.Count > 0)
1320+
{
1321+
AddConversationTasks(selectedTasks);
1322+
ShowPassiveNotification(
1323+
"对话任务识别",
1324+
$"已自动添加 {selectedTasks.Count} 条任务,你可在四象限中随时修改或删除。",
1325+
System.Windows.Forms.ToolTipIcon.Info);
1326+
}
1327+
_conversationRecorder.MarkSessionAsProcessed(session.SessionId);
1328+
return;
1329+
}
1330+
12891331
var result = MessageBox.Show(
12901332
$"从对话中识别到以下任务:\n\n{taskList}\n\n是否添加到任务列表?",
12911333
"对话任务识别",
@@ -1343,6 +1385,16 @@ private void BehaviorObserver_NewInsightGenerated(WorkHabitInsight insight)
13431385

13441386
private void ShowInsightNotification(WorkHabitInsight insight)
13451387
{
1388+
if (_nonBlockingInteractionEnabled)
1389+
{
1390+
_behaviorObserver.AcknowledgeInsight(insight.InsightId);
1391+
ShowPassiveNotification(
1392+
insight?.Title ?? "习惯洞察",
1393+
$"{insight?.Description}\n建议:{insight?.Recommendation}",
1394+
System.Windows.Forms.ToolTipIcon.Info);
1395+
return;
1396+
}
1397+
13461398
var result = MessageBox.Show(
13471399
$"{insight.Description}\n\n建议:{insight.Recommendation}\n\n是否标记为已读?",
13481400
insight.Title,
@@ -1372,6 +1424,16 @@ private void AdaptiveGoalManager_AdjustmentSuggested(GoalAdjustmentSuggestion su
13721424

13731425
private void ShowAdjustmentSuggestionNotification(GoalAdjustmentSuggestion suggestion)
13741426
{
1427+
if (_nonBlockingInteractionEnabled)
1428+
{
1429+
ShowPassiveNotification(
1430+
"目标调整建议",
1431+
$"目标:{suggestion?.GoalDescription}\n建议:{suggestion?.Suggestion}\n已保存建议,可稍后在目标管理中处理。",
1432+
System.Windows.Forms.ToolTipIcon.Warning);
1433+
_behaviorObserver?.RecordSystemEvent("goal_adjustment_notified_passive", $"Goal: {suggestion?.GoalDescription}, Type: {suggestion?.AdjustmentType}");
1434+
return;
1435+
}
1436+
13751437
var result = MessageBox.Show(
13761438
$"目标:{suggestion.GoalDescription}\n\n原因:{suggestion.Reason}\n\n建议:{suggestion.Suggestion}\n\n是否接受此建议?",
13771439
"目标调整建议",
@@ -1893,8 +1955,14 @@ private void UpdateAdaptiveNudgeParameters(bool force = false)
18931955
return;
18941956
}
18951957

1896-
_adaptiveStuckNoProgressThreshold = ClampThreshold(TimeSpan.FromMinutes(recommendation.RecommendedStuckThresholdMinutes));
1897-
_adaptiveDailyStuckNudgeLimit = Math.Max(MinDailyStuckNudgeLimit, Math.Min(MaxDailyStuckNudgeLimit, recommendation.RecommendedDailyNudgeLimit));
1958+
double confidence = Math.Max(0.0, Math.Min(1.0, recommendation.RecommendationConfidence));
1959+
int blendedThresholdMinutes = (int)Math.Round(DefaultStuckNoProgressThreshold.TotalMinutes +
1960+
(recommendation.RecommendedStuckThresholdMinutes - DefaultStuckNoProgressThreshold.TotalMinutes) * confidence);
1961+
int blendedDailyLimit = (int)Math.Round(DefaultDailyStuckNudgeLimit +
1962+
(recommendation.RecommendedDailyNudgeLimit - DefaultDailyStuckNudgeLimit) * confidence);
1963+
1964+
_adaptiveStuckNoProgressThreshold = ClampThreshold(TimeSpan.FromMinutes(blendedThresholdMinutes));
1965+
_adaptiveDailyStuckNudgeLimit = Math.Max(MinDailyStuckNudgeLimit, Math.Min(MaxDailyStuckNudgeLimit, blendedDailyLimit));
18981966
_lastAdaptiveTuneAt = now;
18991967
}
19001968
catch (Exception ex)
@@ -2667,12 +2735,15 @@ private bool TryEditReminderTime(ItemGrid task)
26672735
}
26682736

26692737
DateTime? selected = editor.SelectedReminderTime;
2670-
string confirmText = selected.HasValue
2671-
? $"将“{task.Task}”的提醒时间设为 {selected.Value:yyyy-MM-dd HH:mm},确认吗?"
2672-
: $"将“{task.Task}”的提醒时间清空,确认吗?";
2673-
if (MessageBox.Show(confirmText, "确认提醒时间", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
2738+
if (!_nonBlockingInteractionEnabled)
26742739
{
2675-
return false;
2740+
string confirmText = selected.HasValue
2741+
? $"将“{task.Task}”的提醒时间设为 {selected.Value:yyyy-MM-dd HH:mm},确认吗?"
2742+
: $"将“{task.Task}”的提醒时间清空,确认吗?";
2743+
if (MessageBox.Show(confirmText, "确认提醒时间", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
2744+
{
2745+
return false;
2746+
}
26762747
}
26772748

26782749
task.ReminderTime = selected;
@@ -2681,9 +2752,35 @@ private bool TryEditReminderTime(ItemGrid task)
26812752
task.LastInteractionDate = DateTime.Now;
26822753
TrackTaskInteraction(task, "edit");
26832754
_behaviorObserver?.RecordTaskOperation("update_reminder_time", task.Task, GetTaskTrackingKey(task));
2755+
if (_nonBlockingInteractionEnabled)
2756+
{
2757+
string msg = selected.HasValue
2758+
? $"已更新提醒时间:{selected.Value:yyyy-MM-dd HH:mm}"
2759+
: "已清空提醒时间";
2760+
ShowPassiveNotification("提醒时间已更新", msg, System.Windows.Forms.ToolTipIcon.Info);
2761+
}
26842762
return true;
26852763
}
26862764

2765+
private static void ShowPassiveNotification(string title, string message, System.Windows.Forms.ToolTipIcon icon = System.Windows.Forms.ToolTipIcon.Info, int durationMs = 5000)
2766+
{
2767+
var notification = new System.Windows.Forms.NotifyIcon
2768+
{
2769+
Visible = true,
2770+
Icon = System.Drawing.SystemIcons.Information,
2771+
BalloonTipTitle = string.IsNullOrWhiteSpace(title) ? "TimeTask" : title,
2772+
BalloonTipText = string.IsNullOrWhiteSpace(message) ? "已完成操作" : message,
2773+
BalloonTipIcon = icon
2774+
};
2775+
2776+
notification.ShowBalloonTip(durationMs);
2777+
System.Threading.ThreadPool.QueueUserWorkItem(delegate
2778+
{
2779+
System.Threading.Thread.Sleep(durationMs);
2780+
notification.Dispose();
2781+
});
2782+
}
2783+
26872784
private DataGrid FindSourceGridForTask(ItemGrid task)
26882785
{
26892786
if (task == null)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using System;
3+
using System.IO;
4+
using TimeTask;
5+
6+
namespace TimeTask.Tests
7+
{
8+
[TestClass]
9+
public class UserProfileManagerTests
10+
{
11+
private string _tempRoot;
12+
13+
[TestInitialize]
14+
public void Setup()
15+
{
16+
_tempRoot = Path.Combine(Path.GetTempPath(), "TimeTaskTests", "UserProfileManager", Guid.NewGuid().ToString("N"));
17+
Directory.CreateDirectory(_tempRoot);
18+
}
19+
20+
[TestCleanup]
21+
public void Cleanup()
22+
{
23+
if (Directory.Exists(_tempRoot))
24+
{
25+
Directory.Delete(_tempRoot, true);
26+
}
27+
}
28+
29+
[TestMethod]
30+
public void GetRankedStuckSuggestions_FeedbackImprovesWinningAction()
31+
{
32+
var manager = new UserProfileManager(_tempRoot);
33+
34+
for (int i = 0; i < 8; i++)
35+
{
36+
manager.RecordSuggestionShown("delegate_or_drop");
37+
manager.RecordSuggestionFeedback("delegate_or_drop", "rejected");
38+
manager.RecordSuggestionShown("split_20_min");
39+
manager.RecordSuggestionFeedback("split_20_min", "accepted");
40+
}
41+
42+
var task = new ItemGrid
43+
{
44+
Task = "write document",
45+
Importance = "Low",
46+
Urgency = "High"
47+
};
48+
var ranked = manager.GetRankedStuckSuggestions(task, TimeSpan.FromHours(6));
49+
50+
Assert.IsNotNull(ranked);
51+
Assert.IsTrue(ranked.Count > 0);
52+
Assert.AreEqual("split_20_min", ranked[0].Id, "Accepted action should become top recommendation.");
53+
}
54+
55+
[TestMethod]
56+
public void GetAdaptiveNudgeRecommendation_BadQualityTurnsConservative()
57+
{
58+
var manager = new UserProfileManager(_tempRoot);
59+
60+
for (int i = 0; i < 12; i++)
61+
{
62+
manager.RecordSuggestionShown("start_10_min");
63+
manager.RecordSuggestionFeedback("start_10_min", "rejected");
64+
}
65+
66+
var recommendation = manager.GetAdaptiveNudgeRecommendation(7);
67+
Assert.IsNotNull(recommendation);
68+
Assert.IsTrue(recommendation.RecommendedStuckThresholdMinutes >= 120);
69+
Assert.AreEqual(1, recommendation.RecommendedDailyNudgeLimit);
70+
}
71+
72+
[TestMethod]
73+
public void GetAdaptiveNudgeRecommendation_ConfidenceIncreasesWithSamples()
74+
{
75+
var manager = new UserProfileManager(_tempRoot);
76+
77+
for (int i = 0; i < 10; i++)
78+
{
79+
manager.RecordSuggestionShown("start_10_min");
80+
}
81+
82+
var recommendation = manager.GetAdaptiveNudgeRecommendation(7);
83+
Assert.IsNotNull(recommendation);
84+
Assert.IsTrue(recommendation.RecommendationConfidence >= 0.5 && recommendation.RecommendationConfidence <= 0.6);
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)