Attempts to get horizontal list to work

This commit is contained in:
watsonb8 2019-07-10 17:17:10 -04:00
parent 823e1341ca
commit c99f752174
6 changed files with 190 additions and 125 deletions

View File

@ -1,99 +1,54 @@
<Project <Project Sdk="Microsoft.NET.Sdk">
Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<ProduceAssemblyReference>true</ProduceAssemblyReference> <ProduceAssemblyReference>true</ProduceAssemblyReference>
</PropertyGroup> </PropertyGroup>
<PropertyGroup <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference <PackageReference Include="Xamarin.Forms" Version="3.6.0.264807" />
Include="Xamarin.Forms" <PackageReference Include="Xamarin.Essentials" Version="1.0.1" />
Version="3.6.0.264807"/> <PackageReference Include="Xamarin.Forms.DataGrid" Version="3.1.0" />
<PackageReference <PackageReference Include="taglib-sharp-netstandard2.0" Version="2.1.0" />
Include="Xamarin.Essentials" <PackageReference Include="LibVLCSharp.Forms" Version="3.0.0" />
Version="1.0.1"/> <PackageReference Include="VideoLAN.LibVLC.Mac" Version="3.1.3" />
<PackageReference <PackageReference Include="Grpc" Version="1.21.0" />
Include="Xamarin.Forms.DataGrid" <PackageReference Include="Grpc.Tools" Version="1.21.0" PrivateAssests="All" />
Version="3.1.0"/> <PackageReference Include="Google.Protobuf" Version="3.8.0" />
<PackageReference <PackageReference Include="Xam.Plugins.Settings" Version="3.1.1" />
Include="taglib-sharp-netstandard2.0" <PackageReference Include="Sharpnado.Forms.HorizontalListView" Version="1.2.0" />
Version="2.1.0"/>
<PackageReference
Include="LibVLCSharp.Forms"
Version="3.0.0"/>
<PackageReference
Include="VideoLAN.LibVLC.Mac"
Version="3.1.3"/>
<PackageReference
Include="Grpc"
Version="1.21.0"/>
<PackageReference
Include="Grpc.Tools"
Version="1.21.0"
PrivateAssests="All"/>
<PackageReference
Include="Google.Protobuf"
Version="3.8.0"/>
<PackageReference
Include="Xam.Plugins.Settings"
Version="3.1.1"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder <Folder Include="Design\" />
Include="Design\"/> <Folder Include="Design\Components\" />
<Folder <Folder Include="Design\Views\" />
Include="Design\Components\"/> <Folder Include="Design\Views\Songs\" />
<Folder <Folder Include="Design\Views\MainView\" />
Include="Design\Views\"/> <Folder Include="Design\Behaviors\" />
<Folder <Folder Include="Design\Components\NavigationMenu\" />
Include="Design\Views\Songs\"/> <Folder Include="Design\Views\Albums\" />
<Folder <Folder Include="Design\Views\Artists\" />
Include="Design\Views\MainView\"/> <Folder Include="Design\Views\Stations\" />
<Folder <Folder Include="Utils\" />
Include="Design\Behaviors\"/> <Folder Include="Models\" />
<Folder <Folder Include="Services\" />
Include="Design\Components\NavigationMenu\"/> <Folder Include="Design\Views\Party\" />
<Folder <Folder Include="Design\Components\HostSelector\" />
Include="Design\Views\Albums\"/> <Folder Include="Design\Components\MemberList\" />
<Folder <Folder Include="Design\Components\Queue\" />
Include="Design\Views\Artists\"/> <Folder Include="Design\Views\Profile\" />
<Folder
Include="Design\Views\Stations\"/>
<Folder
Include="Utils\"/>
<Folder
Include="Models\"/>
<Folder
Include="Services\"/>
<Folder
Include="Design\Views\Party\"/>
<Folder
Include="Design\Components\HostSelector\"/>
<Folder
Include="Design\Components\MemberList\"/>
<Folder
Include="Design\Components\Queue\"/>
<Folder
Include="Design\Views\Profile\"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile <Compile Update="Design\Components\MusicPlayer\Player.xaml.cs">
Update="Design\Components\MusicPlayer\Player.xaml.cs">
<DependentUpon>Player.xaml</DependentUpon> <DependentUpon>Player.xaml</DependentUpon>
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Protobuf <Protobuf Include="Proto\general.proto" />
Include="Proto\general.proto"/> <Protobuf Include="Proto\party.proto" />
<Protobuf <Protobuf Include="Proto\playback.proto" />
Include="Proto\party.proto"/> <Protobuf Include="Proto\events.proto" />
<Protobuf
Include="Proto\playback.proto"/>
<Protobuf
Include="Proto\events.proto"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Linq;
using System.Collections.Generic; using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Input; using System.Windows.Input;
using Xamarin.Forms; using Xamarin.Forms;
@ -13,6 +14,7 @@ namespace Aurora.Design.Components.HorizontalList
private readonly StackLayout _itemsStackLayout; private readonly StackLayout _itemsStackLayout;
public event EventHandler SelectedItemChanged; public event EventHandler SelectedItemChanged;
private NotifyCollectionChangedEventHandler _itemsChangedHandler;
public StackOrientation ListOrientation { get; set; } public StackOrientation ListOrientation { get; set; }
@ -22,7 +24,12 @@ namespace Aurora.Design.Components.HorizontalList
BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HorizontalList), null); BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HorizontalList), null);
public static readonly BindableProperty ItemsSourceProperty = public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(HorizontalList), default(IEnumerable<object>), BindingMode.TwoWay, propertyChanged: ItemsSourceChanged); BindableProperty.Create("ItemsSource",
typeof(ObservableCollection<object>),
typeof(HorizontalList),
default(ObservableCollection<object>),
BindingMode.TwoWay,
propertyChanged: ItemsSourceChanged);
public static readonly BindableProperty SelectedItemProperty = public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create("SelectedItem", typeof(object), typeof(HorizontalList), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged); BindableProperty.Create("SelectedItem", typeof(object), typeof(HorizontalList), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
@ -36,9 +43,9 @@ namespace Aurora.Design.Components.HorizontalList
set { SetValue(SelectedCommandProperty, value); } set { SetValue(SelectedCommandProperty, value); }
} }
public IEnumerable ItemsSource public ObservableCollection<object> ItemsSource
{ {
get { return (IEnumerable)GetValue(ItemsSourceProperty); } get { return (ObservableCollection<object>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); } set { SetValue(ItemsSourceProperty, value); }
} }
@ -56,12 +63,13 @@ namespace Aurora.Design.Components.HorizontalList
private static void ItemsSourceChanged(BindableObject bindable, object oldValue, object newValue) private static void ItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{ {
var itemsLayout = (HorizontalList)bindable; HorizontalList itemsLayout = bindable as HorizontalList;
itemsLayout.SetItems(); itemsLayout.SetItems();
} }
public HorizontalList() public HorizontalList()
{ {
_itemsChangedHandler = OnItemsChanged;
// BackgroundColor = Color.FromHex("#1E2634"); // BackgroundColor = Color.FromHex("#1E2634");
Spacing = 6; Spacing = 6;
_scrollView = new ScrollView(); _scrollView = new ScrollView();
@ -78,6 +86,11 @@ namespace Aurora.Design.Components.HorizontalList
Children.Add(_scrollView); Children.Add(_scrollView);
} }
~HorizontalList()
{
ItemsSource.CollectionChanged -= _itemsChangedHandler;
}
protected virtual void SetItems() protected virtual void SetItems()
{ {
_itemsStackLayout.Children.Clear(); _itemsStackLayout.Children.Clear();
@ -99,6 +112,9 @@ namespace Aurora.Design.Components.HorizontalList
return; return;
} }
//Setup collection events
ItemsSource.CollectionChanged += _itemsChangedHandler;
foreach (var item in ItemsSource) foreach (var item in ItemsSource)
{ {
_itemsStackLayout.Children.Add(GetItemView(item)); _itemsStackLayout.Children.Add(GetItemView(item));
@ -127,7 +143,6 @@ namespace Aurora.Design.Components.HorizontalList
}; };
AddGesture(view, gesture); AddGesture(view, gesture);
return view; return view;
} }
@ -164,5 +179,33 @@ namespace Aurora.Design.Components.HorizontalList
itemsView.SelectedCommand?.Execute(newValue); itemsView.SelectedCommand?.Execute(newValue);
} }
} }
private void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
{
foreach (object item in e.NewItems)
{
_itemsStackLayout.Children.Add(GetItemView(item));
}
break;
}
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
{
foreach (object item in e.OldItems)
{
//Clear layout and rebuild
_itemsStackLayout.Children.Clear();
foreach (var source in ItemsSource)
{
_itemsStackLayout.Children.Add(GetItemView(item));
}
}
break;
}
}
}
} }
} }

