55using System . Collections . Generic ;
66using System . Reactive ;
77using System . Reactive . Linq ;
8+ using System . Reactive . Subjects ; // Added for Subject
89
910namespace ImageSort . ViewModels ;
1011
@@ -19,33 +20,46 @@ public class ActionsViewModel : ReactiveObject
1920 private readonly ObservableAsPropertyHelper < string > lastUndone ;
2021 public string LastUndone => lastUndone . Value ;
2122
23+ private readonly ObservableAsPropertyHelper < bool > _canUndo ;
24+ public bool CanUndo => _canUndo . Value ;
25+
26+ private readonly ObservableAsPropertyHelper < bool > _canRedo ;
27+ public bool CanRedo => _canRedo . Value ;
28+
2229 public Interaction < string , Unit > NotifyUserOfError { get ; } = new Interaction < string , Unit > ( ) ;
2330
2431 public ReactiveCommand < IReversibleAction , Unit > Execute { get ; }
2532 public ReactiveCommand < Unit , Unit > Undo { get ; }
2633 public ReactiveCommand < Unit , Unit > Redo { get ; }
2734 public ReactiveCommand < Unit , Unit > Clear { get ; }
2835
36+ private readonly Subject < Unit > _historyChangedSignal = new Subject < Unit > ( ) ;
37+
2938 public ActionsViewModel ( )
3039 {
40+ var canUndoObservable = _historyChangedSignal
41+ . Select ( _ => done . Count > 0 )
42+ . StartWith ( done . Count > 0 ) ;
43+
44+ var canRedoObservable = _historyChangedSignal
45+ . Select ( _ => undone . Count > 0 )
46+ . StartWith ( undone . Count > 0 ) ;
47+
3148 Execute = ReactiveCommand . CreateFromTask < IReversibleAction > ( async action =>
3249 {
3350 try
3451 {
3552 action . Act ( ) ;
53+ done . Push ( action ) ;
54+ undone . Clear ( ) ; // Clear redo stack on new action
55+ _historyChangedSignal . OnNext ( Unit . Default ) ;
3656 }
3757 catch ( Exception ex )
3858 {
3959 await NotifyUserOfError . Handle ( Text . CouldNotActErrorText
4060 . Replace ( "{ErrorMessage}" , ex . Message , StringComparison . OrdinalIgnoreCase )
4161 . Replace ( "{ActMessage}" , action . DisplayName , StringComparison . OrdinalIgnoreCase ) ) ;
42-
43- return ;
4462 }
45-
46- done . Push ( action ) ;
47-
48- undone . Clear ( ) ;
4963 } ) ;
5064
5165 Undo = ReactiveCommand . CreateFromTask ( async ( ) =>
@@ -55,65 +69,59 @@ await NotifyUserOfError.Handle(Text.CouldNotActErrorText
5569 try
5670 {
5771 action . Revert ( ) ;
72+ undone . Push ( action ) ;
73+ _historyChangedSignal . OnNext ( Unit . Default ) ;
5874 }
5975 catch ( Exception ex )
6076 {
6177 await NotifyUserOfError . Handle ( Text . CouldNotUndoErrorText
6278 . Replace ( "{ErrorMessage}" , ex . Message , StringComparison . OrdinalIgnoreCase )
6379 . Replace ( "{ActMessage}" , action . DisplayName , StringComparison . OrdinalIgnoreCase ) ) ;
64-
65- return ;
80+ // Signal change even if revert fails, because 'done' stack changed.
81+ _historyChangedSignal . OnNext ( Unit . Default ) ;
6682 }
67-
68- undone . Push ( action ) ;
6983 }
70- } ) ;
84+ } , canUndoObservable ) ;
7185
7286 Redo = ReactiveCommand . CreateFromTask ( async ( ) =>
7387 {
7488 if ( undone . TryPop ( out var action ) )
7589 {
7690 try
7791 {
78- action . Act ( ) ;
92+ action . Act ( ) ; // Re-apply the action
93+ done . Push ( action ) ;
94+ _historyChangedSignal . OnNext ( Unit . Default ) ;
7995 }
8096 catch ( Exception ex )
8197 {
8298 await NotifyUserOfError . Handle ( Text . CouldNotRedoErrorText
8399 . Replace ( "{ErrorMessage}" , ex . Message , StringComparison . OrdinalIgnoreCase )
84100 . Replace ( "{ActMessage}" , action . DisplayName , StringComparison . OrdinalIgnoreCase ) ) ;
85-
86- return ;
101+ // Signal change even if re-act fails, because 'undone' stack changed.
102+ _historyChangedSignal . OnNext ( Unit . Default ) ;
87103 }
88-
89- done . Push ( action ) ;
90104 }
91- } ) ;
105+ } , canRedoObservable ) ;
92106
93107 Clear = ReactiveCommand . Create ( ( ) =>
94108 {
95109 done . Clear ( ) ;
96110 undone . Clear ( ) ;
111+ _historyChangedSignal . OnNext ( Unit . Default ) ;
97112 } ) ;
98113
99- var historyChanges = Execute . Merge ( Undo ) . Merge ( Redo ) . Merge ( Clear ) ;
100-
101- lastDone = historyChanges
102- . Select ( _ =>
103- {
104- if ( done . TryPeek ( out var action ) ) return action . DisplayName ;
114+ _canUndo = canUndoObservable . ToProperty ( this , vm => vm . CanUndo ) ;
115+ _canRedo = canRedoObservable . ToProperty ( this , vm => vm . CanRedo ) ;
105116
106- return null ;
107- } )
117+ lastDone = _historyChangedSignal
118+ . Select ( _ => done . TryPeek ( out var action ) ? action . DisplayName : null )
119+ . StartWith ( done . TryPeek ( out var action ) ? action . DisplayName : null )
108120 . ToProperty ( this , vm => vm . LastDone ) ;
109121
110- lastUndone = historyChanges
111- . Select ( _ =>
112- {
113- if ( undone . TryPeek ( out var action ) ) return action . DisplayName ;
114-
115- return null ;
116- } )
122+ lastUndone = _historyChangedSignal
123+ . Select ( _ => undone . TryPeek ( out var action ) ? action . DisplayName : null )
124+ . StartWith ( undone . TryPeek ( out var undoneAction ) ? undoneAction . DisplayName : null ) // Renamed variable here
117125 . ToProperty ( this , vm => vm . LastUndone ) ;
118126 }
119127}
0 commit comments