Skip to content

Commit

Permalink
Added CastButton, CastDialog and ChromecastService
Browse files Browse the repository at this point in the history
  • Loading branch information
Tapanila committed Mar 9, 2016
1 parent 006dd02 commit 555d889
Show file tree
Hide file tree
Showing 11 changed files with 1,412 additions and 128 deletions.
13 changes: 2 additions & 11 deletions SharpCaster.Simple/MainPage.xaml
Expand Up @@ -5,6 +5,7 @@
xmlns:local="using:SharpCaster.Simple"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controllers="using:SharpCaster.Controllers"
mc:Ignorable="d">

<Grid>
Expand All @@ -16,7 +17,7 @@
Grid.Row="0"
Orientation="Horizontal"
>
<Button Content="Connect" Click="ConnectClicked"/>
<controllers:CastButton ChromecastService="{Binding ChromecastService}" />
<Button Content="Launch application" Click="LaunchApplication" />
<Button Content="Stop Application" Click="StopApplication" />
<Button Content="Load media" Click="LoadMedia" />
Expand All @@ -25,15 +26,5 @@
<Button Content="Seek to 90 seconds" Click="Seek" />
<Slider Maximum="100" LargeChange="10" SmallChange="1" Width="100" Value="{Binding Volume}" ValueChanged="Slider_ValueChanged" />
</StackPanel>
<ListView Margin="14" Grid.Row="1" ItemsSource="{Binding Chromecasts}" SelectedItem="{Binding SelectedChromecast, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="4">
<TextBlock Text="{Binding FriendlyName}"/>
<TextBlock Text="{Binding DeviceUri}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
12 changes: 1 addition & 11 deletions SharpCaster.Simple/MainPage.xaml.cs
Expand Up @@ -12,18 +12,8 @@ public MainPage()
InitializeComponent();
MainPageViewModel = new MainPageViewModel();
DataContext = MainPageViewModel;
Loaded += MainPage_Loaded;
}

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
MainPageViewModel.StartLocating();
}

private async void ConnectClicked(object sender, RoutedEventArgs e)
{
await MainPageViewModel.Connect();
}


private async void LaunchApplication(object sender, RoutedEventArgs e)
{
Expand Down
99 changes: 18 additions & 81 deletions SharpCaster.Simple/MainPageViewModel.cs
Expand Up @@ -16,34 +16,11 @@ namespace SharpCaster.Simple
{
public class MainPageViewModel : INotifyPropertyChanged
{
readonly ChromecastService _chromecastService = ChromecastService.Current;
public event PropertyChangedEventHandler PropertyChanged;
private ChromeCastClient _client;
private CancellationTokenSource _cancellationTokenSource;
private DeviceLocator _deviceLocator;

public ObservableCollection<Chromecast> Chromecasts
{
get { return _chromecasts; }
set
{
_chromecasts = value;
OnPropertyChanged();
}
}

private ObservableCollection<Chromecast> _chromecasts;

public Chromecast SelectedChromecast
{
get { return _selectedChromecast; }
set
{
_selectedChromecast = value;
OnPropertyChanged();
}
}

private Chromecast _selectedChromecast;


public ChromecastService ChromecastService => _chromecastService;

public double Volume
{
Expand All @@ -66,33 +43,9 @@ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName

public MainPageViewModel()
{
_deviceLocator = new DeviceLocator();
_cancellationTokenSource = new CancellationTokenSource();
_chromecasts = new ObservableCollection<Chromecast>();
}

public async void StartLocating()
{
//We want to be alerted as soon as we found one device so we use the event
_deviceLocator.DeviceFounded += DeviceLocator_DeviceFounded;
await _deviceLocator.LocateDevicesAsync(_cancellationTokenSource.Token);
}
private async void DeviceLocator_DeviceFounded(object sender, Chromecast e)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Chromecasts.Add(e);
});
}


private void ConnectToChromecast(Chromecast chromecast)
{
_client = new ChromeCastClient();
_client.Connected += Client_Connected;
_client.ApplicationStarted += Client_ApplicationStarted;
_client.ConnectChromecast(chromecast.DeviceUri);
_client.VolumeChanged += _client_VolumeChanged;
_chromecastService.StartLocatingDevices();
_chromecastService.ChromeCastClient.ApplicationStarted += Client_ApplicationStarted;
_chromecastService.ChromeCastClient.VolumeChanged += _client_VolumeChanged;
}

private async void _client_VolumeChanged(object sender, Volume e)
Expand All @@ -105,25 +58,9 @@ private async void Client_ApplicationStarted(object sender, Models.ChromecastSta
await ShowMessage($"Application {e.DisplayName} has launched");
}

private async void Client_Connected(object sender, EventArgs e)
{
await ShowMessage("Connection established");
}


public async Task Connect()
{
if (SelectedChromecast == null)
{
await ShowMessage("You must first select chromecast");
return;
}
ConnectToChromecast(SelectedChromecast);
}

public async Task LaunchApplication()
{
await _client.LaunchApplication("B3419EF5");
await _chromecastService.ChromeCastClient.LaunchApplication("B3419EF5");
}

private async Task ShowMessage(string message)
Expand All @@ -143,45 +80,45 @@ private static async Task ExecuteOnUiThread(DispatchedHandler yourAction)

public async Task PlayPause()
{
if (_client.MediaStatus.PlayerState == PlayerState.Paused)
if (_chromecastService.ChromeCastClient.MediaStatus.PlayerState == PlayerState.Paused)
{
await _client.Play();
await _chromecastService.ChromeCastClient.Play();
}
else
{
await _client.Pause();
await _chromecastService.ChromeCastClient.Pause();
}
}

public async Task Pause()
{
await _client.Pause();
await _chromecastService.ChromeCastClient.Pause();
}

public async Task LoadMedia()
{
await _client.LoadMedia("http://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/dash/BigBuckBunny.mpd");
await _chromecastService.ChromeCastClient.LoadMedia("http://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/dash/BigBuckBunny.mpd");
}

public async Task Seek(double seconds)
{
await _client.Seek(seconds);
await _chromecastService.ChromeCastClient.Seek(seconds);
}

public async Task MuteUnmute()
{
await _client.SetMute(!_client.Volume.muted);
await _chromecastService.ChromeCastClient.SetMute(!_chromecastService.ChromeCastClient.Volume.muted);
}

public async Task SetVolume(double newValue)
{
if (Math.Abs(_client.Volume.level - (newValue/100)) < 0.01) return;
await _client.SetVolume((float) (newValue / 100));
if (Math.Abs(_chromecastService.ChromeCastClient.Volume.level - (newValue/100)) < 0.01) return;
await _chromecastService.ChromeCastClient.SetVolume((float) (newValue / 100));
}

public async Task StopApplication()
{
await _client.StopApplication();
await _chromecastService.ChromeCastClient.StopApplication();
}
}
}
1 change: 1 addition & 0 deletions SharpCaster.sln.DotSettings
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=SharpCaster_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/CodeAnnotations/NamespacesWithAnnotations/=SharpCaster_002ESimple_002EAnnotations/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
Expand Down
68 changes: 68 additions & 0 deletions SharpCaster/ChromecastService.cs
@@ -0,0 +1,68 @@
using System.Threading;
using System.Threading.Tasks;
using SharpCaster.Controllers;
using SharpCaster.Models;

