1919using NullGuard ;
2020using ReactiveUI ;
2121using Rothko ;
22+ using System . Collections . ObjectModel ;
23+ using GitHub . Collections ;
2224
2325namespace GitHub . ViewModels
2426{
@@ -28,14 +30,12 @@ public class RepositoryCloneViewModel : BaseViewModel, IRepositoryCloneViewModel
2830 {
2931 static readonly Logger log = LogManager . GetCurrentClassLogger ( ) ;
3032
31- readonly IRepositoryHost repositoryHost ;
3233 readonly IRepositoryCloneService cloneService ;
3334 readonly IOperatingSystem operatingSystem ;
3435 readonly INotificationService notificationService ;
3536 readonly IUsageTracker usageTracker ;
36- readonly IReactiveCommand < IReadOnlyList < IRepositoryModel > > loadRepositoriesCommand ;
3737 readonly ReactiveCommand < object > browseForDirectoryCommand = ReactiveCommand . Create ( ) ;
38- readonly ObservableAsPropertyHelper < bool > isLoading ;
38+ bool isLoading ;
3939 readonly ObservableAsPropertyHelper < bool > noRepositoriesFound ;
4040 readonly ObservableAsPropertyHelper < bool > canClone ;
4141 string baseRepositoryPath ;
@@ -58,34 +58,39 @@ public RepositoryCloneViewModel(
5858 INotificationService notificationService ,
5959 IUsageTracker usageTracker )
6060 {
61- this . repositoryHost = repositoryHost ;
6261 this . cloneService = cloneService ;
6362 this . operatingSystem = operatingSystem ;
6463 this . notificationService = notificationService ;
6564 this . usageTracker = usageTracker ;
6665
6766 Title = string . Format ( CultureInfo . CurrentCulture , Resources . CloneTitle , repositoryHost . Title ) ;
68- Repositories = new ReactiveList < IRepositoryModel > ( ) ;
69- loadRepositoriesCommand = ReactiveCommand . CreateAsyncObservable ( OnLoadRepositories ) ;
70- isLoading = this . WhenAny ( x => x . LoadingFailed , x => x . Value )
71- . CombineLatest ( loadRepositoriesCommand . IsExecuting , ( failed , loading ) => ! failed && loading )
72- . ToProperty ( this , x => x . IsLoading ) ;
73- loadRepositoriesCommand . Subscribe ( Repositories . AddRange ) ;
67+
68+ var col = new TrackingCollection < IRepositoryModel > ( filter : FilterRepository ) ;
69+ col = repositoryHost . ModelService . GetRepositories ( col ) as TrackingCollection < IRepositoryModel > ;
70+ col . OriginalCompleted . Subscribe (
71+ _ => { }
72+ , ex =>
73+ {
74+ LoadingFailed = true ;
75+ log . Error ( "Error while loading repositories" , ex ) ;
76+ } ,
77+ ( ) => IsLoading = false
78+ ) ;
79+ col . Subscribe ( _ => IsLoading = true , ( ) => { } ) ;
80+
81+ Repositories = col ;
82+
7483 filterTextIsEnabled = this . WhenAny ( x => x . Repositories . Count , x => x . Value > 0 )
7584 . ToProperty ( this , x => x . FilterTextIsEnabled ) ;
85+
7686 noRepositoriesFound = this . WhenAny ( x => x . FilterTextIsEnabled , x => x . IsLoading , x => x . LoadingFailed
7787 , ( any , loading , failed ) => ! any . Value && ! loading . Value && ! failed . Value )
7888 . ToProperty ( this , x => x . NoRepositoriesFound ) ;
7989
80- var filterResetSignal = this . WhenAny ( x => x . FilterText , x => x . Value )
90+ this . WhenAny ( x => x . FilterText , x => x . Value )
8191 . DistinctUntilChanged ( StringComparer . OrdinalIgnoreCase )
82- . Throttle ( TimeSpan . FromMilliseconds ( 100 ) , RxApp . MainThreadScheduler ) ;
83-
84- FilteredRepositories = Repositories . CreateDerivedCollection (
85- x => x ,
86- filter : FilterRepository ,
87- signalReset : filterResetSignal
88- ) ;
92+ . Throttle ( TimeSpan . FromMilliseconds ( 100 ) , RxApp . MainThreadScheduler )
93+ . Subscribe ( _ => col . Filter = FilterRepository ) ;
8994
9095 var baseRepositoryPath = this . WhenAny (
9196 x => x . BaseRepositoryPath ,
@@ -112,18 +117,7 @@ public RepositoryCloneViewModel(
112117 BaseRepositoryPath = cloneService . DefaultClonePath ;
113118 }
114119
115- IObservable < IReadOnlyList < IRepositoryModel > > OnLoadRepositories ( object value )
116- {
117- return repositoryHost . ModelService . GetRepositories ( )
118- . Catch < IReadOnlyList < IRepositoryModel > , Exception > ( ex =>
119- {
120- log . Error ( "Error while loading repositories" , ex ) ;
121- return Observable . Start ( ( ) => LoadingFailed = true , RxApp . MainThreadScheduler )
122- . Select ( _ => new IRepositoryModel [ ] { } ) ;
123- } ) ;
124- }
125-
126- bool FilterRepository ( IRepositoryModel repo )
120+ bool FilterRepository ( IRepositoryModel repo , int position , IList < IRepositoryModel > list )
127121 {
128122 if ( string . IsNullOrWhiteSpace ( FilterText ) )
129123 return true ;
@@ -177,6 +171,34 @@ bool IsAlreadyRepoAtPath(string path)
177171 return isAlreadyRepoAtPath ;
178172 }
179173
174+ IObservable < Unit > ShowBrowseForDirectoryDialog ( )
175+ {
176+ return Observable . Start ( ( ) =>
177+ {
178+ // We store this in a local variable to prevent it changing underneath us while the
179+ // folder dialog is open.
180+ var localBaseRepositoryPath = BaseRepositoryPath ;
181+ var browseResult = operatingSystem . Dialog . BrowseForDirectory ( localBaseRepositoryPath , Resources . BrowseForDirectory ) ;
182+
183+ if ( ! browseResult . Success )
184+ return ;
185+
186+ var directory = browseResult . DirectoryPath ?? localBaseRepositoryPath ;
187+
188+ try
189+ {
190+ BaseRepositoryPath = directory ;
191+ }
192+ catch ( Exception e )
193+ {
194+ // TODO: We really should limit this to exceptions we know how to handle.
195+ log . Error ( string . Format ( CultureInfo . InvariantCulture ,
196+ "Failed to set base repository path.{0}localBaseRepositoryPath = \" {1}\" {0}BaseRepositoryPath = \" {2}\" {0}Chosen directory = \" {3}\" " ,
197+ System . Environment . NewLine , localBaseRepositoryPath ?? "(null)" , BaseRepositoryPath ?? "(null)" , directory ?? "(null)" ) , e ) ;
198+ }
199+ } , RxApp . MainThreadScheduler ) ;
200+ }
201+
180202 /// <summary>
181203 /// Path to clone repositories into
182204 /// </summary>
@@ -192,26 +214,16 @@ public string BaseRepositoryPath
192214 /// </summary>
193215 public IReactiveCommand < Unit > CloneCommand { get ; private set ; }
194216
195- IReactiveList < IRepositoryModel > repositories ;
217+ ObservableCollection < IRepositoryModel > repositories ;
196218 /// <summary>
197219 /// List of repositories as returned by the server
198220 /// </summary>
199- public IReactiveList < IRepositoryModel > Repositories
221+ public ObservableCollection < IRepositoryModel > Repositories
200222 {
201223 get { return repositories ; }
202224 private set { this . RaiseAndSetIfChanged ( ref repositories , value ) ; }
203225 }
204226
205- IReactiveDerivedList < IRepositoryModel > filteredRepositories ;
206- /// <summary>
207- /// List of repositories as filtered by user
208- /// </summary>
209- public IReactiveDerivedList < IRepositoryModel > FilteredRepositories
210- {
211- get { return filteredRepositories ; }
212- private set { this . RaiseAndSetIfChanged ( ref filteredRepositories , value ) ; }
213- }
214-
215227 IRepositoryModel selectedRepository ;
216228 /// <summary>
217229 /// Selected repository to clone
@@ -244,12 +256,8 @@ public string FilterText
244256
245257 public bool IsLoading
246258 {
247- get { return isLoading . Value ; }
248- }
249-
250- public IReactiveCommand < IReadOnlyList < IRepositoryModel > > LoadRepositoriesCommand
251- {
252- get { return loadRepositoriesCommand ; }
259+ get { return isLoading ; }
260+ private set { this . RaiseAndSetIfChanged ( ref isLoading , value ) ; }
253261 }
254262
255263 public bool LoadingFailed
@@ -278,33 +286,5 @@ public ReactivePropertyValidator<string> BaseRepositoryPathValidator
278286 get ;
279287 private set ;
280288 }
281-
282- IObservable < Unit > ShowBrowseForDirectoryDialog ( )
283- {
284- return Observable . Start ( ( ) =>
285- {
286- // We store this in a local variable to prevent it changing underneath us while the
287- // folder dialog is open.
288- var localBaseRepositoryPath = BaseRepositoryPath ;
289- var browseResult = operatingSystem . Dialog . BrowseForDirectory ( localBaseRepositoryPath , Resources . BrowseForDirectory ) ;
290-
291- if ( ! browseResult . Success )
292- return ;
293-
294- var directory = browseResult . DirectoryPath ?? localBaseRepositoryPath ;
295-
296- try
297- {
298- BaseRepositoryPath = directory ;
299- }
300- catch ( Exception e )
301- {
302- // TODO: We really should limit this to exceptions we know how to handle.
303- log . Error ( string . Format ( CultureInfo . InvariantCulture ,
304- "Failed to set base repository path.{0}localBaseRepositoryPath = \" {1}\" {0}BaseRepositoryPath = \" {2}\" {0}Chosen directory = \" {3}\" " ,
305- System . Environment . NewLine , localBaseRepositoryPath ?? "(null)" , BaseRepositoryPath ?? "(null)" , directory ?? "(null)" ) , e ) ;
306- }
307- } , RxApp . MainThreadScheduler ) ;
308- }
309289 }
310290}
0 commit comments