public ClientLobbyViewModel(IClientConnection clientConnection, INavigationService navigation, IMeetingViewModelFactory meetingFactory) { _clientConnection = clientConnection; _navigation = navigation; // This command should be available when we're not already waiting // but not before we get the Meeting data back. // Check for a non null meeting and make sure WaitingForAgent is false var cmd = new ReactiveCommand(this.WhenAnyValue( vm => vm.WaitingForAgent, vm => vm.Meeting, (wait, mtg) => !wait && mtg != null)); // This is the navigation function. // We want to go to the ClientMeeting screen once the following conditions are met: // 1) We are the Active screen (IsActive == true) // 2) We have the meeting VM back (this gets set as a result of the previous call) // 3) We get the MeetingDetails (non-null). This means the agent hit Start Meeting // // Combine the three things we're observing into an anon type // Then check them against our conditions // If all true, then navigate _navSub = _clientConnection.MeetingDetails .CombineLatest(this.WhenAnyValue(vm => vm.IsActive), this.WhenAnyValue(vm => vm.Meeting), (det, act, mtg) => new { Details = det, IsActive = act, Meeting = mtg }) .Where(t => t.IsActive && t.Details != null && t.Meeting != null) .Subscribe(c => { if (c.Details.MeetingId == Meeting.Id) { Meeting.VideoConf.Config = c.Details; _navigation.Navigate(Screen.ClientMeeting, Meeting); } }); // The command's action will set the WaitingForAgent to true so we can't click // Join again. It will then send the join message to the server _joinMeetingSub = cmd.RegisterAsyncAction(p => { WaitingForAgent = true; ConnectedToMeeting = true; MeetingJoined = true; _clientConnection.JoinMeeting(Meeting.Id); }).Subscribe(); JoinMeetingCommand = cmd; var connectCmd = new ReactiveCommand(this.WhenAnyValue(p => p.MeetingId, p => p.ConnectedToMeeting, p => p.RequestInProgress, (id, connected, requestInProgress) => !string.IsNullOrEmpty(id) && id.Length == 6 && !connected && !requestInProgress)); connectCmd.RegisterAsyncAction(p => { RequestInProgress = true; // Kick off the GetMeetingDetails call // Normally you can't await a task in a ctor, but // Rx solves that by turning it into an Observable. // When we get the meeting DTO back, turn it into a MeetingVM // and expose it as a property here. clientConnection.GetMeetingDetails(MeetingId) .ToObservable() .ObserveOn(RxApp.MainThreadScheduler) .Select(p1 => p1 == null ? null : meetingFactory.Create(p1)) .Subscribe(p1 => { Error = string.Empty; if (p1 == null) { Error = "Meeting with id " + MeetingId + " does not exist."; return; // nothing, meeting doesn't exist } Meeting = p1; RequestInProgress = false; JoinMeetingCommand.Execute(null); }); }); ConnectCommand = connectCmd; var disconnectCmd = new ReactiveCommand(this.WhenAnyValue(p => p.ConnectedToMeeting, p => p.RequestInProgress, (connected, requestInProgress) => connected && !requestInProgress)); disconnectCmd.RegisterAsyncAction(p => { WaitingForAgent = false; ConnectedToMeeting = false; if (MeetingJoined) { _clientConnection.LeaveMeeting(Meeting.Id); MeetingJoined = false; } _clientConnection.LeaveMeeting(Meeting.Id); Meeting = null; }); DisconnectCommand = disconnectCmd; // Update the title based on the waiting status. Once we press the button, go into // "waiting" mode. _titleSub = this.WhenAny(v => v.WaitingForAgent, v => v.Meeting, (waiting, meeting) => { if (meeting.Value == null) { return("Please connect to a meeting"); } return(waiting.Value ? "Waiting for agent to start the meeting" : "Please join the meeting."); }) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(text => Title = text); MeetingId = "64BDF0"; // default to the first meeting for easy testing }
public ClientLobbyViewModel(IClientConnection clientConnection, INavigationService navigation, IMeetingViewModelFactory meetingFactory) { _clientConnection = clientConnection; _navigation = navigation; // This command should be available when we're not already waiting // but not before we get the Meeting data back. // Check for a non null meeting and make sure WaitingForAgent is false var cmd = new ReactiveCommand(this.WhenAnyValue( vm => vm.WaitingForAgent, vm => vm.Meeting, (wait, mtg) => !wait && mtg != null)); // This is the navigation function. // We want to go to the ClientMeeting screen once the following conditions are met: // 1) We are the Active screen (IsActive == true) // 2) We have the meeting VM back (this gets set as a result of the previous call) // 3) We get the MeetingDetails (non-null). This means the agent hit Start Meeting // // Combine the three things we're observing into an anon type // Then check them against our conditions // If all true, then navigate _navSub = _clientConnection.MeetingDetails .CombineLatest(this.WhenAnyValue(vm => vm.IsActive), this.WhenAnyValue(vm => vm.Meeting), (det, act, mtg) => new { Details = det, IsActive = act, Meeting = mtg }) .Where(t => t.IsActive && t.Details != null && t.Meeting != null) .Subscribe(c => { if (c.Details.MeetingId == Meeting.Id) { Meeting.VideoConf.Config = c.Details; _navigation.Navigate(Screen.ClientMeeting, Meeting); } }); // The command's action will set the WaitingForAgent to true so we can't click // Join again. It will then send the join message to the server _joinMeetingSub = cmd.RegisterAsyncAction(p => { WaitingForAgent = true; ConnectedToMeeting = true; MeetingJoined = true; _clientConnection.JoinMeeting(Meeting.Id); }).Subscribe(); JoinMeetingCommand = cmd; var connectCmd = new ReactiveCommand(this.WhenAnyValue(p => p.MeetingId, p => p.ConnectedToMeeting, p => p.RequestInProgress, (id, connected, requestInProgress) => !string.IsNullOrEmpty(id) && id.Length == 6 && !connected && !requestInProgress)); connectCmd.RegisterAsyncAction(p => { RequestInProgress = true; // Kick off the GetMeetingDetails call // Normally you can't await a task in a ctor, but // Rx solves that by turning it into an Observable. // When we get the meeting DTO back, turn it into a MeetingVM // and expose it as a property here. clientConnection.GetMeetingDetails(MeetingId) .ToObservable() .ObserveOn(RxApp.MainThreadScheduler) .Select(p1 => p1 == null ? null : meetingFactory.Create(p1)) .Subscribe(p1 => { Error = string.Empty; if (p1 == null) { Error = "Meeting with id " + MeetingId + " does not exist."; return; // nothing, meeting doesn't exist } Meeting = p1; RequestInProgress = false; JoinMeetingCommand.Execute(null); }); }); ConnectCommand = connectCmd; var disconnectCmd = new ReactiveCommand(this.WhenAnyValue(p => p.ConnectedToMeeting, p => p.RequestInProgress, (connected,requestInProgress) => connected && !requestInProgress)); disconnectCmd.RegisterAsyncAction(p => { WaitingForAgent = false; ConnectedToMeeting = false; if (MeetingJoined) { _clientConnection.LeaveMeeting(Meeting.Id); MeetingJoined = false; } _clientConnection.LeaveMeeting(Meeting.Id); Meeting = null; }); DisconnectCommand = disconnectCmd; // Update the title based on the waiting status. Once we press the button, go into // "waiting" mode. _titleSub = this.WhenAny(v => v.WaitingForAgent, v => v.Meeting, (waiting, meeting) => { if (meeting.Value == null) return "Please connect to a meeting"; return waiting.Value ? "Waiting for agent to start the meeting" : "Please join the meeting."; }) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(text => Title = text); MeetingId = "64BDF0"; // default to the first meeting for easy testing }