@@ -328,6 +328,11 @@ public partial class MainWindow : Window
328328 private System . Windows . Threading . DispatcherTimer _draftBadgeTimer ;
329329 private TaskDraftManager _draftBadgeManager ;
330330 private UserProfileManager _userProfileManager ;
331+ private bool _proactiveAssistEnabled = true ;
332+ private bool _behaviorLearningEnabled = true ;
333+ private bool _stuckNudgesEnabled = true ;
334+ private int _quietHoursStart = 22 ;
335+ private int _quietHoursEnd = 8 ;
331336 private const int DailyReminderLimit = 3 ;
332337 private static readonly TimeSpan ReminderCooldown = TimeSpan . FromMinutes ( 45 ) ;
333338 private int _remindersShownToday = 0 ;
@@ -561,7 +566,7 @@ public void DataGrid_MouseDoubleClick_AddTask(object sender, MouseButtonEventArg
561566
562567 items . Add ( newTask ) ;
563568 TrackTaskInteraction ( newTask , "progress" ) ;
564- _userProfileManager ? . RecordTaskProgress ( newTask , "manual_create" ) ;
569+ RecordTaskProgressProfile ( newTask , "manual_create" ) ;
565570 for ( int i = 0 ; i < items . Count ; i ++ )
566571 {
567572 items [ i ] . Score = items . Count - i ;
@@ -592,6 +597,7 @@ public MainWindow()
592597
593598 _llmService = LlmService . Create ( ) ;
594599 _userProfileManager = new UserProfileManager ( ) ;
600+ LoadProactiveConfig ( ) ;
595601 UpdateAdaptiveNudgeParameters ( force : true ) ;
596602
597603 var normalizedPosition = NormalizeWindowPosition (
@@ -645,6 +651,104 @@ private void ApplyQuickImprovements()
645651 }
646652 }
647653
654+ private void LoadProactiveConfig ( )
655+ {
656+ _proactiveAssistEnabled = GetAppSettingBool ( "ProactiveAssistEnabled" , true ) ;
657+ _behaviorLearningEnabled = GetAppSettingBool ( "BehaviorLearningEnabled" , true ) ;
658+ _stuckNudgesEnabled = GetAppSettingBool ( "StuckNudgesEnabled" , true ) ;
659+ _quietHoursStart = GetAppSettingInt ( "QuietHoursStart" , 22 , 0 , 23 ) ;
660+ _quietHoursEnd = GetAppSettingInt ( "QuietHoursEnd" , 8 , 0 , 23 ) ;
661+ }
662+
663+ private static bool GetAppSettingBool ( string key , bool defaultValue )
664+ {
665+ string value = ConfigurationManager . AppSettings [ key ] ;
666+ return bool . TryParse ( value , out bool parsed ) ? parsed : defaultValue ;
667+ }
668+
669+ private static int GetAppSettingInt ( string key , int defaultValue , int min , int max )
670+ {
671+ string value = ConfigurationManager . AppSettings [ key ] ;
672+ if ( int . TryParse ( value , out int parsed ) )
673+ {
674+ return Math . Max ( min , Math . Min ( max , parsed ) ) ;
675+ }
676+ return defaultValue ;
677+ }
678+
679+ private bool IsInQuietHours ( DateTime now )
680+ {
681+ if ( _quietHoursStart == _quietHoursEnd )
682+ {
683+ return false ;
684+ }
685+
686+ if ( _quietHoursStart < _quietHoursEnd )
687+ {
688+ return now . Hour >= _quietHoursStart && now . Hour < _quietHoursEnd ;
689+ }
690+
691+ return now . Hour >= _quietHoursStart || now . Hour < _quietHoursEnd ;
692+ }
693+
694+ private bool CanRunProactiveAssist ( DateTime now )
695+ {
696+ return _proactiveAssistEnabled && ! IsInQuietHours ( now ) ;
697+ }
698+
699+ private bool ShouldRecordBehavior ( )
700+ {
701+ return _behaviorLearningEnabled && _userProfileManager != null ;
702+ }
703+
704+ private void RecordTaskProgressProfile ( ItemGrid task , string source )
705+ {
706+ if ( ShouldRecordBehavior ( ) )
707+ {
708+ _userProfileManager . RecordTaskProgress ( task , source ) ;
709+ }
710+ }
711+
712+ private void RecordReminderShownProfile ( ItemGrid task )
713+ {
714+ if ( ShouldRecordBehavior ( ) )
715+ {
716+ _userProfileManager . RecordReminderShown ( task ) ;
717+ }
718+ }
719+
720+ private void RecordReminderResultProfile ( ItemGrid task , TaskReminderResult result )
721+ {
722+ if ( ShouldRecordBehavior ( ) )
723+ {
724+ _userProfileManager . RecordReminderResult ( task , result ) ;
725+ }
726+ }
727+
728+ private void RecordSuggestionShownProfile ( string suggestionId )
729+ {
730+ if ( ShouldRecordBehavior ( ) )
731+ {
732+ _userProfileManager . RecordSuggestionShown ( suggestionId ) ;
733+ }
734+ }
735+
736+ private void RecordSuggestionFeedbackProfile ( string suggestionId , string feedbackType )
737+ {
738+ if ( ShouldRecordBehavior ( ) )
739+ {
740+ _userProfileManager . RecordSuggestionFeedback ( suggestionId , feedbackType ) ;
741+ }
742+ }
743+
744+ private void RecordQuadrantMoveProfile ( ItemGrid task , string sourceQuadrantNumber , string targetQuadrantNumber )
745+ {
746+ if ( ShouldRecordBehavior ( ) )
747+ {
748+ _userProfileManager . RecordQuadrantMove ( task , sourceQuadrantNumber , targetQuadrantNumber ) ;
749+ }
750+ }
751+
648752 private void InitializeDraftBadgeMonitor ( )
649753 {
650754 try
@@ -754,7 +858,7 @@ private async void ShowFriendlyReminder(ItemGrid task, string message)
754858 // Generate AI-powered reminder and suggestions
755859 TimeSpan taskAge = DateTime . Now - task . CreatedDate ;
756860 TimeSpan inactiveDuration = DateTime . Now - task . LastProgressDate ;
757- string reminderContext = _userProfileManager ? . BuildReminderContext ( task , inactiveDuration ) ;
861+ string reminderContext = ShouldRecordBehavior ( ) ? _userProfileManager . BuildReminderContext ( task , inactiveDuration ) : null ;
758862 var ( reminder , suggestions ) = await _llmService . GenerateTaskReminderAsync ( task . Task , taskAge , reminderContext ) ;
759863
760864 // Show modern reminder window
@@ -841,7 +945,7 @@ private async Task HandleTaskReminderResult(ItemGrid task, TaskReminderResult re
841945 break ;
842946 }
843947
844- _userProfileManager ? . RecordReminderResult ( task , result ) ;
948+ RecordReminderResultProfile ( task , result ) ;
845949
846950 // Save changes to CSV
847951 UpdateTaskInAllGrids ( task ) ;
@@ -925,7 +1029,7 @@ private Task AddSubTasksToQuadrants(Dictionary<string, int> taskQuadrantAssignme
9251029
9261030 currentGridItems . Add ( newTask ) ;
9271031 TrackTaskInteraction ( newTask , "progress" ) ;
928- _userProfileManager ? . RecordTaskProgress ( newTask , "decompose_create" ) ;
1032+ RecordTaskProgressProfile ( newTask , "decompose_create" ) ;
9291033 targetGrid . ItemsSource = null ;
9301034 targetGrid . ItemsSource = currentGridItems ;
9311035 RefreshDataGrid ( targetGrid ) ;
@@ -1017,9 +1121,12 @@ private void UpdateAdaptiveNudgeParameters(bool force = false)
10171121
10181122 try
10191123 {
1020- var recommendation = _userProfileManager ? . GetAdaptiveNudgeRecommendation ( 7 ) ;
1124+ var recommendation = ShouldRecordBehavior ( ) ? _userProfileManager . GetAdaptiveNudgeRecommendation ( 7 ) : null ;
10211125 if ( recommendation == null )
10221126 {
1127+ _adaptiveStuckNoProgressThreshold = DefaultStuckNoProgressThreshold ;
1128+ _adaptiveDailyStuckNudgeLimit = DefaultDailyStuckNudgeLimit ;
1129+ _lastAdaptiveTuneAt = now ;
10231130 return ;
10241131 }
10251132
@@ -1051,6 +1158,10 @@ private static TimeSpan ClampThreshold(TimeSpan threshold)
10511158 private void CheckForPotentialStuckTasks ( )
10521159 {
10531160 DateTime now = DateTime . Now ;
1161+ if ( ! _stuckNudgesEnabled || ! CanRunProactiveAssist ( now ) )
1162+ {
1163+ return ;
1164+ }
10541165 if ( _stuckNudgeCounterDate != now . Date )
10551166 {
10561167 _stuckNudgeCounterDate = now . Date ;
@@ -1124,7 +1235,7 @@ private void ShowPassiveStuckSuggestion(ItemGrid task, TimeSpan noProgressDurati
11241235 state . LastSuggestedActionId = suggestion . Id ;
11251236 state . PendingSuggestedActionId = suggestion . Id ;
11261237 state . PendingSuggestedAt = DateTime . Now ;
1127- _userProfileManager ? . RecordSuggestionShown ( suggestion . Id ) ;
1238+ RecordSuggestionShownProfile ( suggestion . Id ) ;
11281239
11291240 var notification = new System . Windows . Forms . NotifyIcon
11301241 {
@@ -1144,7 +1255,7 @@ private void ShowPassiveStuckSuggestion(ItemGrid task, TimeSpan noProgressDurati
11441255
11451256 private UserProfileManager . StuckActionSuggestion BuildStuckNextStep ( ItemGrid task , TimeSpan noProgressDuration , TaskInteractionState state )
11461257 {
1147- var suggestions = _userProfileManager ? . GetRankedStuckSuggestions ( task , noProgressDuration , state ? . LastSuggestedActionId ) ;
1258+ var suggestions = ShouldRecordBehavior ( ) ? _userProfileManager . GetRankedStuckSuggestions ( task , noProgressDuration , state ? . LastSuggestedActionId ) : null ;
11481259 if ( suggestions != null && suggestions . Count > 0 )
11491260 {
11501261 return suggestions [ 0 ] ;
@@ -1226,7 +1337,7 @@ private void TryResolvePendingSuggestionFeedback(TaskInteractionState state, Dat
12261337 return ;
12271338 }
12281339
1229- _userProfileManager ? . RecordSuggestionFeedback ( state . PendingSuggestedActionId , feedbackType ) ;
1340+ RecordSuggestionFeedbackProfile ( state . PendingSuggestedActionId , feedbackType ) ;
12301341 state . PendingSuggestedActionId = null ;
12311342 state . PendingSuggestedAt = null ;
12321343 }
@@ -1260,6 +1371,11 @@ private static string GetTaskTrackingKey(ItemGrid task)
12601371 private Task CheckForStaleTasksAndRemind ( )
12611372 {
12621373 DateTime now = DateTime . Now ;
1374+ if ( ! CanRunProactiveAssist ( now ) )
1375+ {
1376+ return Task . CompletedTask ;
1377+ }
1378+
12631379 if ( _reminderCounterDate != now . Date )
12641380 {
12651381 _reminderCounterDate = now . Date ;
@@ -1274,6 +1390,7 @@ private Task CheckForStaleTasksAndRemind()
12741390 DataGrid [ ] dataGrids = { task1 , task2 , task3 , task4 } ;
12751391 ItemGrid candidate = null ;
12761392 TimeSpan candidateInactive = TimeSpan . Zero ;
1393+ double candidateScore = double . MinValue ;
12771394
12781395 foreach ( var dataGrid in dataGrids )
12791396 {
@@ -1283,10 +1400,15 @@ private Task CheckForStaleTasksAndRemind()
12831400 {
12841401 TimeSpan inactiveDuration = now - task . LastProgressDate ;
12851402
1286- if ( ShouldShowReminder ( task , inactiveDuration , now ) && inactiveDuration > candidateInactive )
1403+ if ( ShouldShowReminder ( task , inactiveDuration , now ) )
12871404 {
1288- candidate = task ;
1289- candidateInactive = inactiveDuration ;
1405+ double score = GetReminderPriorityScore ( task , inactiveDuration ) ;
1406+ if ( candidate == null || score > candidateScore )
1407+ {
1408+ candidate = task ;
1409+ candidateInactive = inactiveDuration ;
1410+ candidateScore = score ;
1411+ }
12901412 }
12911413 }
12921414 }
@@ -1299,7 +1421,7 @@ private Task CheckForStaleTasksAndRemind()
12991421 candidate . LastInteractionDate = now ;
13001422 candidate . LastReminderDate = now ;
13011423 _remindersShownToday ++ ;
1302- _userProfileManager ? . RecordReminderShown ( candidate ) ;
1424+ RecordReminderShownProfile ( candidate ) ;
13031425 UpdateTaskInAllGrids ( candidate ) ;
13041426 }
13051427 return Task . CompletedTask ;
@@ -1333,6 +1455,23 @@ private bool ShouldShowReminder(ItemGrid task, TimeSpan inactiveDuration, DateTi
13331455
13341456 return false ;
13351457 }
1458+
1459+ private static double GetReminderPriorityScore ( ItemGrid task , TimeSpan inactiveDuration )
1460+ {
1461+ double score = inactiveDuration . TotalHours ;
1462+ bool highImportance = string . Equals ( task . Importance , "High" , StringComparison . OrdinalIgnoreCase ) ;
1463+ bool highUrgency = string . Equals ( task . Urgency , "High" , StringComparison . OrdinalIgnoreCase ) ;
1464+
1465+ if ( highImportance && highUrgency ) score += 24 ;
1466+ else if ( highImportance && ! highUrgency ) score += 16 ;
1467+ else if ( ! highImportance && highUrgency ) score += 10 ;
1468+ else score += 4 ;
1469+
1470+ if ( task . InactiveWarningCount == 0 ) score += 2 ;
1471+ if ( task . InactiveWarningCount >= 2 ) score += 1 ;
1472+
1473+ return score ;
1474+ }
13361475
13371476 private string GetReminderMessage ( ItemGrid task , TimeSpan inactiveDuration )
13381477 {
@@ -1628,7 +1767,7 @@ private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventA
16281767 item . InactiveWarningCount = 0 ;
16291768 item . ReminderSnoozeUntil = null ;
16301769 TrackTaskInteraction ( item , "edit" ) ;
1631- _userProfileManager ? . RecordTaskProgress ( item , "manual_edit" ) ;
1770+ RecordTaskProgressProfile ( item , "manual_edit" ) ;
16321771
16331772 Console . WriteLine ( $ "Task edited in grid. Task ID (if available): [{ item . SourceTaskID } ], New Description: [{ newDescription } ]") ;
16341773
@@ -2166,7 +2305,7 @@ private void Quadrant_Drop(object sender, DragEventArgs e)
21662305 if ( ProcessTaskReorder ( draggedItem , sourceList , originalIndex , visualDropIndex ) )
21672306 {
21682307 TrackTaskInteraction ( draggedItem , "reorder" ) ;
2169- _userProfileManager ? . RecordTaskProgress ( draggedItem , "reorder" ) ;
2308+ RecordTaskProgressProfile ( draggedItem , "reorder" ) ;
21702309 RefreshDataGrid ( targetDataGrid ) ;
21712310 string quadrantNumber = GetQuadrantNumber ( targetDataGrid . Name ) ;
21722311 if ( quadrantNumber != null ) update_csv ( targetDataGrid , quadrantNumber ) ;
@@ -2189,7 +2328,7 @@ private void Quadrant_Drop(object sender, DragEventArgs e)
21892328 TrackTaskInteraction ( draggedItem , "move" ) ;
21902329 string sourceQuadrantNumber = GetQuadrantNumber ( _sourceDataGrid . Name ) ;
21912330 string targetQuadrantNumber = GetQuadrantNumber ( targetDataGrid . Name ) ;
2192- _userProfileManager ? . RecordQuadrantMove ( draggedItem , sourceQuadrantNumber , targetQuadrantNumber ) ;
2331+ RecordQuadrantMoveProfile ( draggedItem , sourceQuadrantNumber , targetQuadrantNumber ) ;
21932332
21942333 // Update scores for the source list (optional, but good for consistency if scores mean global order)
21952334 // For now, let's assume scores are quadrant-local unless specified otherwise
@@ -2267,7 +2406,7 @@ private void AddQuickTask_Click(object sender, RoutedEventArgs e)
22672406
22682407 items . Add ( newTask ) ;
22692408 TrackTaskInteraction ( newTask , "progress" ) ;
2270- _userProfileManager ? . RecordTaskProgress ( newTask , "manual_create" ) ;
2409+ RecordTaskProgressProfile ( newTask , "manual_create" ) ;
22712410 // Re-score all items in the list for consistent ordering
22722411 for ( int i = 0 ; i < items . Count ; i ++ )
22732412 {
@@ -2585,7 +2724,7 @@ private async Task HandleNormalGoalCreation(SetLongTermGoalWindow goalDialog)
25852724 }
25862725 quadrantTasks . Add ( newItem ) ;
25872726 TrackTaskInteraction ( newItem , "progress" ) ;
2588- _userProfileManager ? . RecordTaskProgress ( newItem , "goal_plan_create" ) ;
2727+ RecordTaskProgressProfile ( newItem , "goal_plan_create" ) ;
25892728 tasksProcessedCount ++ ;
25902729 }
25912730 HelperClass . WriteCsv ( quadrantTasks , quadrantCsvPath ) ;
0 commit comments