namespace SharpCaster
{
public class ChromecastService
{
private static ChromecastService _instance;

public static ChromecastService Current
{
get
{
if (_instance == null)
{
_instance = new ChromecastService();
}
return _instance;
}
}

public DeviceLocator DeviceLocator { get; }
public ChromeCastClient ChromeCastClient { get; }
public Chromecast ConnectedChromecast { get; set; }
public CastButton CastButton { get; set; }
private CancellationTokenSource _cancellationTokenSource;

public ChromecastService()
{
DeviceLocator = new DeviceLocator();
DeviceLocator.DeviceFounded += DeviceLocator_DeviceFounded;
ChromeCastClient = new ChromeCastClient();
ChromeCastClient.Connected += ChromeCastClient_Connected;

}

private void DeviceLocator_DeviceFounded(object sender, Chromecast e)
{
CastButton?.GoToState(CastButtonVisualStates.InteractiveStates.Disconnected);
}

public void ConnectToChromecast(Chromecast chromecast)
{
CastButton?.GoToState(CastButtonVisualStates.InteractiveStates.Connecting);
StopLocatingDevices();
ConnectedChromecast = chromecast;
ChromeCastClient.ConnectChromecast(chromecast.DeviceUri);
}

private void ChromeCastClient_Connected(object sender, System.EventArgs e)
{
CastButton?.GoToState(CastButtonVisualStates.InteractiveStates.Connected);
}

public void StopLocatingDevices()
{
_cancellationTokenSource.Cancel();
}

public async Task StartLocatingDevices()
{
_cancellationTokenSource = new CancellationTokenSource();
await DeviceLocator.LocateDevicesAsync(_cancellationTokenSource.Token);
}
}
}
93 changes: 93 additions & 0 deletions SharpCaster/Controllers/CastButton.cs
@@ -0,0 +1,93 @@
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Shapes;

namespace SharpCaster.Controllers
{
public class CastButton : Control
{
public static readonly DependencyProperty ChromecastServiceProperty = DependencyProperty.Register("ChromecastService", typeof(ChromecastService), typeof(CastButton), new PropertyMetadata(null));

public ChromecastService ChromecastService
{
get { return (ChromecastService)GetValue(ChromecastServiceProperty); }
set { SetValue(ChromecastServiceProperty, value); }
}

public static readonly DependencyProperty CastDialogProperty = DependencyProperty.Register("CastDialog", typeof(CastDialog), typeof(CastButton), new PropertyMetadata(null));

public CastDialog CastDialog
{
get { return (CastDialog) GetValue(CastDialogProperty); }
set { SetValue(CastDialogProperty, value); }
}

private Popup _popup;


public CastButton()
{
DefaultStyleKey = typeof(CastButton);
}

protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var castIcon = GetTemplateChild("CastIcon") as Path;
if (ChromecastService != null) ChromecastService.CastButton = this;
if (castIcon != null) Tapped += CastIcon_Tapped;
VisualStateManager.GoToState(this, CastButtonVisualStates.InteractiveStates.Unavailable.ToString(), true);
}

private void CastIcon_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
if (CastDialog == null) CastDialog = new CastDialog {ChromecastService = ChromecastService};
if (_popup != null)
{
CastDialog.Visibility = Visibility.Visible;
return;
}
_popup = new Popup
{
Child = CastDialog,
IsOpen = true,
HorizontalAlignment = HorizontalAlignment.Center
};
}


private static async Task ExecuteOnUiThread(DispatchedHandler yourAction)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, yourAction);
}

public async Task GoToState(CastButtonVisualStates.InteractiveStates state)
{
await ExecuteOnUiThread(() =>
{
VisualStateManager.GoToState(this, state.ToString(), true);
});

}
}
public static class CastButtonVisualStates
{
internal static class GroupNames
{
internal const string InteractiveStates = "InteractiveStates";
}

public enum InteractiveStates
{
Unavailable,
Disconnected,
Connecting,
Connected
}
}
}

0 comments on commit 555d889

Please sign in to comment.