View File

@ -57,7 +57,7 @@ namespace Aurora.Design.Components.MemberList
if (membersList != null) if (membersList != null)
{ {
_newSource = newValue as ObservableCollection<PartyMember>; _newSource = newValue as ObservableCollection<PartyMember>;
membersList.ItemsSource = newValue as ObservableCollection<PartyMember>; membersList.ItemsSource = newValue as ObservableCollection<object>;
} }
} }
} }

View File

@ -3,7 +3,8 @@
xmlns="http://xamarin.com/schemas/2014/forms" xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:hs="clr-namespace:Aurora.Design.Components.HostSelector" xmlns:hs="clr-namespace:Aurora.Design.Components.HostSelector"
xmlns:ml="clr-namespace:Aurora.Design.Components.MemberList" xmlns:hl="clr-namespace:Aurora.Design.Components.HorizontalList"
xmlns:renderedViews="clr-namespace:Sharpnado.Presentation.Forms.RenderedViews;assembly=Sharpnado.Presentation.Forms"
xmlns:qu="clr-namespace:Aurora.Design.Components.Queue" xmlns:qu="clr-namespace:Aurora.Design.Components.Queue"
x:Class="Aurora.Design.Views.Party.PartyView"> x:Class="Aurora.Design.Views.Party.PartyView">
<ContentView.Content> <ContentView.Content>
@ -17,9 +18,20 @@
IsVisible="{Binding IsNotSelectingHost}"> IsVisible="{Binding IsNotSelectingHost}">
<Label <Label
Text="Party Members"/> Text="Party Members"/>
<ml:MemberList <hl:HorizontalList
VerticalOptions="FillAndExpand" x:Name="MembersHorizontalList"
Members="{Binding Members}"/> ListOrientation="Horizontal"
VerticalOptions="Start"
ItemsSource="{Binding Members}">
<hl:HorizontalList.ItemTemplate>
<DataTemplate>
<Frame>
<Label
Text="{Binding UserName}"/>
</Frame>
</DataTemplate>
</hl:HorizontalList.ItemTemplate>
</hl:HorizontalList>
<Label <Label
Text="Queue"/> Text="Queue"/>
<qu:Queue/> <qu:Queue/>

