1313using System . Reactive . Linq ;
1414using GitHub . Extensions . Reactive ;
1515using System . Windows . Data ;
16- using System . ComponentModel ;
1716using GitHub . Collections ;
1817using System . Windows . Input ;
1918using GitHub . UI ;
19+ using System . Windows . Media . Imaging ;
2020
2121namespace GitHub . ViewModels
2222{
@@ -27,6 +27,8 @@ public class PullRequestListViewModel : BaseViewModel, IPullRequestListViewModel
2727 readonly ReactiveCommand < object > openPullRequestCommand ;
2828 readonly IRepositoryHost repositoryHost ;
2929 readonly ISimpleRepositoryModel repository ;
30+ readonly TrackingCollection < IAccount > trackingAuthors ;
31+ readonly TrackingCollection < IAccount > trackingAssignees ;
3032
3133 [ ImportingConstructor ]
3234 PullRequestListViewModel (
@@ -46,30 +48,68 @@ public PullRequestListViewModel(IRepositoryHost repositoryHost, ISimpleRepositor
4648 VisualStudio . Services . DefaultExportProvider . GetExportedValue < IVisualStudioBrowser > ( ) . OpenUrl ( repositoryHost . Address . WebUri ) ;
4749 } ) ;
4850
49- var list = new TrackingCollection < IPullRequestModel > ( ) ;
50- list . Comparer = OrderedComparer < IPullRequestModel > . OrderByDescending ( x => x . UpdatedAt ) . Compare ;
51- list . Filter = ( pr , i , l ) => pr . IsOpen ;
52- PullRequests = list ;
51+ States = new List < PullRequestState > {
52+ new PullRequestState { IsOpen = true , Name = "Open" } ,
53+ new PullRequestState { IsOpen = false , Name = "Closed" } ,
54+ new PullRequestState { Name = "All" }
55+ } ;
56+ SelectedState = States [ 0 ] ;
57+
58+ this . WhenAny ( x => x . SelectedState , x => x . Value )
59+ . Where ( x => PullRequests != null )
60+ . Subscribe ( s => UpdateFilter ( s , SelectedAssignee , SelectedAuthor ) ) ;
61+
62+ this . WhenAny ( x => x . SelectedAssignee , x => x . Value )
63+ . Where ( x => PullRequests != null )
64+ . Subscribe ( a => UpdateFilter ( SelectedState , a , SelectedAuthor ) ) ;
65+
66+ this . WhenAny ( x => x . SelectedAuthor , x => x . Value )
67+ . Where ( x => PullRequests != null )
68+ . Subscribe ( a => UpdateFilter ( SelectedState , SelectedAssignee , a ) ) ;
69+
70+ trackingAuthors = new TrackingCollection < IAccount > ( Observable . Empty < IAccount > ( ) ,
71+ OrderedComparer < IAccount > . OrderByDescending ( x => x . Login ) . Compare ) ;
72+ trackingAssignees = new TrackingCollection < IAccount > ( Observable . Empty < IAccount > ( ) ,
73+ OrderedComparer < IAccount > . OrderByDescending ( x => x . Login ) . Compare ) ;
74+ trackingAuthors . Subscribe ( ) ;
75+ trackingAssignees . Subscribe ( ) ;
76+
77+ Authors = trackingAuthors . CreateListenerCollection ( new List < IAccount > { EmptyUser } ) ;
78+ Assignees = trackingAssignees . CreateListenerCollection ( new List < IAccount > { EmptyUser } ) ;
79+
80+ PullRequests = new TrackingCollection < IPullRequestModel > ( ) ;
81+ pullRequests . Comparer = OrderedComparer < IPullRequestModel > . OrderByDescending ( x => x . UpdatedAt ) . Compare ;
82+ pullRequests . Filter = ( pr , i , l ) => pr . IsOpen ;
5383 }
5484
5585 public override void Initialize ( [ AllowNull ] ViewWithData data )
5686 {
5787 base . Initialize ( data ) ;
5888
59- var old = PullRequests ;
60- var list = repositoryHost . ModelService . GetPullRequests ( repository ) ;
61- list . Comparer = old . Comparer ;
62- list . Filter = old . Filter ;
63- PullRequests = list ;
64- list . Subscribe ( ) ;
65- old . Dispose ( ) ;
89+ repositoryHost . ModelService . GetPullRequests ( repository , pullRequests ) ;
90+ pullRequests . Subscribe ( pr =>
91+ {
92+ trackingAssignees . AddItem ( pr . Assignee ) ;
93+ trackingAuthors . AddItem ( pr . Author ) ;
94+ } , ( ) => { } ) ;
6695 }
6796
68- ITrackingCollection < IPullRequestModel > pullRequests ;
69- public ITrackingCollection < IPullRequestModel > PullRequests
97+ void UpdateFilter ( PullRequestState state , [ AllowNull ] IAccount ass , [ AllowNull ] IAccount aut )
7098 {
99+ if ( PullRequests == null )
100+ return ;
101+ pullRequests . Filter = ( pr , i , l ) =>
102+ ( ! state . IsOpen . HasValue || state . IsOpen == pr . IsOpen ) &&
103+ ( ass == null || pr . Assignee == ass ) &&
104+ ( aut == null || pr . Author == aut ) ;
105+ }
106+
107+ TrackingCollection < IPullRequestModel > pullRequests ;
108+ public ObservableCollection < IPullRequestModel > PullRequests
109+ {
110+ [ return : AllowNull ]
71111 get { return pullRequests ; }
72- private set { this . RaiseAndSetIfChanged ( ref pullRequests , value ) ; }
112+ private set { this . RaiseAndSetIfChanged ( ref pullRequests , ( TrackingCollection < IPullRequestModel > ) value ) ; }
73113 }
74114
75115 IPullRequestModel selectedPullRequest ;
@@ -85,5 +125,106 @@ public ICommand OpenPullRequest
85125 {
86126 get { return openPullRequestCommand ; }
87127 }
128+
129+ IReadOnlyList < PullRequestState > states ;
130+ public IReadOnlyList < PullRequestState > States
131+ {
132+ get { return states ; }
133+ set { this . RaiseAndSetIfChanged ( ref states , value ) ; }
134+ }
135+
136+ PullRequestState selectedState ;
137+ public PullRequestState SelectedState
138+ {
139+ get { return selectedState ; }
140+ set { this . RaiseAndSetIfChanged ( ref selectedState , value ) ; }
141+ }
142+
143+ ObservableCollection < IAccount > assignees ;
144+ public ObservableCollection < IAccount > Assignees
145+ {
146+ get { return assignees ; }
147+ set { this . RaiseAndSetIfChanged ( ref assignees , value ) ; }
148+ }
149+
150+ ObservableCollection < IAccount > authors ;
151+ public ObservableCollection < IAccount > Authors
152+ {
153+ get { return authors ; }
154+ set { this . RaiseAndSetIfChanged ( ref authors , value ) ; }
155+ }
156+
157+ IAccount selectedAuthor ;
158+ [ AllowNull ]
159+ public IAccount SelectedAuthor
160+ {
161+ [ return : AllowNull ]
162+ get { return selectedAuthor ; }
163+ set { this . RaiseAndSetIfChanged ( ref selectedAuthor , value ) ; }
164+ }
165+
166+ IAccount selectedAssignee ;
167+ [ AllowNull ]
168+ public IAccount SelectedAssignee
169+ {
170+ [ return : AllowNull ]
171+ get { return selectedAssignee ; }
172+ set { this . RaiseAndSetIfChanged ( ref selectedAssignee , value ) ; }
173+ }
174+
175+ public IAccount EmptyUser
176+ {
177+ get { return new Account ( "[None]" , false , false , 0 , 0 , Observable . Empty < BitmapSource > ( ) ) ; }
178+ }
179+ }
180+
181+ // doing this as an extension because I get the feeling it might be useful in other places
182+ public static class TrackingCollectionExtensions
183+ {
184+ public static ObservableCollection < T > CreateListenerCollection < T > ( this ITrackingCollection < T > tcol ,
185+ IList < T > stickieItemsOnTop = null )
186+ where T : ICopyable < T >
187+ {
188+ var col = new ObservableCollection < T > ( ) ;
189+ tcol . CollectionChanged += ( s , e ) =>
190+ {
191+ var offset = 0 ;
192+ if ( stickieItemsOnTop != null )
193+ {
194+ foreach ( var item in stickieItemsOnTop )
195+ {
196+ if ( col . Contains ( item ) )
197+ offset ++ ;
198+ }
199+ }
200+
201+ if ( e . Action == System . Collections . Specialized . NotifyCollectionChangedAction . Move )
202+ {
203+ for ( int i = 0 , oldIdx = e . OldStartingIndex , newIdx = e . NewStartingIndex ;
204+ i < e . OldItems . Count ; i ++ , oldIdx ++ , newIdx ++ )
205+ col . Move ( oldIdx + offset , newIdx + offset ) ;
206+ }
207+ else if ( e . Action == System . Collections . Specialized . NotifyCollectionChangedAction . Add )
208+ foreach ( T item in e . NewItems )
209+ col . Add ( item ) ;
210+ else if ( e . Action == System . Collections . Specialized . NotifyCollectionChangedAction . Remove )
211+ foreach ( T item in e . OldItems )
212+ col . Remove ( item ) ;
213+ else if ( e . Action == System . Collections . Specialized . NotifyCollectionChangedAction . Replace )
214+ for ( int i = 0 , idx = e . OldStartingIndex ;
215+ i < e . OldItems . Count ; i ++ , idx ++ )
216+ col [ idx + offset ] = ( T ) e . NewItems [ i ] ;
217+ else if ( e . Action == System . Collections . Specialized . NotifyCollectionChangedAction . Reset )
218+ {
219+ col . Clear ( ) ;
220+ if ( stickieItemsOnTop != null )
221+ {
222+ foreach ( var item in stickieItemsOnTop )
223+ col . Add ( item ) ;
224+ }
225+ }
226+ } ;
227+ return col ;
228+ }
88229 }
89230}
0 commit comments