예제 #1
0
        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);
        }
예제 #2
0
 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 => {
     });
 }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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>()));
        }
예제 #7
0
 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>()));
        }
예제 #9
0
 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 => {
         });
 }