View File

@ -28,7 +28,11 @@ namespace Aurora.Design.Views.Party
{ {
this.JoinCommand = new Command(OnJoinExecute, CanJoinExecute); this.JoinCommand = new Command(OnJoinExecute, CanJoinExecute);
this.HostCommand = new Command(OnHostExecute, CanHostExecute); this.HostCommand = new Command(OnHostExecute, CanHostExecute);
_members = new ObservableCollection<PartyMember>(); _members = new ObservableCollection<PartyMember>
{
new PartyMember{UserName = "asdf"}
};
State(PartyState.SelectingHost); State(PartyState.SelectingHost);
} }
@ -49,7 +53,10 @@ namespace Aurora.Design.Views.Party
{ {
return _members; return _members;
} }
set { SetProperty(ref _members, value); } set
{
SetProperty(ref _members, value);
}
} }
public bool IsSelectingHost public bool IsSelectingHost
@ -87,7 +94,8 @@ namespace Aurora.Design.Views.Party
_executor = BaseExecutor.CreateExecutor<ClientExecutor>(); _executor = BaseExecutor.CreateExecutor<ClientExecutor>();
_executor.Connect(this.Hostname); _executor.Connect(this.Hostname);
SetUpMembers(); SetupMembersCollection();
OnPropertyChanged("Members");
State(PartyState.Connecting); State(PartyState.Connecting);
} }
@ -104,7 +112,8 @@ namespace Aurora.Design.Views.Party
_executor = BaseExecutor.CreateExecutor<HostExecutor>(); _executor = BaseExecutor.CreateExecutor<HostExecutor>();
_executor.Connect(this.Hostname); _executor.Connect(this.Hostname);
SetUpMembers(); SetupMembersCollection();
OnPropertyChanged("Members");
//Change state //Change state
State(PartyState.Connecting); State(PartyState.Connecting);
@ -118,18 +127,41 @@ namespace Aurora.Design.Views.Party
#endregion Commands #endregion Commands
private void SetUpMembers() private void SetupMembersCollection()
{ {
_members = _executor.PartyMembers; if (_executor != null)
OnPropertyChanged("Members");
_executor.PartyMembers.CollectionChanged += (sender, e) =>
{ {
if (_executor != null) foreach (PartyMember member in _executor.PartyMembers)
{ {
_members = _executor.PartyMembers; _members.Add(member);
} }
OnPropertyChanged("Members");
}; //Setup events
_executor.PartyMembers.CollectionChanged += (sender, e) =>
{
switch (e.Action)
{
case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
{
foreach (PartyMember member in e.NewItems)
{
Members.Add(member);
OnPropertyChanged("Members");
}
break;
}
case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
{
foreach (PartyMember member in e.OldItems)
{
Members.Remove(member);
OnPropertyChanged("Members");
}
break;
}
}
};
}
} }
} }
} }

