public SearchViewModel(IScreen hostScreen, ILoginMethods loginMethods) { HostScreen = hostScreen; SearchResults = new ReactiveCollection<ISongTileViewModel>(); var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { hostScreen.Router.Navigate.Execute(RxApp.GetService<IWelcomeViewModel>()); return; } var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value)); PerformSearch = new ReactiveAsyncCommand(canSearch); this.ObservableForProperty(x => x.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .InvokeCommand(PerformSearch); var searchResults = PerformSearch.RegisterAsyncObservable(_ => playApi.Search(SearchQuery)); SearchResults = searchResults .Do(_ => SearchResults.Clear()) .SelectMany(list => list.ToObservable()) .LoggedCatch(this, Observable.Empty<Song>()) .CreateCollection(x => (ISongTileViewModel) new SongTileViewModel(x, playApi)); PerformSearch.ItemsInflight.StartWith(0) .Select(x => x > 0 ? Visibility.Visible : Visibility.Collapsed) .ToProperty(this, x => x.SearchBusySpinner); PerformSearch.ThrownExceptions.Subscribe(_ => { }); GoBack = new ReactiveCommand(); GoBack.InvokeCommand(hostScreen.Router.NavigateBack); }
public static void LoadAuthenticatedUserFromCache(ILoginMethods login, ISecureBlobCache loginCache) { Observable.Zip(loginCache.GetObjectAsync <string>("BaseUrl"), loginCache.GetObjectAsync <string>("Token"), (url, name) => new Tuple <string, string>(url, name)) .Catch(Observable.Return <Tuple <string, string> >(null)) .Subscribe(x => { }); }
public WelcomeViewModel( IScreen screen, ILoginMethods loginMethods, [Named("connectToServer")][Optional] Func <string, string, IObservable <Unit> > connectToServerMock) { HostScreen = screen; var canOk = this.WhenAny(x => x.BaseUrl, x => x.Token, (b, u) => isValidUrl(b.Value) && !String.IsNullOrWhiteSpace(u.Value)); OkButton = new ReactiveCommand(canOk); OpenTokenPage = new ReactiveCommand(this.WhenAny(x => x.BaseUrl, x => isValidUrl(x.Value))); var connectToServer = connectToServerMock ?? ConnectToPlay; Observable.Defer(() => OkButton.SelectMany(_ => connectToServer(BaseUrl, Token))) .Select(_ => true).Catch(Observable.Return(false)) .Repeat() .Subscribe(result => { if (result == false) { UserError.Throw("Couldn't connect to Play instance."); return; } loginMethods.SaveCredentials(BaseUrl, Token); screen.Router.NavigateBack.Execute(null); }); OpenTokenPage.Subscribe(_ => Process.Start(String.Format("{0}/token", BaseUrl))); var error = new Subject <string>(); UserError.RegisterHandler(ex => { error.OnNext(ex.ErrorMessage); return(Observable.Return(RecoveryOptionResult.CancelOperation)); }); this.WhenAny(x => x.Token, x => x.BaseUrl, (_, __) => Unit.Default) .Subscribe(_ => error.OnNext(null)); error.ToProperty(this, x => x.ErrorMessage); }
public WelcomeViewModel( IScreen screen, ILoginMethods loginMethods, [Named("connectToServer")] [Optional] Func<string, string, IObservable<Unit>> connectToServerMock) { HostScreen = screen; var canOk = this.WhenAny(x => x.BaseUrl, x => x.Token, (b, u) => isValidUrl(b.Value) && !String.IsNullOrWhiteSpace(u.Value)); OkButton = new ReactiveCommand(canOk); OpenTokenPage = new ReactiveCommand(this.WhenAny(x => x.BaseUrl, x => isValidUrl(x.Value))); var connectToServer = connectToServerMock ?? ConnectToPlay; Observable.Defer(() => OkButton.SelectMany(_ => connectToServer(BaseUrl, Token))) .Select(_ => true).Catch(Observable.Return(false)) .Repeat() .Subscribe(result => { if (result == false) { UserError.Throw("Couldn't connect to Play instance."); return; } loginMethods.SaveCredentials(BaseUrl, Token); screen.Router.NavigateBack.Execute(null); }); OpenTokenPage.Subscribe(_ => Process.Start(String.Format("{0}/token", BaseUrl))); var error = new Subject<string>(); UserError.RegisterHandler(ex => { error.OnNext(ex.ErrorMessage); return Observable.Return(RecoveryOptionResult.CancelOperation); }); this.WhenAny(x => x.Token, x => x.BaseUrl, (_, __) => Unit.Default) .Subscribe(_ => error.OnNext(null)); error.ToProperty(this, x => x.ErrorMessage); }
public SearchViewModel(IScreen hostScreen, ILoginMethods loginMethods, [Named("UserAccount")] IBlobCache userCache) { HostScreen = hostScreen; SearchResults = new ReactiveCollection <ISongTileViewModel>(); var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { hostScreen.Router.Navigate.Execute(RxApp.GetService <IWelcomeViewModel>()); return; } var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value)); PerformSearch = new ReactiveAsyncCommand(canSearch); this.ObservableForProperty(x => x.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .InvokeCommand(PerformSearch); var searchResults = PerformSearch.RegisterAsyncObservable(_ => userCache.GetOrFetchObject( "search__" + SearchQuery, () => playApi.Search(SearchQuery), RxApp.TaskpoolScheduler.Now + TimeSpan.FromMinutes(1.0))); SearchResults = searchResults .Do(_ => SearchResults.Clear()) .SelectMany(list => list.ToObservable()) .LoggedCatch(this, Observable.Empty <Song>()) .CreateCollection(x => (ISongTileViewModel) new SongTileViewModel(x, playApi)); PerformSearch.ItemsInflight.StartWith(0) .Select(x => x > 0 ? Visibility.Visible : Visibility.Hidden) .ToProperty(this, x => x.SearchBusySpinner); PerformSearch.ThrownExceptions.Subscribe(_ => { }); GoBack = new ReactiveCommand(); GoBack.InvokeCommand(hostScreen.Router.NavigateBack); }
public PlayViewModel(IScreen screen, ILoginMethods loginMethods) { HostScreen = screen; TogglePlay = new ReactiveCommand(); Logout = new ReactiveCommand(); Search = new ReactiveCommand(); // XXX: God I hate that I have to do this Observable.Never<Song>().ToProperty(this, x => x.CurrentSong); Observable.Never<IEnumerable<Song>>().ToProperty(this, x => x.Queue); Observable.Never<IEnumerable<SongTileViewModel>>().ToProperty(this, x => x.AllSongs); this.WhenNavigatedTo(() => { var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { loginMethods.EraseCredentialsAndNavigateToLogin(); return null; } // Get the Listen URL or die trying Observable.Defer(playApi.ListenUrl) .Timeout(TimeSpan.FromSeconds(30), RxApp.TaskpoolScheduler) .Retry() .ToProperty(this, x => x.ListenUrl); var pusherSubj = playApi.ConnectToSongChangeNotifications() .Retry(25) .Multicast(new Subject<Unit>()); var shouldUpdate = Observable.Defer(() => pusherSubj.Take(1).Timeout(TimeSpan.FromMinutes(2.0), RxApp.TaskpoolScheduler)).Catch(Observable.Return(Unit.Default)) .Repeat() .StartWith(Unit.Default) .Multicast(new Subject<Unit>()); var nowPlaying = shouldUpdate.SelectMany(_ => playApi.NowPlaying()).Multicast(new Subject<Song>()); shouldUpdate.SelectMany(_ => playApi.Queue()) .Catch(Observable.Return(Enumerable.Empty<Song>())) .ToProperty(this, x => x.Queue); nowPlaying .Catch(Observable.Return(new Song())) .ToProperty(this, x => x.CurrentSong); this.WhenAny(x => x.CurrentSong, x => x.Queue, (song, queue) => (queue.Value != null && song.Value != null ? queue.Value.StartWith(song.Value) : Enumerable.Empty<Song>())) .Do(x => this.Log().Info("Found {0} items", x.Count())) .Select(x => x.Select(y => new SongTileViewModel(y, loginMethods.CurrentAuthenticatedClient) { QueueSongVisibility = Visibility.Collapsed })) .ToProperty(this, x => x.AllSongs); MessageBus.Current.RegisterMessageSource(this.WhenAny(x => x.IsPlaying, x => x.Value), "IsPlaying"); var ret = new CompositeDisposable(); ret.Add(nowPlaying.Connect()); ret.Add(shouldUpdate.Connect()); ret.Add(pusherSubj.Connect()); return ret; }); Logout.Subscribe(_ => loginMethods.EraseCredentialsAndNavigateToLogin()); Search.Subscribe(_ => screen.Router.Navigate.Execute(RxApp.GetService<ISearchViewModel>())); }
public UsersController(IUserMethods userMethods, ILoginMethods loginMethods) { _userMethods = userMethods; _loginMethods = loginMethods; }
public PlayViewModel(IScreen screen, ILoginMethods loginMethods) { HostScreen = screen; TogglePlay = new ReactiveCommand(); Logout = new ReactiveCommand(); Search = new ReactiveCommand(); // XXX: God I hate that I have to do this Observable.Never <Song>().ToProperty(this, x => x.CurrentSong); Observable.Never <IEnumerable <Song> >().ToProperty(this, x => x.Queue); Observable.Never <IEnumerable <SongTileViewModel> >().ToProperty(this, x => x.AllSongs); this.WhenNavigatedTo(() => { var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { loginMethods.EraseCredentialsAndNavigateToLogin(); return(null); } // Get the Listen URL or die trying Observable.Defer(playApi.ListenUrl) .Timeout(TimeSpan.FromSeconds(30), RxApp.TaskpoolScheduler) .Retry() .ToProperty(this, x => x.ListenUrl); var pusherSubj = playApi.ConnectToSongChangeNotifications() .Retry(25) .Multicast(new Subject <Unit>()); var shouldUpdate = Observable.Defer(() => pusherSubj.Take(1).Timeout(TimeSpan.FromMinutes(2.0), RxApp.TaskpoolScheduler)).Catch(Observable.Return(Unit.Default)) .Repeat() .StartWith(Unit.Default) .Multicast(new Subject <Unit>()); var nowPlaying = shouldUpdate.SelectMany(_ => playApi.NowPlaying()).Multicast(new Subject <Song>()); shouldUpdate.SelectMany(_ => playApi.Queue()) .Catch(Observable.Return(Enumerable.Empty <Song>())) .ToProperty(this, x => x.Queue); nowPlaying .Catch(Observable.Return(new Song())) .ToProperty(this, x => x.CurrentSong); this.WhenAny(x => x.CurrentSong, x => x.Queue, (song, queue) => (queue.Value != null && song.Value != null ? queue.Value.StartWith(song.Value) : Enumerable.Empty <Song>())) .Do(x => this.Log().Info("Found {0} items", x.Count())) .Select(x => x.Select(y => new SongTileViewModel(y, loginMethods.CurrentAuthenticatedClient) { QueueSongVisibility = Visibility.Collapsed })) .ToProperty(this, x => x.AllSongs); MessageBus.Current.RegisterMessageSource(this.WhenAny(x => x.IsPlaying, x => x.Value), "IsPlaying"); var ret = new CompositeDisposable(); ret.Add(nowPlaying.Connect()); ret.Add(shouldUpdate.Connect()); ret.Add(pusherSubj.Connect()); return(ret); }); Logout.Subscribe(_ => loginMethods.EraseCredentialsAndNavigateToLogin()); Search.Subscribe(_ => screen.Router.Navigate.Execute(RxApp.GetService <ISearchViewModel>())); }
public static void LoadAuthenticatedUserFromCache(ILoginMethods login, ISecureBlobCache loginCache) { Observable.Zip(loginCache.GetObjectAsync<string>("BaseUrl"), loginCache.GetObjectAsync<string>("Token"), (url, name) => new Tuple<string, string>(url, name)) .Catch(Observable.Return<Tuple<string, string>>(null)) .Subscribe(x => { }); }