diff --git a/Aurora/Design/Views/BaseViewModel.cs b/Aurora/Design/Views/BaseViewModel.cs
index 48edd6e..b8de4f6 100644
--- a/Aurora/Design/Views/BaseViewModel.cs
+++ b/Aurora/Design/Views/BaseViewModel.cs
@@ -21,8 +21,8 @@ namespace Aurora.Design.Views
///
/// Command event handler for player play button
///
- public virtual void OnPlayExecute() { }
- public virtual bool CanPlayExecute()
+ public virtual void OnPlayButtonExecute() { }
+ public virtual bool CanPlayButtonExecute()
{
return true;
}
@@ -30,8 +30,8 @@ namespace Aurora.Design.Views
///
/// Command event handler for player next button
///
- public virtual void OnNextExecute() { }
- public virtual bool CanNextExecute()
+ public virtual void OnNextButtonExecute() { }
+ public virtual bool CanNextButtonExecute()
{
return true;
}
@@ -39,8 +39,8 @@ namespace Aurora.Design.Views
///
/// Command event handler for player previous button
///
- public virtual void OnPreviousExecute() { }
- public virtual bool CanPreviousExecute()
+ public virtual void OnPreviousButtonExecute() { }
+ public virtual bool CanPreviousButtonExecute()
{
return true;
}
@@ -70,6 +70,8 @@ namespace Aurora.Design.Views
public SetPlayerMetadataDelegate SetPlayerMetadata { get; set; }
+ public SetPlayerVisibleDelegate SetPlayerVisible { get; set; }
+
#endregion Player
#region Lifecycle
diff --git a/Aurora/Design/Views/MainView/MainView.xaml.cs b/Aurora/Design/Views/MainView/MainView.xaml.cs
index d1fae37..9db6227 100644
--- a/Aurora/Design/Views/MainView/MainView.xaml.cs
+++ b/Aurora/Design/Views/MainView/MainView.xaml.cs
@@ -17,17 +17,25 @@ namespace Aurora.Design.Views.Main
///
public delegate void SetPlayerMetadataDelegate(BaseMedia media);
+ public delegate void SetPlayerVisibleDelegate(Boolean visible);
+
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainView : MasterDetailPage, IDisposable
{
private Dictionary _viewModels;
private BaseViewModel _lastViewModel;
+ private Player _player;
+ private ContentPresenter _viewContent;
public MainView()
{
InitializeComponent();
BindingContext = new MainViewModel();
_viewModels = new Dictionary();
+
+ _player = (Player)ContentPage.FindByName("Player");
+ _viewContent = (ContentPresenter)ContentPage.Content.FindByName("ViewContent");
+
MasterPage.ListView.ItemSelected += OnNavItemSelected;
Appearing += OnAppearing;
@@ -84,8 +92,7 @@ namespace Aurora.Design.Views.Main
//Assign player controls to viewmodel
AssignPlayerControls(vm);
- ContentPresenter viewContent = (ContentPresenter)ContentPage.Content.FindByName("ViewContent");
- viewContent.Content = view;
+ _viewContent.Content = view;
MasterPage.ListView.SelectedItem = null;
}
@@ -121,9 +128,7 @@ namespace Aurora.Design.Views.Main
AssignPlayerControls(vm);
vm.OnActive();
-
- ContentPresenter viewContent = (ContentPresenter)ContentPage.Content.FindByName("ViewContent");
- viewContent.Content = view;
+ _viewContent.Content = view;
MasterPage.ListView.SelectedItem = screenList.FirstOrDefault();
}
@@ -135,6 +140,7 @@ namespace Aurora.Design.Views.Main
private void UnassignPlayerControls(BaseViewModel vm)
{
vm.SetPlayerMetadata = null;
+ vm.SetPlayerVisible = null;
}
///
@@ -143,25 +149,37 @@ namespace Aurora.Design.Views.Main
/// BaseViewModel to assign controls to
private void AssignPlayerControls(BaseViewModel vm)
{
- Player player = (Player)ContentPage.FindByName("Player");
- player.PlayButtonCommand = new Command(vm.OnPlayExecute, vm.CanPlayExecute);
- player.NextButtonCommand = new Command(vm.OnNextExecute, vm.CanNextExecute);
- player.PreviousButtonCommand = new Command(vm.OnPreviousExecute, vm.CanPreviousExecute);
+ _player.PlayButtonCommand = new Command(vm.OnPlayButtonExecute, vm.CanPlayButtonExecute);
+ _player.NextButtonCommand = new Command(vm.OnNextButtonExecute, vm.CanNextButtonExecute);
+ _player.PreviousButtonCommand = new Command(vm.OnPreviousButtonExecute, vm.CanPreviousButtonExecute);
//Assign SetPlayer delegate
- vm.SetPlayerMetadata = SetPlayerDelegate;
+ vm.SetPlayerMetadata = SetPlayer;
+ vm.SetPlayerVisible = SetPlayerVisible;
}
- private void SetPlayerDelegate(BaseMedia media)
+ ///
+ /// SetPlayerDelegate implementation
+ ///
+ ///
+ private void SetPlayer(BaseMedia media)
{
- Player player = (Player)ContentPage.FindByName("Player");
if (media.Metadata is AudioMetadata)
{
AudioMetadata meta = (AudioMetadata)media.Metadata;
- player.ArtistName = meta.Artist;
- player.SongTitle = meta.Title;
+ _player.ArtistName = meta.Artist;
+ _player.SongTitle = meta.Title;
}
}
+
+ ///
+ /// SetPlayerVisibleDelegate implementation
+ ///
+ ///
+ private void SetPlayerVisible(Boolean visible)
+ {
+ _player.IsVisible = visible;
+ }
}
}
diff --git a/Aurora/Design/Views/Party/PartyViewModel.cs b/Aurora/Design/Views/Party/PartyViewModel.cs
index e03e642..1f9384a 100644
--- a/Aurora/Design/Views/Party/PartyViewModel.cs
+++ b/Aurora/Design/Views/Party/PartyViewModel.cs
@@ -9,10 +9,12 @@ using Aurora.Proto.Party;
using Aurora.Proto.Events;
using Aurora.Services.ClientService;
using Aurora.Services.PlayerService;
+using Aurora.Services.EventManager;
using Aurora.Models.Media;
namespace Aurora.Design.Views.Party
{
+ //TODO refactor
enum PartyState
{
SelectingHost,
@@ -29,6 +31,7 @@ namespace Aurora.Design.Views.Party
private ObservableCollection _queue;
private BaseMedia _selectedMedia;
private PlayerService _player;
+ private ClientService _client;
public PartyViewModel()
{
@@ -41,10 +44,12 @@ namespace Aurora.Design.Views.Party
SetState(PartyState.SelectingHost);
this._player = PlayerService.Instance;
- PlayCommand = new Command(OnPlayExecute);
+ PlayCommand = new Command(OnDoubleClickExecute, CanDoubleClickExecute);
+
+ _client = ClientService.Instance;
//Hook up event handler
- ClientService.Instance.EventReceived += this.OnEventReceived;
+ _client.EventReceived += this.OnEventReceived;
}
~PartyViewModel()
@@ -198,6 +203,18 @@ namespace Aurora.Design.Views.Party
}
break;
}
+ case BaseEvent.DerivedEventOneofCase.MediaPlayingEvent:
+ {
+ MediaPlayingEvent derivedEvent = eventArgs.BaseEvent.MediaPlayingEvent;
+ Play(derivedEvent);
+ break;
+ }
+ case BaseEvent.DerivedEventOneofCase.MediaPausedEvent:
+ {
+ MediaPausedEvent derivedEvent = eventArgs.BaseEvent.MediaPausedEvent;
+ StopPlaying();
+ break;
+ }
}
}
@@ -207,7 +224,7 @@ namespace Aurora.Design.Views.Party
private async void OnJoinExecute()
{
SetState(PartyState.Connecting);
- ClientService.Instance.Start(Hostname, SettingsService.Instance.DefaultPort.ToString());
+ _client.Start(Hostname, SettingsService.Instance.DefaultPort.ToString());
await JoinParty();
SetState(PartyState.InParty);
@@ -224,13 +241,16 @@ namespace Aurora.Design.Views.Party
SetState(PartyState.Connecting);
ServerService.Instance.Start();
string localHost = ServerService.GetLocalIPAddress();
- ClientService.Instance.Start(localHost, SettingsService.Instance.DefaultPort.ToString());
+ _client.IsHost = true;
+ _client.Start(localHost, SettingsService.Instance.DefaultPort.ToString());
await JoinParty();
+
+ //TODO add cancellation token
try
{
SetState(PartyState.Hosting);
- await ClientService.Instance.GetEvents().ConfigureAwait(true);
+ await _client.GetEvents().ConfigureAwait(true);
}
catch (Exception ex)
{
@@ -243,108 +263,8 @@ namespace Aurora.Design.Views.Party
return true;
}
-
- #endregion Commands
-
- #region Private Methods
- ///
- /// Join the remote party.
- ///
- ///
- private async Task JoinParty()
+ public override void OnPlayButtonExecute()
{
- try
- {
- JoinPartyResponse resp = await ClientService.Instance.RemotePartyClient.JoinPartyAsync(new JoinPartyRequest
- {
- UserName = SettingsService.Instance.Username,
- });
-
- SettingsService.Instance.ClientId = resp.ClientId;
-
- RefreshMembers();
-
- //Subscribe to events
- SubscribeRequest req = new SubscribeRequest();
- req.EventTypes.Add(EventType.PartyMemberJoined);
- req.EventTypes.Add(EventType.PartyMemberLeft);
- if (!string.IsNullOrWhiteSpace(SettingsService.Instance.ClientId))
- {
- req.ClientId = SettingsService.Instance.ClientId;
- }
-
-
- Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", SettingsService.Instance.ClientId));
- ClientService.Instance.RemoteEventClient.SubscribeToEvents(req);
-
- QueueResponse queueResponse = ClientService.Instance.RemotePartyClient.GetQueue(new Empty());
-
- Queue.Clear();
- //Convert received data to remote audio models
- foreach (RemoteMediaData data in queueResponse.MediaList)
- {
- //Assign received metadata (since this can't be aquired from a file)
- AudioMetadata meta = new AudioMetadata();
- meta.Title = data.Title;
- meta.Album = data.Album;
- meta.Artist = data.Artist;
- meta.Duration = data.Duration;
-
- RemoteAudio remote = new RemoteAudio(data.Id,
- meta,
- ClientService.Instance.RemotePartyClient);
-
- Queue.Add(remote);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error subscribing to events: " + ex.Message);
- }
- }
-
- private async Task LeaveParty()
- {
- //Stop receiving events
- ClientService.Instance.StopEvents();
-
- //Unsubscribe
- UnsubscribeAllRequest unsubscribeReq = new UnsubscribeAllRequest();
- await ClientService.Instance.RemoteEventClient.UnsubscribeFromAllAsync(unsubscribeReq);
-
- //Leave party
- LeavePartyRequest leaveReq = new LeavePartyRequest();
- await ClientService.Instance.RemotePartyClient.LeavePartyAsync(leaveReq);
- }
-
- ///
- /// Refresh members list.
- ///
- private void RefreshMembers()
- {
- MembersResponse response = ClientService.Instance.RemotePartyClient.GetPartyMembers(new Empty());
- //Add members
- foreach (PartyMember member in response.Members)
- {
- Members.Add(member);
- }
- }
-
- private void SetState(PartyState state)
- {
- _state = state;
- OnPropertyChanged("IsSelectingHost");
- OnPropertyChanged("IsNotSelectingHost");
- }
-
- public override async void OnPlayExecute()
- {
- base.Media = this._selectedMedia;
- if (!_player.IsMediaLoaded(base.Media))
- {
- await _player.LoadMedia(base.Media).ConfigureAwait(true);
- }
-
_player.Play();
switch (_player.PlaybackState)
{
@@ -361,21 +281,163 @@ namespace Aurora.Design.Views.Party
}
}
- public override bool CanPlayExecute()
+ public override bool CanPlayButtonExecute()
+ {
+ return this._state == PartyState.Hosting && this._player.IsLoaded;
+ }
+
+ public override bool CanNextButtonExecute()
{
return this._state == PartyState.Hosting;
}
- public override bool CanNextExecute()
+ public override bool CanPreviousButtonExecute()
{
return this._state == PartyState.Hosting;
}
- public override bool CanPreviousExecute()
+ ///
+ /// On double click execute, fire media playing event
+ ///
+ public void OnDoubleClickExecute()
+ {
+ AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
+ MediaPlayingEvent mediaPlaying = new MediaPlayingEvent()
+ {
+ Media = new RemoteMediaData()
+ {
+ Id = _selectedMedia.Id,
+ Title = meta.Title,
+ Artist = meta.Artist,
+ Album = meta.Album,
+ }
+ };
+
+ EventManager.Instance.FireEvent(new BaseEvent()
+ {
+ MediaPlayingEvent = mediaPlaying
+ });
+ }
+
+ public bool CanDoubleClickExecute()
{
return this._state == PartyState.Hosting;
}
+
+ #endregion Commands
+
+ #region Private Methods
+ ///
+ /// Join the remote party.
+ ///
+ ///
+ private async Task JoinParty()
+ {
+ try
+ {
+ JoinPartyResponse resp = await _client.RemotePartyClient.JoinPartyAsync(new JoinPartyRequest
+ {
+ UserName = SettingsService.Instance.Username,
+ });
+
+ SettingsService.Instance.ClientId = resp.ClientId;
+
+ RefreshMembers();
+
+ //Subscribe to events
+ SubscribeRequest req = new SubscribeRequest();
+ req.EventTypes.Add(EventType.PartyMemberJoined);
+ req.EventTypes.Add(EventType.PartyMemberLeft);
+ req.EventTypes.Add(EventType.MediaPlaying);
+ req.EventTypes.Add(EventType.MediaStopped);
+ if (!string.IsNullOrWhiteSpace(SettingsService.Instance.ClientId))
+ {
+ req.ClientId = SettingsService.Instance.ClientId;
+ }
+
+
+ Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", SettingsService.Instance.ClientId));
+ _client.RemoteEventClient.SubscribeToEvents(req);
+
+ QueueResponse queueResponse = _client.RemotePartyClient.GetQueue(new Empty());
+
+ Queue.Clear();
+ //Convert received data to remote audio models
+ foreach (RemoteMediaData data in queueResponse.MediaList)
+ {
+ //Assign received metadata (since this can't be aquired from a file)
+ AudioMetadata meta = new AudioMetadata();
+ meta.Title = data.Title;
+ meta.Album = data.Album;
+ meta.Artist = data.Artist;
+ meta.Duration = data.Duration;
+
+ RemoteAudio remote = new RemoteAudio(data.Id,
+ meta,
+ _client.RemotePartyClient);
+
+ Queue.Add(remote);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("Error subscribing to events: " + ex.Message);
+ }
+ }
+
+ private async Task LeaveParty()
+ {
+ //Stop receiving events
+ _client.StopEvents();
+
+ //Unsubscribe
+ UnsubscribeAllRequest unsubscribeReq = new UnsubscribeAllRequest();
+ await _client.RemoteEventClient.UnsubscribeFromAllAsync(unsubscribeReq);
+
+ //Leave party
+ LeavePartyRequest leaveReq = new LeavePartyRequest();
+ await _client.RemotePartyClient.LeavePartyAsync(leaveReq);
+ }
+
+ ///
+ /// Refresh members list.
+ ///
+ private void RefreshMembers()
+ {
+ MembersResponse response = _client.RemotePartyClient.GetPartyMembers(new Empty());
+ //Add members
+ foreach (PartyMember member in response.Members)
+ {
+ Members.Add(member);
+ }
+ }
+
+ private void SetState(PartyState state)
+ {
+ _state = state;
+ OnPropertyChanged("IsSelectingHost");
+ OnPropertyChanged("IsNotSelectingHost");
+ }
+
+ private async void Play(MediaPlayingEvent args)
+ {
+ //TODO this design assumes all played music is in a queue
+ //TODO this is a slow design depending on size of queue
+ if (_queue.Any((BaseMedia media) => media.Id == args.Media.Id))
+ {
+ BaseMedia media = _queue.First((BaseMedia med) => med.Id == args.Media.Id);
+ base.Media = media;
+ await _player.LoadMedia(base.Media).ConfigureAwait(true);
+ _player.Play();
+ }
+ }
+
+ private void StopPlaying()
+ {
+ _player.Pause();
+ }
+
#endregion Private Methods
}
}
\ No newline at end of file
diff --git a/Aurora/Design/Views/Songs/SongsViewModel.cs b/Aurora/Design/Views/Songs/SongsViewModel.cs
index c699361..3798aab 100644
--- a/Aurora/Design/Views/Songs/SongsViewModel.cs
+++ b/Aurora/Design/Views/Songs/SongsViewModel.cs
@@ -20,7 +20,7 @@ namespace Aurora.Design.Views.Songs
{
_player = PlayerService.Instance;
_songsList = new ObservableCollection();
- PlayCommand = new Command(OnPlayExecute, CanPlayExecute);
+ PlayCommand = new Command(OnPlayButtonExecute, CanPlayButtonExecute);
_player.PlaybackStateChanged += OnPlaybackStateChanged;
@@ -56,16 +56,16 @@ namespace Aurora.Design.Views.Songs
#endregion Methods
#region Commmands
- public override bool CanPreviousExecute()
+ public override bool CanPreviousButtonExecute()
{
return true;
}
- public override void OnPreviousExecute()
+ public override void OnPreviousButtonExecute()
{
}
- public override bool CanPlayExecute()
+ public override bool CanPlayButtonExecute()
{
switch (_player.PlaybackState)
{
@@ -85,7 +85,7 @@ namespace Aurora.Design.Views.Songs
return false;
}
- public async override void OnPlayExecute()
+ public async override void OnPlayButtonExecute()
{
base.Media = _selectedSong;
if (!_player.IsMediaLoaded(base.Media))
@@ -109,12 +109,12 @@ namespace Aurora.Design.Views.Songs
}
}
- public override bool CanNextExecute()
+ public override bool CanNextButtonExecute()
{
return true;
}
- public override void OnNextExecute()
+ public override void OnNextButtonExecute()
{
}
diff --git a/Aurora/Proto/events.proto b/Aurora/Proto/events.proto
index f8acbdd..29c6fa7 100644
--- a/Aurora/Proto/events.proto
+++ b/Aurora/Proto/events.proto
@@ -40,6 +40,8 @@ message SubscriptionResponse {
enum EventType {
PartyMemberJoined = 0;
PartyMemberLeft = 1;
+ MediaPlaying = 2;
+ MediaStopped = 3;
}
message BaseEvent {
EventType eventType = 1;
@@ -48,13 +50,23 @@ message BaseEvent {
oneof derivedEvent {
PartyMemberJoinedEvent partyMemberJoinedEvent = 3;
PartyMemberLeftEvent partyMemberLeftEvent = 4;
+ MediaPlayingEvent mediaPlayingEvent = 5;
+ MediaPausedEvent mediaPausedEvent = 6;
}
}
+message MediaPlayingEvent {
+ Aurora.Proto.Party.RemoteMediaData media = 1;
+}
+
+message MediaPausedEvent {
+ Aurora.Proto.General.Empty empty = 1;
+}
+
message PartyMemberJoinedEvent {
- Aurora.Proto.Party.PartyMember member = 3;
+ Aurora.Proto.Party.PartyMember member = 1;
}
message PartyMemberLeftEvent {
- Aurora.Proto.Party.PartyMember member = 3;
+ Aurora.Proto.Party.PartyMember member = 1;
}
\ No newline at end of file
diff --git a/Aurora/Services/ClientService/ClientService.cs b/Aurora/Services/ClientService/ClientService.cs
index 2f72b35..1dd04b4 100644
--- a/Aurora/Services/ClientService/ClientService.cs
+++ b/Aurora/Services/ClientService/ClientService.cs
@@ -17,7 +17,6 @@ namespace Aurora.Services.ClientService
public ClientService()
{
-
}
public EventReceivedEventHandler EventReceived;
@@ -44,6 +43,8 @@ namespace Aurora.Services.ClientService
}
}
+ public bool IsHost { get; set; }
+
public void Start(string hostname, string port)
{
_channel = new Channel(string.Format("{0}:{1}", hostname, port), ChannelCredentials.Insecure);