View File

@ -2,6 +2,8 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading; using System.Threading;
using System.Linq.Expressions;
using System.Linq;
using Grpc.Core; using Grpc.Core;
using wellKnown = Google.Protobuf.WellKnownTypes; using wellKnown = Google.Protobuf.WellKnownTypes;
using Aurora.Proto.General; using Aurora.Proto.General;
@ -18,6 +20,7 @@ namespace Aurora.Executors
private RemotePlaybackService.RemotePlaybackServiceClient _remotePlaybackClient; private RemotePlaybackService.RemotePlaybackServiceClient _remotePlaybackClient;
private RemoteEventService.RemoteEventServiceClient _remoteEventsClient; private RemoteEventService.RemoteEventServiceClient _remoteEventsClient;
private Task _eventsTask; private Task _eventsTask;
CancellationTokenSource _eventCancellationTokenSource;
private ObservableCollection<PartyMember> _partyMembers; private ObservableCollection<PartyMember> _partyMembers;
@ -48,6 +51,7 @@ namespace Aurora.Executors
//Assign but don't start task //Assign but don't start task
_eventsTask = new Task(GetEvents); _eventsTask = new Task(GetEvents);
_eventCancellationTokenSource = new CancellationTokenSource();
JoinParty(); JoinParty();
} }
@ -58,6 +62,7 @@ namespace Aurora.Executors
/// <returns></returns> /// <returns></returns>
public override async void Close() public override async void Close()
{ {
_eventCancellationTokenSource.Cancel();
await _channel.ShutdownAsync(); await _channel.ShutdownAsync();
} }
@ -81,6 +86,10 @@ namespace Aurora.Executors
throw new NotImplementedException(); throw new NotImplementedException();
} }
/// <summary>
/// Join the remote party.
/// </summary>
/// <returns></returns>
private async void JoinParty() private async void JoinParty()
{ {
await _remotePartyClient.JoinPartyAsync(new JoinPartyRequest await _remotePartyClient.JoinPartyAsync(new JoinPartyRequest
@ -108,6 +117,9 @@ namespace Aurora.Executors
} }
/// <summary>
/// Refresh members list.
/// </summary>
private void RefreshMembers() private void RefreshMembers()
{ {
MembersResponse resposne = _remotePartyClient.GetPartyMembers(new Empty()); MembersResponse resposne = _remotePartyClient.GetPartyMembers(new Empty());
@ -127,32 +139,43 @@ namespace Aurora.Executors
} }
} }
/// <summary>
/// Asynchronous function for processing events off of the event stream.
/// </summary>
/// <returns></returns>
private async void GetEvents() private async void GetEvents()
{ {
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
using (AsyncServerStreamingCall<BaseEvent> eventStream = _remoteEventsClient.GetEvents(new Empty())) using (AsyncServerStreamingCall<BaseEvent> eventStream = _remoteEventsClient.GetEvents(new Empty()))
{ {
while (await eventStream.ResponseStream.MoveNext(cancellationTokenSource.Token)) while (!_eventCancellationTokenSource.Token.IsCancellationRequested)
{ {
//Convert derived event type if (await eventStream.ResponseStream.MoveNext(_eventCancellationTokenSource.Token))
BaseEvent e = eventStream.ResponseStream.Current;
switch (e.DerivedEventCase)
{ {
case BaseEvent.DerivedEventOneofCase.None: //Convert derived event type
{ BaseEvent e = eventStream.ResponseStream.Current;
throw new InvalidOperationException(); switch (e.DerivedEventCase)
} {
case BaseEvent.DerivedEventOneofCase.PartyMemberJoinedEvent: case BaseEvent.DerivedEventOneofCase.None:
{ {
PartyMemberJoinedEvent derivedEvent = e.PartyMemberJoinedEvent; throw new InvalidOperationException();
break; }
} case BaseEvent.DerivedEventOneofCase.PartyMemberJoinedEvent:
case BaseEvent.DerivedEventOneofCase.PartyMemberLeftEvent: {
{ PartyMemberJoinedEvent derivedEvent = e.PartyMemberJoinedEvent;
PartyMemberJoinedEvent derivedEvent = e.PartyMemberJoinedEvent; _partyMembers.Add(derivedEvent.Member);
break; break;
} }
case BaseEvent.DerivedEventOneofCase.PartyMemberLeftEvent:
{
PartyMemberJoinedEvent derivedEvent = e.PartyMemberJoinedEvent;
var found = _partyMembers.Where(x => x.Id == derivedEvent.Member.Id);
foreach (PartyMember member in found)
{
_partyMembers.Remove(member);
}
break;
}
}
} }
} }
} }