Changing folder names

This commit is contained in:
Brandon Watson
2021-04-10 10:20:50 -04:00
parent f1a3771912
commit dd4632cdb6
62 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,42 @@
using System;
using Xamarin.Forms;
namespace Aurora.Design.Behaviors
{
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
{
BindingContext = bindable.BindingContext;
}
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}

View File

@ -0,0 +1,132 @@
using System;
using System.Reflection;
using System.Windows.Input;
using Xamarin.Forms;
namespace Aurora.Design.Behaviors
{
public class EventToCommandBehavior : BehaviorBase<View>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter Converter
{
get { return (IValueConverter)GetValue(InputConverterProperty); }
set { SetValue(InputConverterProperty, value); }
}
protected override void OnAttachedTo(View bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(View bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
}
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
if (eventHandler == null)
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
}
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null)
{
return;
}
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else if (Converter != null)
{
resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
}
else
{
resolvedParameter = eventArgs;
}
if (Command.CanExecute(resolvedParameter))
{
Command.Execute(resolvedParameter);
}
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null)
{
return;
}
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Components.Dialogs.Modal">
<ContentView.Content>
<ContentPresenter
x:Name="ViewContent"/>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Components.Dialogs
{
public partial class Modal : ContentView
{
public Modal()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,208 @@
using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Input;
using Xamarin.Forms;
namespace Aurora.Design.Components.HorizontalList
{
public class HorizontalList : Grid
{
private ICommand _innerSelectedCommand;
private readonly ScrollView _scrollView;
private readonly StackLayout _itemsStackLayout;
public event EventHandler SelectedItemChanged;
private NotifyCollectionChangedEventHandler _itemsChangedHandler;
public StackOrientation ListOrientation { get; set; }
public double Spacing { get; set; }
public static readonly BindableProperty SelectedCommandProperty =
BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HorizontalList), null);
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource",
returnType: typeof(ObservableCollection<object>),
declaringType: typeof(HorizontalList),
defaultValue: default(ObservableCollection<object>),
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: ItemsSourceChanged);
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create("SelectedItem", typeof(object), typeof(HorizontalList), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(HorizontalList), default(DataTemplate));
public ICommand SelectedCommand
{
get { return (ICommand)GetValue(SelectedCommandProperty); }
set { SetValue(SelectedCommandProperty, value); }
}
public ObservableCollection<object> ItemsSource
{
get { return (ObservableCollection<object>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
private static void ItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
HorizontalList itemsLayout = bindable as HorizontalList;
itemsLayout.SetItems();
}
public HorizontalList()
{
_itemsChangedHandler = OnItemsChanged;
// BackgroundColor = Color.FromHex("#1E2634");
Spacing = 6;
_scrollView = new ScrollView();
_itemsStackLayout = new StackLayout
{
Padding = Padding,
Spacing = Spacing,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_scrollView.Content = _itemsStackLayout;
Children.Add(_scrollView);
}
~HorizontalList()
{
ItemsSource.CollectionChanged -= _itemsChangedHandler;
}
protected virtual void SetItems()
{
_itemsStackLayout.Children.Clear();
_itemsStackLayout.Spacing = Spacing;
_innerSelectedCommand = new Command<View>(view =>
{
SelectedItem = view.BindingContext;
SelectedItem = null; // Allowing item second time selection
});
_itemsStackLayout.Orientation = ListOrientation;
_scrollView.Orientation = ListOrientation == StackOrientation.Horizontal
? ScrollOrientation.Horizontal
: ScrollOrientation.Vertical;
if (ItemsSource == null)
{
return;
}
//Setup collection events
ItemsSource.CollectionChanged += _itemsChangedHandler;
foreach (var item in ItemsSource)
{
_itemsStackLayout.Children.Add(GetItemView(item));
}
SelectedItem = null;
}
protected virtual View GetItemView(object item)
{
var content = ItemTemplate.CreateContent();
var view = content as View;
if (view == null)
{
return null;
}
view.BindingContext = item;
var gesture = new TapGestureRecognizer
{
Command = _innerSelectedCommand,
CommandParameter = view
};
AddGesture(view, gesture);
return view;
}
private void AddGesture(View view, TapGestureRecognizer gesture)
{
view.GestureRecognizers.Add(gesture);
var layout = view as Layout<View>;
if (layout == null)
{
return;
}
foreach (var child in layout.Children)
{
AddGesture(child, gesture);
}
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var itemsView = (HorizontalList)bindable;
if (newValue == oldValue && newValue != null)
{
return;
}
itemsView.SelectedItemChanged?.Invoke(itemsView, EventArgs.Empty);
if (itemsView.SelectedCommand?.CanExecute(newValue) ?? false)
{
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

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Aurora.Design.Components.ImageButton.ImageButton">
<ContentView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnButtonTapped" />
</ContentView.GestureRecognizers>
<ContentView.Content>
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Image x:Name="imgButton" Aspect="AspectFit" />
</StackLayout>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Components.ImageButton
{
public partial class ImageButton : ContentView
{
public ImageButton()
{
InitializeComponent();
}
public static readonly BindableProperty SourceProperty =
BindableProperty.Create(
"Source",
typeof(ImageSource),
typeof(ImageButton),
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
ImageButton control = (ImageButton)bindable;
control.imgButton.Source = (ImageSource)newValue;
});
public static readonly BindableProperty CommandProperty = BindableProperty.Create(
"Command",
typeof(Command),
typeof(ImageButton),
null,
propertyChanged: (bindable, oldValue, newValue) =>
{
ImageButton control = (ImageButton)bindable;
var command = (Command)newValue;
CanExecute(command, control);
command.CanExecuteChanged += (sender, e) =>
{
CanExecute(sender, control);
};
});
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(
"CommandParameter",
typeof(object),
typeof(ImageButton),
null);
private static void CanExecute(object sender, ImageButton control)
{
var cmd = (Command)sender;
control.imgButton.IsEnabled = cmd.CanExecute(null);
}
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public event EventHandler<EventArgs> Tapped;
public Command Command
{
get { return (Command)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
protected void OnButtonTapped(object sender, EventArgs args)
{
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else
{
resolvedParameter = args;
}
if (Command?.CanExecute(resolvedParameter) ?? true)
{
this.AbortAnimation("imgButtonAnim");
new Animation(v => imgButton.Scale = v, 1, 0.5).Commit(imgButton, "imgButtonAnim", 16, 150, Easing.SinOut,
(v, c) =>
{
imgButton.Scale = 1;
Tapped?.Invoke(this, args);
Command?.Execute(resolvedParameter);
});
}
}
}
}

View File

@ -0,0 +1,7 @@
Label {
margin-left: 25;
text-align: left;
vertical-align: middle;
word-wrap: break-word;
font-size: 14;
}

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:dg="clr-namespace:Xamarin.Forms.DataGrid;assembly=Xamarin.Forms.DataGrid"
x:Class="Aurora.Design.Components.Library.Library">
<ContentView.Resources>
<StyleSheet
Source="Library.css"/>
</ContentView.Resources>
<ContentView.Content>
<dg:DataGrid
x:Name="LibraryDataGrid"
SelectionEnabled="True"
RowHeight="30"
BorderColor="#181818"
BorderThickness="0"
HeaderHeight="45"
HeaderBackground="#181818">
<dg:DataGrid.HeaderLabelStyle>
<Style
TargetType="Label">
<Setter
Property="HorizontalOptions"
Value="Start"/>
<Setter
Property="FontSize"
Value="14"/>
<Setter
Property="TextColor"
Value="White"/>
</Style>
</dg:DataGrid.HeaderLabelStyle>
<dg:DataGrid.GestureRecognizers>
<TapGestureRecognizer
NumberOfTapsRequired="2"/>
</dg:DataGrid.GestureRecognizers>
<dg:DataGrid.Columns>
<dg:DataGridColumn
Title=""
PropertyName="Icon"
Width="15">
<dg:DataGridColumn.CellTemplate>
<DataTemplate>
<Image
Source="../../Resources/unselected.png"/>
</DataTemplate>
</dg:DataGridColumn.CellTemplate>
</dg:DataGridColumn>
<dg:DataGridColumn
Title="Title"
PropertyName="Metadata.Title"
Width="2*">
<dg:DataGridColumn.CellTemplate>
<DataTemplate>
<Label
LineBreakMode="TailTruncation"
Text="{Binding .}"/>
</DataTemplate>
</dg:DataGridColumn.CellTemplate>
</dg:DataGridColumn>
<dg:DataGridColumn
Title="Album"
PropertyName="Metadata.Album"
Width="0.95*">
<dg:DataGridColumn.CellTemplate>
<DataTemplate>
<Label
LineBreakMode="TailTruncation"
Text="{Binding .}"/>
</DataTemplate>
</dg:DataGridColumn.CellTemplate>
</dg:DataGridColumn>
<dg:DataGridColumn
Title="Artist"
PropertyName="Metadata.Artist"
Width="1*">
<dg:DataGridColumn.CellTemplate>
<DataTemplate>
<Label
LineBreakMode="TailTruncation"
Text="{Binding .}"/>
</DataTemplate>
</dg:DataGridColumn.CellTemplate>
</dg:DataGridColumn>
</dg:DataGrid.Columns>
<dg:DataGrid.RowsTextColorPalette>
<dg:PaletteCollection>
<Color>White</Color>
</dg:PaletteCollection>
</dg:DataGrid.RowsTextColorPalette>
<dg:DataGrid.RowsBackgroundColorPalette>
<dg:PaletteCollection>
<Color>Transparent</Color>
</dg:PaletteCollection>
</dg:DataGrid.RowsBackgroundColorPalette>
</dg:DataGrid>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,139 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xamarin.Forms;
namespace Aurora.Design.Components.Library
{
public partial class Library : ContentView
{
public Library()
{
InitializeComponent();
this.LibraryDataGrid.ItemSelected += (sender, e) =>
{
this.SelectedItem = e.SelectedItem;
};
}
#region ItemsSource Property
/// <summary>
/// Bindable Property for the ItemsSource of the datagrid.
/// </summary>
/// <param name=""ItemsSource""></param>
/// <param name="typeof(IEnumerable<object>"></param>
/// <returns></returns>
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create(propertyName: "ItemsSource",
returnType: typeof(IEnumerable<object>),
declaringType: typeof(Library),
defaultBindingMode: BindingMode.Default,
propertyChanged: (BindableObject bindable, object oldValue, object newValue) =>
{
Library control = bindable as Library;
control.LibraryDataGrid.ItemsSource = (IEnumerable<object>)newValue;
});
/// <summary>
/// Backing property for the ItemsSource property.
/// </summary>
/// <value></value>
public IEnumerable<object> ItemsSource
{
get
{
return (IEnumerable<object>)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
#endregion ItemsSource Property
/// <summary>
/// Bindable property for the selected item field on the datagrid.
/// </summary>
/// <param name=""SelectedItem""></param>
/// <param name="typeof(BaseMetadata"></param>
/// <returns></returns>
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create(propertyName: "SelectedItem",
returnType: typeof(object),
declaringType: typeof(Library),
defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Backing property for the SelectedItem property.
/// </summary>
/// <value></value>
public object SelectedItem
{
get
{
return ((object)GetValue(SelectedItemProperty));
}
set
{
SetValue(SelectedItemProperty, value);
}
}
/// <summary>
/// Bindable property for the item double clicked command
/// </summary>
/// <param name=""SelectedItem""></param>
/// <param name="typeof(BaseMetadata"></param>
/// <returns></returns>
public static readonly BindableProperty ItemDoubleClickedProperty =
BindableProperty.Create(propertyName: "ItemDoubleClicked",
returnType: typeof(Command),
declaringType: typeof(Library),
propertyChanged: OnDoubleClickPropertyChanged);
/// <summary>
/// Public backing property
/// </summary>
/// <value></value>
public Command ItemDoubleClicked
{
get
{
return (Command)GetValue(ItemDoubleClickedProperty);
}
set
{
SetValue(ItemDoubleClickedProperty, value);
}
}
/// <summary>
/// Event handler for double click property. Adds command execute handler.
/// </summary>
/// <param name="bindable"></param>
/// <param name="newValue"></param>
/// <param name="oldValue"></param>
private static void OnDoubleClickPropertyChanged(BindableObject bindable, object newValue, object oldValue)
{
Library control = bindable as Library;
var dataGrid = control.LibraryDataGrid;
if (dataGrid.GestureRecognizers.Count > 0)
{
var gestureRecognizer = dataGrid.GestureRecognizers.First();
if (gestureRecognizer is TapGestureRecognizer)
{
TapGestureRecognizer tap = gestureRecognizer as TapGestureRecognizer;
tap.Tapped += (sender, e) =>
{
control.ItemDoubleClicked.Execute(null);
};
}
}
}
}
}

View File

@ -0,0 +1,44 @@
#PlayerControlContainer {
background-color: #303030;
}
Label {
color: white;
text-align: left;
vertical-align: middle;
word-wrap: break-word;
}
#MediaInfoContainer {
width: 150;
margin-top: 10;
margin-bottom: 10;
}
#MediaInfoContainer label {
margin-left: 20;
}
#AlbumArtBoxView {
background-color: black;
width: 80;
}
.PlayButton {
width: 40;
}
.DirectionButton {
width: 30;
}
.LibraryButton {
width: 25;
}
ImageButton {
margin-top: 10;
margin-left: 15;
margin-right: 15;
margin-bottom: 10;
}

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:imgBtn="clr-namespace:Aurora.Design.Components.ImageButton"
x:Class="Aurora.Design.Components.MediaPlayer.Player">
<ContentView.Resources>
<StyleSheet
Source="Player.css"/>
</ContentView.Resources>
<ContentView.Content>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="200"/>
<ColumnDefinition
Width="*"/>
<ColumnDefinition
Width="100"/>
</Grid.ColumnDefinitions>
<StackLayout
Grid.Column="0"
Orientation="Horizontal">
<BoxView
x:Name="AlbumArtBoxView"/>
<StackLayout
x:Name="MediaInfoContainer"
HorizontalOptions="StartAndExpand">
<Label
x:Name="SongTitleLabel"
LineBreakMode="TailTruncation"/>
<Label
x:Name="ArtistNameLabel"
LineBreakMode="TailTruncation"/>
</StackLayout>
</StackLayout>
<StackLayout
x:Name="PlayerControlContainer"
Grid.Column="1"
HorizontalOptions="Center"
Orientation="Horizontal">
<imgBtn:ImageButton
x:Name="ShuffleButton"
StyleClass="LibraryButton"
Source="Resources/shuffle.png"/>
<imgBtn:ImageButton
x:Name="PreviousButton"
StyleClass="DirectionButton"
Source="Resources/backward.png"/>
<imgBtn:ImageButton
x:Name="PlayButton"
StyleClass="PlayButton"/>
<imgBtn:ImageButton
x:Name="NextButton"
StyleClass="DirectionButton"
Source="Resources/forwards.png"/>
<imgBtn:ImageButton
x:Name="LoopButton"
StyleClass="LibraryButton"
Source="Resources/loop.png"/>
</StackLayout>
</Grid>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,303 @@
using System;
using Xamarin.Forms;
namespace Aurora.Design.Components.MediaPlayer
{
public partial class Player : ContentView
{
public Player()
{
InitializeComponent();
PlayButton.Source = ImageSource.FromFile("Resources/play.png");
}
#region SongTitle Bindable
public static readonly BindableProperty SongTitleProperty =
BindableProperty.Create(propertyName: "SongTitle",
returnType: typeof(string),
declaringType: typeof(Player),
propertyChanged: (BindableObject bindable, object oldValue, object newValue) =>
{
Player component = bindable as Player;
component.SongTitleLabel.Text = (string)newValue;
});
public string SongTitle
{
get
{
return (string)GetValue(SongTitleProperty);
}
set
{
SetValue(SongTitleProperty, value);
}
}
#endregion SongTitle Bindable
#region ArtistName Bindable
public static readonly BindableProperty ArtistNameProperty =
BindableProperty.Create(propertyName: "ArtistName",
returnType: typeof(string),
declaringType: typeof(Player),
propertyChanged: (BindableObject bindable, object oldValue, object newValue) =>
{
Player component = bindable as Player;
component.ArtistNameLabel.Text = (string)newValue;
});
public string ArtistName
{
get
{
return (string)GetValue(ArtistNameProperty);
}
set
{
SetValue(ArtistNameProperty, value);
}
}
#endregion ArtistName Bindable
#region PreviousButton
public static readonly BindableProperty PreviousButtonCommandProperty =
BindableProperty.Create(propertyName: "PreviousButtonCommand",
returnType: typeof(Command),
propertyChanged: OnPreviousButtonPropertyChanged,
declaringType: typeof(Player));
public Command PreviousButtonCommand
{
get
{
return (Command)GetValue(PreviousButtonCommandProperty);
}
set
{
SetValue(PreviousButtonCommandProperty, value);
}
}
private void OnPreviousButtonClicked(object sender, EventArgs args)
{
if (PreviousButtonCommand.CanExecute(null))
{
PreviousButtonCommand.Execute(null);
PreviousButtonCommand.ChangeCanExecute();
PlayButtonCommand.ChangeCanExecute();
NextButtonCommand.ChangeCanExecute();
}
}
/// <summary>
/// Event handler to hook up can execute events on property changed
/// </summary>
/// <param name="bindable"></param>
/// <param name="newValue"></param>
/// <param name="oldValue"></param>
private static void OnPreviousButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
Player component = bindable as Player;
if (newValue is Command)
{
Command cmd = newValue as Command;
component.PreviousButton.Tapped += component.OnPreviousButtonClicked;
cmd.CanExecuteChanged += (sender, e) => OnPreviousButtonCanExecuteChanged(sender, e, component, cmd);
}
if (oldValue is Command && oldValue != null)
{
Command cmd = newValue as Command;
component.PreviousButton.Tapped -= component.OnPreviousButtonClicked;
cmd.CanExecuteChanged -= (sender, e) => OnPreviousButtonCanExecuteChanged(sender, e, component, cmd);
}
}
/// <summary>
/// Can execute changed event handler
/// </summary>
/// <param name="sender"></param>
/// <param name="eventArgs"></param>
/// <param name="component"></param>
/// <param name="cmd"></param>
private static void OnPreviousButtonCanExecuteChanged(object sender,
EventArgs eventArgs,
Player component,
Command cmd)
{
component.NextButton.IsEnabled = cmd.CanExecute(null);
}
#endregion PreviousButton
#region PlayButton
public static readonly BindableProperty PlayButtonCommandProperty =
BindableProperty.Create(propertyName: "PlayButtonCommand",
returnType: typeof(Command),
propertyChanged: OnPlayButtonPropertyChanged,
declaringType: typeof(Player));
public Command PlayButtonCommand
{
get
{
return (Command)GetValue(PlayButtonCommandProperty);
}
set
{
SetValue(PlayButtonCommandProperty, value);
}
}
private void OnPlayButtonClicked(object sender, EventArgs args)
{
if (PlayButtonCommand.CanExecute(null))
{
PlayButtonCommand.Execute(null);
PreviousButtonCommand.ChangeCanExecute();
PlayButtonCommand.ChangeCanExecute();
NextButtonCommand.ChangeCanExecute();
}
}
/// <summary>
/// Event handler to hook up can execute events on property changed
/// </summary>
/// <param name="bindable"></param>
/// <param name="newValue"></param>
/// <param name="oldValue"></param>
private static void OnPlayButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
Player component = bindable as Player;
if (newValue is Command)
{
Command cmd = newValue as Command;
component.PlayButton.Tapped += component.OnPlayButtonClicked;
cmd.CanExecuteChanged += (sender, e) => OnPlayButtonCanExecuteChanged(sender, e, component, cmd);
}
if (oldValue is Command && oldValue != null)
{
Command cmd = newValue as Command;
component.PlayButton.Tapped -= component.OnPlayButtonClicked;
cmd.CanExecuteChanged -= (sender, e) => OnPlayButtonCanExecuteChanged(sender, e, component, cmd);
}
}
/// <summary>
/// Can execute changed event handler
/// </summary>
/// <param name="sender"></param>
/// <param name="eventArgs"></param>
/// <param name="component"></param>
/// <param name="cmd"></param>
private static void OnPlayButtonCanExecuteChanged(object sender,
EventArgs eventArgs,
Player component,
Command cmd)
{
component.NextButton.IsEnabled = cmd.CanExecute(null);
}
#endregion PlayButton
#region NextButton
public static readonly BindableProperty NextButtonCommandProperty =
BindableProperty.Create(propertyName: "NextButtonCommand",
returnType: typeof(Command),
declaringType: typeof(Player),
propertyChanged: OnNextButtonPropertyChanged);
public Command NextButtonCommand
{
get
{
return (Command)GetValue(NextButtonCommandProperty);
}
set
{
SetValue(NextButtonCommandProperty, value);
}
}
private void OnNextButtonClicked(object sender, EventArgs args)
{
if (NextButtonCommand.CanExecute(null))
{
NextButtonCommand.Execute(null);
PreviousButtonCommand.ChangeCanExecute();
PlayButtonCommand.ChangeCanExecute();
NextButtonCommand.ChangeCanExecute();
}
}
/// <summary>
/// Event handler to hook up can execute events on property changed
/// </summary>
/// <param name="bindable"></param>
/// <param name="newValue"></param>
/// <param name="oldValue"></param>
private static void OnNextButtonPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
Player component = bindable as Player;
if (newValue is Command)
{
Command cmd = newValue as Command;
component.NextButton.Tapped += component.OnNextButtonClicked;
cmd.CanExecuteChanged += (sender, e) => OnNextButtonCanExecuteChanged(sender, e, component, cmd);
}
if (oldValue is Command && oldValue != null)
{
Command cmd = oldValue as Command;
component.NextButton.Tapped -= component.OnNextButtonClicked;
cmd.CanExecuteChanged -= (sender, e) => OnNextButtonCanExecuteChanged(sender, e, component, cmd);
}
}
/// <summary>
/// Can execute changed event handler
/// </summary>
/// <param name="sender"></param>
/// <param name="eventArgs"></param>
/// <param name="component"></param>
/// <param name="cmd"></param>
private static void OnNextButtonCanExecuteChanged(object sender,
EventArgs eventArgs,
Player component,
Command cmd)
{
component.NextButton.IsEnabled = cmd.CanExecute(null);
}
#endregion PlayButton
#region Playing Bindable
public static readonly BindableProperty IsPlayingProperty =
BindableProperty.Create(
propertyName: "IsPlaying",
returnType: typeof(bool),
declaringType: typeof(Player),
propertyChanged: (BindableObject bindable, object oldValue, object newValue) =>
{
Player control = (Player)bindable;
if ((bool)newValue == true)
{
control.PlayButton.Source = ImageSource.FromFile("Resources/pause.png");
}
else
{
control.PlayButton.Source = ImageSource.FromFile("Resources/play.png");
}
});
public bool IsPlaying
{
get { return (bool)GetValue(IsPlayingProperty); }
set { SetValue(IsPlayingProperty, value); }
}
#endregion Playing Binadable
}
}

View File

@ -0,0 +1,20 @@
#MembersList {
background-color: #1e1e1e;
}
Grid {
margin-left: 20;
margin-right: 20;
margin-top: 20;
margin-bottom: 20;
width: 150;
border-radius: 25;
background-color: #626363;
}
Grid Label {
text-align: center;
vertical-align: middle;
color: white;
font-size: 20;
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"
x:Class="Aurora.Design.Components.MemberList.MemberList">
<ContentView.Resources>
<StyleSheet
Source="./MemberList.css"/>
</ContentView.Resources>
<ContentView.Content>
<flv:FlowListView
x:Name="MembersList"
FlowColumnMinWidth="150"
RowHeight="150"
SeparatorVisibility="None"
BackgroundColor="#181818"
HasUnevenRows="false">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Label
Text="{Binding UserName}"/>
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections;
using System.Linq;
using Xamarin.Forms;
using Aurora.Proto.Party;
using DLToolkit.Forms.Controls;
namespace Aurora.Design.Components.MemberList
{
public partial class MemberList : ContentView
{
public MemberList()
{
InitializeComponent();
}
/// <summary>
/// Bindable property for members list.
/// </summary>
/// <param name=""Members""></param>
/// <param name="typeof(IEnumerable<string>"></param>
/// <returns></returns>
public static readonly BindableProperty MembersProperty =
BindableProperty.Create(propertyName: "Members",
returnType: typeof(ObservableCollection<Member>),
declaringType: typeof(MemberList),
defaultBindingMode: BindingMode.Default,
propertyChanged: OnMembersChanged);
/// <summary>
/// Backing property for MembersProperty
/// </summary>
/// <value></value>
public ObservableCollection<Member> Members
{
get
{
return (ObservableCollection<Member>)GetValue(MembersProperty);
}
set
{
SetValue(MembersProperty, value);
}
}
/// <summary>
/// Memberes changed event handler. Assign member list source.
/// </summary>
/// <param name="bindable"></param>
/// <param name="oldValue"></param>
/// <param name="newValue"></param>
private static void OnMembersChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (MemberList)bindable;
var membersList = control.FindByName("MembersList") as FlowListView;
if (newValue is ICollection source)
{
membersList.FlowItemsSource = source;
}
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Aurora.Design.Components.NavigationMenu
{
public class NavigationGroupItem : List<NavigationItem>
{
public NavigationGroupItem()
{
}
public NavigationGroupItem(string heading)
{
GroupHeading = heading;
}
public List<NavigationItem> Items => this;
public string GroupHeading { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aurora.Design.Views.Main;
namespace Aurora.Design.Components.NavigationMenu
{
public class NavigationItem
{
public NavigationItem()
{
}
public int Id { get; set; }
public string Title { get; set; }
public string Group { get; set; }
public Type TargetType { get; set; }
public Type TargetViewModelType { get; set; }
}
}

View File

@ -0,0 +1,25 @@
ListView {
margin-left: 15;
margin-top: 40;
}
#GroupTemplate {
align-items: end;
}
#GroupCell Label {
color: lightgray;
font-size: 12;
font-family: Courier New, Courier, monospace;
font-style: italic;
padding-top: 20;
}
#ItemCell Label {
color: white;
font-size: 15;
font-family: Courier New, Courier, monospace;
font-style: normal;
text-align: left;
padding-top: 12;
}

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Components.NavigationMenu.NavigationMenu">
<ContentView.Resources>
<StyleSheet
Source="NavigationMenu.css"/>
</ContentView.Resources>
<ContentView.Content>
<StackLayout
x:Name="Layout"
StyleClass="primaryColor">
<ListView
x:Name="MenuItemsListView"
HasUnevenRows="true"
SeparatorVisibility="None"
IsGroupingEnabled="true"
RowHeight="35"
StyleClass="primaryColor"
CachingStrategy="RecycleElement">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell
x:Name="GroupCell">
<Label
VerticalTextAlignment="Center"
Text="{Binding GroupHeading}"/>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell
x:Name="ItemCell">
<Label
StyleClass="primaryColor"
Text="{Binding Title}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Xamarin.Forms;
namespace Aurora.Design.Components.NavigationMenu
{
public partial class NavigationMenu : ContentView
{
public NavigationMenu()
{
InitializeComponent();
ListView = MenuItemsListView;
ListView.ItemSelected += ListView_ItemSelected;
}
private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
this.SelectedItem = e.SelectedItem as NavigationItem;
}
public ListView ListView;
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create(propertyName: nameof(SelectedItem),
returnType: typeof(NavigationItem),
declaringType: typeof(NavigationMenu),
defaultBindingMode: BindingMode.OneWayToSource);
public NavigationItem SelectedItem
{
get
{
return (NavigationItem)GetValue(SelectedItemProperty);
}
set
{
SetValue(SelectedItemProperty, value);
}
}
public static readonly BindableProperty ItemsProperty =
BindableProperty.Create(propertyName: nameof(Items),
returnType: typeof(ObservableCollection<NavigationItem>),
declaringType: typeof(NavigationMenu),
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnItemsChanged);
public ObservableCollection<NavigationItem> Items
{
get
{
return (ObservableCollection<NavigationItem>)GetValue(ItemsProperty);
}
set
{
SetValue(ItemsProperty, value);
}
}
/// <summary>
/// Items changed event handler. Organizes items in groups for display.
/// </summary>
/// <param name="bindable">The changed Item.</param>
/// <param name="oldValue">The previous value.</param>
/// <param name="newValue">The new value.</param>
private static void OnItemsChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (NavigationMenu)bindable;
ObservableCollection<NavigationItem> items = (ObservableCollection<NavigationItem>)newValue;
Dictionary<string, NavigationGroupItem> groupDictioanry = new Dictionary<string, NavigationGroupItem>();
//Populate dictionary where group heading is the key
foreach (NavigationItem item in items)
{
if (groupDictioanry.ContainsKey(item.Group))
{
groupDictioanry.TryGetValue(item.Group, out var groupItem);
groupItem.Items.Add(item);
}
else
{
NavigationGroupItem groupItem = new NavigationGroupItem(item.Group);
groupItem.Add(item);
groupDictioanry.Add(item.Group, groupItem);
}
}
ObservableCollection<NavigationGroupItem> groups = new ObservableCollection<NavigationGroupItem>();
foreach (string groupHeading in groupDictioanry.Keys)
{
groupDictioanry.TryGetValue(groupHeading, out var groupItem);
groups.Add(groupItem);
}
control.MenuItemsListView.ItemsSource = groups;
}
}
}

View File

@ -0,0 +1,111 @@
using Xamarin.Forms;
namespace Aurora.Design.Components.TabView
{
[ContentProperty(nameof(Content))]
public class TabItem : BindableObject
{
public TabItem()
{
//Parameterless constructor required for xaml instantiation.
}
public void TriggerPropertyChange(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
}
public TabItem(string headerText, View content, ImageSource headerIcon = null)
{
HeaderText = headerText;
Content = content;
if (headerIcon != null)
HeaderIcon = headerIcon;
}
public static readonly BindableProperty HeaderIconProperty = BindableProperty.Create(nameof(HeaderIcon), typeof(ImageSource), typeof(TabItem));
public ImageSource HeaderIcon
{
get => (ImageSource)GetValue(HeaderIconProperty);
set { SetValue(HeaderIconProperty, value); }
}
public readonly BindableProperty HeaderIconSizeProperty = BindableProperty.Create(nameof(HeaderIconSize), typeof(double), typeof(TabItem), 32.0);
public double HeaderIconSize
{
get => (double)GetValue(HeaderIconSizeProperty);
set { SetValue(HeaderIconSizeProperty, value); }
}
public static readonly BindableProperty HeaderTextProperty = BindableProperty.Create(nameof(HeaderText), typeof(string), typeof(TabItem), string.Empty);
public string HeaderText
{
get => (string)GetValue(HeaderTextProperty);
set { SetValue(HeaderTextProperty, value); }
}
public static readonly BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(TabItem));
public View Content
{
get => (View)GetValue(ContentProperty);
set { SetValue(ContentProperty, value); }
}
public static readonly BindableProperty IsCurrentProperty = BindableProperty.Create(nameof(IsCurrent), typeof(bool), typeof(TabItem), false);
public bool IsCurrent
{
get => (bool)GetValue(IsCurrentProperty);
set { SetValue(IsCurrentProperty, value); }
}
public static readonly BindableProperty HeaderTextColorProperty = BindableProperty.Create(nameof(HeaderTextColor), typeof(Color), typeof(TabItem), Color.White);
public Color HeaderTextColor
{
get => (Color)GetValue(HeaderTextColorProperty);
set { SetValue(HeaderTextColorProperty, value); }
}
public static readonly BindableProperty HeaderSelectionUnderlineColorProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineColor), typeof(Color), typeof(TabItem), Color.Transparent);
public Color HeaderSelectionUnderlineColor
{
get => (Color)GetValue(HeaderSelectionUnderlineColorProperty);
set { SetValue(HeaderSelectionUnderlineColorProperty, value); }
}
public static readonly BindableProperty HeaderSelectionUnderlineThicknessProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineThickness), typeof(double), typeof(TabItem), (double)5);
public double HeaderSelectionUnderlineThickness
{
get => (double)GetValue(HeaderSelectionUnderlineThicknessProperty);
set { SetValue(HeaderSelectionUnderlineThicknessProperty, value); }
}
public static readonly BindableProperty HeaderSelectionUnderlineWidthProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineWidth), typeof(double), typeof(TabItem), (double)40);
public double HeaderSelectionUnderlineWidth
{
get => (double)GetValue(HeaderSelectionUnderlineWidthProperty);
set { SetValue(HeaderSelectionUnderlineWidthProperty, value); }
}
public static readonly BindableProperty HeaderTabTextFontSizeProperty = BindableProperty.Create(nameof(HeaderTabTextFontSize), typeof(double), typeof(TabItem), TabDefaults.DefaultTextSize);
[TypeConverter(typeof(FontSizeConverter))]
public double HeaderTabTextFontSize
{
get => (double)GetValue(HeaderTabTextFontSizeProperty);
set { SetValue(HeaderTabTextFontSizeProperty, value); }
}
public static readonly BindableProperty HeaderTabTextFontFamilyProperty = BindableProperty.Create(nameof(HeaderTabTextFontFamily), typeof(string), typeof(TabItem));
public string HeaderTabTextFontFamily
{
get => (string)GetValue(HeaderTabTextFontFamilyProperty);
set { SetValue(HeaderTabTextFontFamilyProperty, value); }
}
public static readonly BindableProperty HeaderTabTextFontAttributesProperty = BindableProperty.Create(nameof(HeaderTabTextFontAttributes), typeof(FontAttributes), typeof(TabItem), FontAttributes.None);
public FontAttributes HeaderTabTextFontAttributes
{
get => (FontAttributes)GetValue(HeaderTabTextFontAttributesProperty);
set { SetValue(HeaderTabTextFontAttributesProperty, value); }
}
}
}

View File

@ -0,0 +1,571 @@
// using CarouselView.FormsPlugin.Abstractions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Xamarin.Forms;
using Aurora.Design.Converters;
namespace Aurora.Design.Components.TabView
{
public delegate void PositionChangingEventHandler(object sender, TabChangingEventArgs e);
public delegate void PositionChangedEventHandler(object sender, TabChangedEventArgs e);
public class TabChangingEventArgs : EventArgs
{
public bool Canceled { get; set; }
public int NewPosition { get; set; }
public int OldPosition { get; set; }
}
public class TabChangedEventArgs : EventArgs
{
public int NewPosition { get; set; }
public int OldPosition { get; set; }
}
static class TabDefaults
{
public static readonly Color DefaultColor = Color.White;
public const double DefaultThickness = 5;
public const double DefaultTextSize = 14;
}
public class TabViewControl : ContentView
{
private StackLayout _mainContainerSL;
private Grid _headerContainerGrid;
private ScrollView _tabHeadersContainerSv;
public event PositionChangingEventHandler PositionChanging;
public event PositionChangedEventHandler PositionChanged;
protected virtual void OnTabChanging(ref TabChangingEventArgs e)
{
PositionChangingEventHandler handler = PositionChanging;
handler?.Invoke(this, e);
}
protected virtual void OnTabChanged(TabChangedEventArgs e)
{
PositionChangedEventHandler handler = PositionChanged;
handler?.Invoke(this, e);
}
public TabViewControl()
{
//Parameterless constructor required for xaml instantiation.
Init();
}
public TabViewControl(IList<TabItem> tabItems, int selectedTabIndex = 0)
{
Init();
foreach (var tab in tabItems)
{
ItemSource.Add(tab);
}
if (selectedTabIndex > 0)
{
SelectedTabIndex = selectedTabIndex;
}
}
void ItemSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (var tab in e.NewItems)
{
if (tab is TabItem newTab)
{
SetTabProps(newTab);
AddTabToView(newTab);
}
}
}
}
private void SetTabProps(TabItem tab)
{
//Set the tab properties from the main control only if not set in xaml at the individual tab level.
if (tab.HeaderTextColor == TabDefaults.DefaultColor && HeaderTabTextColor != TabDefaults.DefaultColor)
tab.HeaderTextColor = HeaderTabTextColor;
if (tab.HeaderSelectionUnderlineColor == TabDefaults.DefaultColor && HeaderSelectionUnderlineColor != TabDefaults.DefaultColor)
tab.HeaderSelectionUnderlineColor = HeaderSelectionUnderlineColor;
if (tab.HeaderSelectionUnderlineThickness.Equals(TabDefaults.DefaultThickness) && !HeaderSelectionUnderlineThickness.Equals(TabDefaults.DefaultThickness))
tab.HeaderSelectionUnderlineThickness = HeaderSelectionUnderlineThickness;
if (tab.HeaderSelectionUnderlineWidth > 0)
tab.HeaderSelectionUnderlineWidth = HeaderSelectionUnderlineWidth;
if (tab.HeaderTabTextFontSize.Equals(TabDefaults.DefaultTextSize) && !HeaderTabTextFontSize.Equals(TabDefaults.DefaultTextSize))
tab.HeaderTabTextFontSize = HeaderTabTextFontSize;
if (tab.HeaderTabTextFontFamily is null && !string.IsNullOrWhiteSpace(HeaderTabTextFontFamily))
tab.HeaderTabTextFontFamily = HeaderTabTextFontFamily;
if (tab.HeaderTabTextFontAttributes == FontAttributes.None && HeaderTabTextFontAttributes != FontAttributes.None)
tab.HeaderTabTextFontAttributes = HeaderTabTextFontAttributes;
}
private void Init()
{
ItemSource = new ObservableCollection<TabItem>();
_headerContainerGrid = new Grid
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Start,
// BackgroundColor = Color.White, // tab sepeartor color
MinimumHeightRequest = 50,
ColumnSpacing = 0, // seperator thickness
};
_tabHeadersContainerSv = new ScrollView()
{
HorizontalScrollBarVisibility = ScrollBarVisibility.Never,
Orientation = ScrollOrientation.Horizontal,
Content = _headerContainerGrid,
BackgroundColor = HeaderBackgroundColor,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_mainContainerSL = new StackLayout
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Children = { _tabHeadersContainerSv },
Spacing = 0
};
Content = _mainContainerSL;
ItemSource.CollectionChanged += ItemSource_CollectionChanged;
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (BindingContext != null)
{
foreach (var tab in ItemSource)
{
if (tab is TabItem view)
{
view.Content.BindingContext = BindingContext;
}
}
SetCurrentTab(SelectedTabIndex, true);
}
}
private void AddTabToView(TabItem tab)
{
var tabSize = (TabSizeOption.IsAbsolute && TabSizeOption.Value.Equals(0)) ? new GridLength(1, GridUnitType.Star) : TabSizeOption;
_headerContainerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = tabSize });
tab.IsCurrent = _headerContainerGrid.ColumnDefinitions.Count - 1 == SelectedTabIndex;
var headerIcon = new Image
{
Margin = new Thickness(0, 8, 0, 0),
BindingContext = tab,
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.Center,
WidthRequest = tab.HeaderIconSize,
HeightRequest = tab.HeaderIconSize
};
headerIcon.SetBinding(Image.SourceProperty, nameof(TabItem.HeaderIcon));
headerIcon.SetBinding(IsVisibleProperty, nameof(TabItem.HeaderIcon), converter: new NullToBoolConverter());
var headerLabel = new Label
{
BindingContext = tab,
VerticalTextAlignment = TextAlignment.Center,
HorizontalTextAlignment = TextAlignment.Center,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand,
Margin = new Thickness(5, 8, 5, 5)
};
headerLabel.SetBinding(Label.TextProperty, nameof(TabItem.HeaderText));
headerLabel.SetBinding(Label.TextColorProperty, nameof(TabItem.HeaderTextColor));
headerLabel.SetBinding(Label.FontSizeProperty, nameof(TabItem.HeaderTabTextFontSize));
headerLabel.SetBinding(Label.FontFamilyProperty, nameof(TabItem.HeaderTabTextFontFamily));
headerLabel.SetBinding(Label.FontAttributesProperty, nameof(TabItem.HeaderTabTextFontAttributes));
headerLabel.SetBinding(IsVisibleProperty, nameof(TabItem.HeaderText), converter: new NullToBoolConverter());
var selectionBarBoxView = new BoxView
{
VerticalOptions = LayoutOptions.End,
BindingContext = tab,
HeightRequest = HeaderSelectionUnderlineThickness,
WidthRequest = HeaderSelectionUnderlineWidth
};
var underlineColorBinding = new Binding(nameof(TabItem.IsCurrent), BindingMode.OneWay, new SelectedTabHeaderToTabBackgroundColorConverter(), this);
selectionBarBoxView.SetBinding(BoxView.BackgroundColorProperty, underlineColorBinding);
selectionBarBoxView.SetBinding(WidthRequestProperty, nameof(TabItem.HeaderSelectionUnderlineWidth));
selectionBarBoxView.SetBinding(HeightRequestProperty, nameof(TabItem.HeaderSelectionUnderlineThickness));
selectionBarBoxView.SetBinding(HorizontalOptionsProperty,
nameof(TabItem.HeaderSelectionUnderlineWidthProperty),
converter: new DoubleToLayoutOptionsConverter());
selectionBarBoxView.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
{
if (e.PropertyName == nameof(TabItem.IsCurrent))
{
SetCurrentTab(ItemSource.IndexOf((TabItem)((BoxView)sender).BindingContext));
}
if (e.PropertyName == nameof(WidthRequest))
{
selectionBarBoxView.HorizontalOptions = tab.HeaderSelectionUnderlineWidth > 0 ? LayoutOptions.CenterAndExpand : LayoutOptions.FillAndExpand;
}
};
var headerItemSL = new StackLayout
{
VerticalOptions = LayoutOptions.FillAndExpand,
Children = { headerIcon, headerLabel, selectionBarBoxView },
BackgroundColor = HeaderBackgroundColor,
Spacing = 0
};
var tapRecognizer = new TapGestureRecognizer();
tapRecognizer.Tapped += (object s, EventArgs e) =>
{
var capturedIndex = _headerContainerGrid.Children.IndexOf((View)s);
SetCurrentTab(capturedIndex);
};
headerItemSL.GestureRecognizers.Add(tapRecognizer);
_headerContainerGrid.Children.Add(headerItemSL, _headerContainerGrid.ColumnDefinitions.Count - 1, 0);
}
#region HeaderBackgroundColor
public Color HeaderBackgroundColor
{
get { return (Color)GetValue(HeaderBackgroundColorProperty); }
set { SetValue(HeaderBackgroundColorProperty, value); }
}
private static void HeaderBackgroundColorChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl)
{
tabViewControl._tabHeadersContainerSv.BackgroundColor = (Color)newValue;
}
}
public static readonly BindableProperty HeaderBackgroundColorProperty = BindableProperty.Create(nameof(HeaderBackgroundColor), typeof(Color), typeof(TabViewControl), Color.SkyBlue, BindingMode.Default, null, HeaderBackgroundColorChanged);
#endregion
#region HeaderTabTextColor
public Color HeaderTabTextColor
{
get { return (Color)GetValue(HeaderTabTextColorProperty); }
set { SetValue(HeaderTabTextColorProperty, value); }
}
private static void HeaderTabTextColorChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderTextColor = (Color)newValue;
}
}
}
public static readonly BindableProperty HeaderTabTextColorProperty =
BindableProperty.Create(nameof(HeaderTabTextColor), typeof(Color), typeof(TabViewControl), TabDefaults.DefaultColor, BindingMode.OneWay, null, HeaderTabTextColorChanged);
#endregion
#region ContentHeight
public double ContentHeight
{
get { return (double)GetValue(ContentHeightProperty); }
set { SetValue(ContentHeightProperty, value); }
}
private static void ContentHeightChanged(BindableObject bindable, object oldValue, object newValue)
{
throw new NotImplementedException();
// if (bindable is TabViewControl tabViewControl && tabViewControl._carouselView != null)
// {
// tabViewControl._carouselView.HeightRequest = (double)newValue;
// }
}
public static readonly BindableProperty ContentHeightProperty = BindableProperty.Create(nameof(ContentHeight), typeof(double), typeof(TabViewControl), (double)200, BindingMode.Default, null, ContentHeightChanged);
#endregion
#region HeaderSelectionUnderlineColor
public Color HeaderSelectionUnderlineColor
{
get { return (Color)GetValue(HeaderSelectionUnderlineColorProperty); }
set { SetValue(HeaderSelectionUnderlineColorProperty, value); }
}
private static void HeaderSelectionUnderlineColorChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderSelectionUnderlineColor = (Color)newValue;
tab.TriggerPropertyChange(nameof(tab.IsCurrent));
}
}
}
public static readonly BindableProperty HeaderSelectionUnderlineColorProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineColor), typeof(Color), typeof(TabViewControl), Color.White, BindingMode.Default, null, HeaderSelectionUnderlineColorChanged);
#endregion
#region HeaderSelectionUnderlineThickness
public double HeaderSelectionUnderlineThickness
{
get { return (double)GetValue(HeaderSelectionUnderlineThicknessProperty); }
set { SetValue(HeaderSelectionUnderlineThicknessProperty, value); }
}
private static void HeaderSelectionUnderlineThicknessChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderSelectionUnderlineThickness = (double)newValue;
}
}
}
public static readonly BindableProperty HeaderSelectionUnderlineThicknessProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineThickness), typeof(double), typeof(TabViewControl), TabDefaults.DefaultThickness, BindingMode.Default, null, HeaderSelectionUnderlineThicknessChanged);
#endregion
#region HeaderSelectionUnderlineWidth
public double HeaderSelectionUnderlineWidth
{
get { return (double)GetValue(HeaderSelectionUnderlineWidthProperty); }
set { SetValue(HeaderSelectionUnderlineWidthProperty, value); }
}
private static void HeaderSelectionUnderlineWidthChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderSelectionUnderlineWidth = (double)newValue;
}
}
}
public static readonly BindableProperty HeaderSelectionUnderlineWidthProperty = BindableProperty.Create(nameof(HeaderSelectionUnderlineWidth), typeof(double), typeof(TabViewControl), (double)0, BindingMode.Default, null, HeaderSelectionUnderlineWidthChanged);
#endregion
#region HeaderTabTextFontSize
[Xamarin.Forms.TypeConverter(typeof(FontSizeConverter))]
public double HeaderTabTextFontSize
{
get { return (double)GetValue(HeaderTabTextFontSizeProperty); }
set { SetValue(HeaderTabTextFontSizeProperty, value); }
}
private static void HeaderTabTextFontSizeChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderTabTextFontSize = (double)newValue;
}
}
}
public static readonly BindableProperty HeaderTabTextFontSizeProperty = BindableProperty.Create(nameof(HeaderTabTextFontSize), typeof(double), typeof(TabViewControl), (double)14, BindingMode.Default, null, HeaderTabTextFontSizeChanged);
#endregion
#region HeaderTabTextFontFamily
public string HeaderTabTextFontFamily
{
get { return (string)GetValue(HeaderTabTextFontFamilyProperty); }
set { SetValue(HeaderTabTextFontFamilyProperty, value); }
}
private static void HeaderTabTextFontFamilyChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderTabTextFontFamily = (string)newValue;
}
}
}
public static readonly BindableProperty HeaderTabTextFontFamilyProperty = BindableProperty.Create(nameof(HeaderTabTextFontFamily), typeof(string), typeof(TabViewControl), null, BindingMode.Default, null, HeaderTabTextFontFamilyChanged);
#endregion
#region HeaderTabTextFontAttributes
public FontAttributes HeaderTabTextFontAttributes
{
get { return (FontAttributes)GetValue(HeaderTabTextFontAttributesProperty); }
set { SetValue(HeaderTabTextFontAttributesProperty, value); }
}
private static void HeaderTabTextFontAttributesChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
foreach (var tab in tabViewControl.ItemSource)
{
tab.HeaderTabTextFontAttributes = (FontAttributes)newValue;
}
}
}
public static readonly BindableProperty HeaderTabTextFontAttributesProperty = BindableProperty.Create(nameof(HeaderTabTextFontAttributes), typeof(FontAttributes), typeof(TabViewControl), FontAttributes.None, BindingMode.Default, null, HeaderTabTextFontAttributesChanged);
#endregion
#region ItemSource
public static readonly BindableProperty ItemSourceProperty = BindableProperty.Create(nameof(ItemSource), typeof(ObservableCollection<TabItem>), typeof(TabViewControl));
public ObservableCollection<TabItem> ItemSource
{
get => (ObservableCollection<TabItem>)GetValue(ItemSourceProperty);
set { SetValue(ItemSourceProperty, value); }
}
#endregion
#region TabSizeOption
public static readonly BindableProperty TabSizeOptionProperty = BindableProperty.Create(nameof(TabSizeOption), typeof(GridLength), typeof(TabViewControl), default(GridLength), propertyChanged: OnTabSizeOptionChanged);
private static void OnTabSizeOptionChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl._headerContainerGrid != null && tabViewControl.ItemSource != null)
{
foreach (var tabContainer in tabViewControl._headerContainerGrid.ColumnDefinitions)
{
tabContainer.Width = (GridLength)newValue;
}
}
}
public GridLength TabSizeOption
{
get => (GridLength)GetValue(TabSizeOptionProperty);
set { SetValue(TabSizeOptionProperty, value); }
}
#endregion
#region SelectedTabIndex
public static readonly BindableProperty SelectedTabIndexProperty = BindableProperty.Create(
nameof(SelectedTabIndex),
typeof(int),
typeof(TabViewControl),
defaultValue: 0,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnSelectedTabIndexChanged);
private static void OnSelectedTabIndexChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null)
{
tabViewControl.SetCurrentTab((int)newValue);
}
}
public int SelectedTabIndex
{
get => (int)GetValue(SelectedTabIndexProperty);
set { SetValue(SelectedTabIndexProperty, value); }
}
#endregion
public void SetCurrentTab(int position, bool initialRun = false)
{
if (SelectedTabIndex == position && !initialRun)
{
return;
}
int oldPosition = SelectedTabIndex;
var tabChangingArgs = new TabChangingEventArgs()
{
Canceled = false,
NewPosition = position,
OldPosition = oldPosition
};
OnTabChanging(ref tabChangingArgs);
if (tabChangingArgs != null && tabChangingArgs.Canceled)
{
return;
}
if (((position >= 0 && position < ItemSource.Count) || initialRun))
{
if (oldPosition < ItemSource.Count)
{
List<bool> tabActiveList = ItemSource.Select((TabItem tab, int index) =>
{
return index == position;
})
.ToList();
for (int i = 0; i < tabActiveList.Count(); i++)
{
ItemSource[i].IsCurrent = tabActiveList[i];
}
// Remove second child
if (_mainContainerSL.Children.Count == 2)
{
_mainContainerSL.Children.RemoveAt(1);
}
}
_mainContainerSL.Children.Add(ItemSource[position].Content);
SelectedTabIndex = position;
Device.BeginInvokeOnMainThread(async () => await _tabHeadersContainerSv.ScrollToAsync(_headerContainerGrid.Children[position], ScrollToPosition.MakeVisible, false));
}
var tabChangedArgs = new TabChangedEventArgs()
{
NewPosition = SelectedTabIndex,
OldPosition = oldPosition
};
OnTabChanged(tabChangedArgs);
}
public void SelectNext()
{
SetCurrentTab(SelectedTabIndex + 1);
}
public void SelectPrevious()
{
SetCurrentTab(SelectedTabIndex - 1);
}
public void SelectFirst()
{
SetCurrentTab(0);
}
public void SelectLast()
{
SetCurrentTab(ItemSource.Count - 1);
}
public void AddTab(TabItem tab, int position = -1, bool selectNewPosition = false)
{
if (position > -1)
{
ItemSource.Insert(position, tab);
}
else
{
ItemSource.Add(tab);
}
if (selectNewPosition)
{
SelectedTabIndex = position;
}
}
public void RemoveTab(int position = -1)
{
if (position > -1)
{
ItemSource.RemoveAt(position);
_headerContainerGrid.Children.RemoveAt(position);
_headerContainerGrid.ColumnDefinitions.RemoveAt(position);
}
else
{
ItemSource.Remove(ItemSource.Last());
_headerContainerGrid.Children.RemoveAt(_headerContainerGrid.Children.Count - 1);
_headerContainerGrid.ColumnDefinitions.Remove(_headerContainerGrid.ColumnDefinitions.Last());
}
SelectedTabIndex = position >= 0 && position < ItemSource.Count ? position : ItemSource.Count - 1;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Globalization;
using Xamarin.Forms;
namespace Aurora.Design.Converters
{
public class DoubleToLayoutOptionsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = double.TryParse(value.ToString(), out double val);
if (result && val > 0)
{
return LayoutOptions.CenterAndExpand;
}
return LayoutOptions.FillAndExpand;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Globalization;
using Xamarin.Forms;
namespace Aurora.Design.Converters
{
public class InverseBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool))
{
throw new InvalidOperationException("The target must be a boolean");
}
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Globalization;
using Xamarin.Forms;
namespace Aurora.Design.Converters
{
public class NullToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace Aurora.Design.Converters
{
public class PlayIconConverter
{
public PlayIconConverter()
{
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Globalization;
using Aurora.Design.Components.TabView;
using Xamarin.Forms;
namespace Aurora.Design.Converters
{
class SelectedTabHeaderToTabBackgroundColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isCurrentTabSelected = false;
if (!string.IsNullOrWhiteSpace(value?.ToString()))
bool.TryParse(value.ToString(), out isCurrentTabSelected);
if (parameter is TabViewControl tvc && isCurrentTabSelected)
{
return tvc.HeaderSelectionUnderlineColor;
}
else
{
return Color.Transparent;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Globalization;
using Xamarin.Forms;
namespace Aurora.Design.Converters
{
public class ToUpperConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString().ToUpper();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Linq;
using System.Reflection;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Aurora.Design.Extensions
{
[ContentProperty(nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
{
return null;
}
Assembly[] referencedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var gtkAsm = referencedAssemblies.FirstOrDefault((e) =>
{
return e.FullName.Contains("Aurora.gtk");
});
foreach (var res in gtkAsm.GetManifestResourceNames())
{
Console.WriteLine("found resource: " + res);
}
if (gtkAsm == null && gtkAsm is Assembly)
{
return null;
}
// Do your translation lookup here, using whatever method you require
var imageSource = ImageSource.FromResource(Source, gtkAsm);
return imageSource;
}
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Views.Albums.AlbumsView">
<ContentPage.Content>
<Grid></Grid>
</ContentPage.Content>
</ContentView>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.Albums
{
public partial class AlbumsView : ContentView
{
public AlbumsView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace Aurora.Design.Views.Albums
{
public class AlbumsViewModel : BaseViewModel
{
public AlbumsViewModel()
{
}
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Views.Artists.ArtistsView">
<ContentView.Content>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.Artists
{
public partial class ArtistsView : ContentView
{
public ArtistsView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace Aurora.Design.Views.Artists
{
public class TestObj
{
public string Test1 { get; set; }
public string Test2 { get; set; }
}
public class ArtistsViewModel : BaseViewModel
{
public ArtistsViewModel()
{
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using Aurora.Design.Views.Main;
namespace Aurora.Design.Views
{
public class BaseDialogViewModel : BaseViewModel
{
public BaseDialogViewModel()
{
}
public FinishDialogDelegate Finish { get; set; }
public object ReturnObject { get; protected set; }
}
}

View File

@ -0,0 +1,104 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Aurora.Models.Media;
using Xamarin.Forms;
using Aurora.Design.Views.Main;
namespace Aurora.Design.Views
{
public class BaseViewModel : INotifyPropertyChanged
{
public BaseViewModel()
{
}
#region Player
/// <summary>
/// Command event handler for player play button
/// </summary>
public virtual void OnPlayButtonCommandExecute() { }
public virtual bool CanPlayButtonCommandExecute()
{
return true;
}
/// <summary>
/// Command event handler for player next button
/// </summary>
public virtual void OnNextButtonExecute() { }
public virtual bool CanNextButtonCommandExecute()
{
return true;
}
/// <summary>
/// Command event handler for player previous button
/// </summary>
public virtual void OnPreviousButtonExecute() { }
public virtual bool CanPreviousButtonCommandExecute()
{
return true;
}
/// <summary>
/// Delegate for interacting with main screen player control
/// </summary>
/// <value></value>
public SetPlayerDelegate ChangePlayerState { get; set; }
/// <summary>
/// Delegate for checking if main screen player control is currently playing
/// </summary>
/// <value></value>
public GetIsPlayingDelegate IsPlaying { get; set; }
public ShowModalDelegate ShowModal { get; set; }
public HideModalDelegate HideModal { get; set; }
#endregion Player
#region Lifecycle
/// <summary>
/// Called by main screen on view appearing
/// </summary>
/// <typeparam name="object"></typeparam>
/// <returns></returns>
public virtual Task OnActive() { return Task.FromResult<object>(null); }
/// <summary>
/// Called by main screen on view disappearing
/// </summary>
/// <typeparam name="object"></typeparam>
/// <returns></returns>
public virtual Task OnInactive() { return Task.FromResult<object>(null); }
#endregion
#region INotifyPropertyChanged Implementation
public bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged == null)
return;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}

View File

@ -0,0 +1,41 @@
#Header {
background-color: transparent;
margin-top: 10;
}
#Header > Entry {
margin-left: 155;
margin-top: 2;
margin-bottom: 2;
}
#TitleContainer {
margin-top: 10;
margin-left: 10;
background-color: transparent;
}
#TitleContainer Label {
color: white;
margin-left: 155;
font-size: 22;
vertical-align: bottom;
}
#Player {
background-color: #303030;
height: 60;
}
#Content {
margin-right: 10;
}
#Modal {
height: 500;
width: 400;
margin-top: 20;
margin-bottom: 20;
border-radius: 15;
background-color: #626363;
}

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Aurora.Design.Views.MainView"
xmlns:navigation="clr-namespace:Aurora.Design.Components.NavigationMenu"
xmlns:mp="clr-namespace:Aurora.Design.Components.MediaPlayer"
xmlns:dialog="clr-namespace:Aurora.Design.Components.Dialogs"
x:Class="Aurora.Design.Views.Main.MainView"
StyleClass="primaryColor">
<ContentPage.Resources>
<StyleSheet
Source="MainView.css"/>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--Header-->
<StackLayout
x:Name="Header"
Grid.Row="0"
Grid.ColumnSpan="2"
Orientation="Horizontal">
<Entry Text="Search"/>
</StackLayout>
<!--Title-->
<StackLayout
Grid.Row="1"
Grid.ColumnSpan="2"
x:Name="TitleContainer">
<Label Text="{Binding Title}" TextColor="White"/>
</StackLayout>
<!--Sidebar-->
<navigation:NavigationMenu
Grid.Column="0"
Grid.RowSpan="3"
x:Name="MasterPage"
Items="{Binding Pages}"
SelectedItem="{Binding SelectedItem}"/>
<!--Page Container-->
<views:PageContainer
Grid.Column="1"
Grid.Row="2"
x:Name="Content"/>
<!--Modal Dialog-->
<dialog:Modal x:Name="Modal"
Grid.Column="1"
Grid.Row="2"
StyleClass="secondAccentColor"
HorizontalOptions="Center"
VerticalOptions="End"/>
<!--Music Player-->
<mp:Player
StyleClass="secondAccentColor"
x:Name="Player"
Grid.Row="3"
Grid.ColumnSpan="2"/>
</Grid>
</ContentPage>

View File

@ -0,0 +1,263 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Aurora.Design.Components.NavigationMenu;
using Aurora.Design.Views.MainView;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Aurora.Models.Media;
using Aurora.Design.Components.MediaPlayer;
using Aurora.Services.Player;
using Autofac;
namespace Aurora.Design.Views.Main
{
public enum PlayAction
{
Play,
Pause,
Resume,
Stop
}
/// <summary>
/// Delegate for updating player metadata
/// </summary>
/// <param name="media"></param>
public delegate Task SetPlayerDelegate(BaseMedia media, PlayAction action);
public delegate bool GetIsPlayingDelegate();
public delegate void ShowModalDelegate(Type view, BaseDialogViewModel viewModel);
public delegate void HideModalDelegate();
public delegate void FinishDialogDelegate();
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainView : ContentPage//, IDisposable
{
private Dictionary<int, BaseViewModel> _viewModels;
private BaseViewModel _lastViewModel;
private Player _playerComponent;
private IPlayer _playerService;
private ContentPresenter _viewContent;
public MainView(IPlayer player)
{
InitializeComponent();
BindingContext = new MainViewModel();
_viewModels = new Dictionary<int, BaseViewModel>();
_playerComponent = Player;
_viewContent = (ContentPresenter)Content.FindByName("ViewContent");
_playerService = player;
MasterPage.ListView.ItemSelected += OnNavItemSelected;
Appearing += OnAppearing;
}
public void Dispose()
{
Appearing -= OnAppearing;
}
/// <summary>
/// Event handler for side bar items being selected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnNavItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as NavigationItem;
if (item == null)
return;
var view = (View)Activator.CreateInstance(item.TargetType);
//Check if we have an instantiated viewModel
BaseViewModel vm = new BaseViewModel();
if (_viewModels.ContainsKey(item.Id))
{
_viewModels.TryGetValue(item.Id, out vm);
}
else
{
if (item.TargetViewModelType.BaseType != typeof(BaseViewModel))
{
throw new InvalidOperationException("TargetViewModel field must be of type BaseViewModel");
}
//Instantiate new view model
vm = (BaseViewModel)App.Container.Resolve(item.TargetViewModelType); //Activator.CreateInstance(item.TargetViewModelType);
_viewModels.Add(item.Id, vm);
}
//Assign player controls to viewmodel
AssignPlayerControls(vm);
ChangeModalVisiblity(false);
//Activate viewmodel
vm.OnActive();
//Deactivate last viewModel
_lastViewModel.OnInactive();
//Unasign deactivating vm
UnassignPlayerControls(_lastViewModel);
//Assign viewModel
_lastViewModel = vm;
view.BindingContext = vm;
_viewContent.Content = view;
}
/// <summary>
/// Event handler for page appearing.
/// </summary>
/// <param name="sender">The object that fired the event.</param>
/// <param name="args">The event arguments</param>
private void OnAppearing(object sender, EventArgs args)
{
//Set initial view from first item in list
ObservableCollection<NavigationGroupItem> screenList = (ObservableCollection<NavigationGroupItem>)MasterPage.ListView.ItemsSource;
//Assign viewModel
NavigationItem firstNavItem = screenList.FirstOrDefault().FirstOrDefault();
var view = (View)Activator.CreateInstance(firstNavItem.TargetType);
BaseViewModel vm = new BaseViewModel();
if (_viewModels.ContainsKey(firstNavItem.Id))
{
_viewModels.TryGetValue(firstNavItem.Id, out vm);
}
else
{
//Instantiate new view model
vm = (BaseViewModel)App.Container.Resolve(firstNavItem.TargetViewModelType); //(BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType);
_viewModels.Add(firstNavItem.Id, vm);
}
view.BindingContext = vm;
_lastViewModel = vm;
AssignPlayerControls(vm);
ChangeModalVisiblity(false);
vm.OnActive();
_viewContent.Content = view;
}
/// <summary>
/// Unassign setplayer delegate to prevent vms from changing player info when inactive
/// </summary>
/// <param name="vm"></param>
private void UnassignPlayerControls(BaseViewModel vm)
{
vm.ChangePlayerState = null;
vm.IsPlaying = null;
vm.ShowModal = null;
}
/// <summary>
/// Assign main views music player controls to a view model
/// </summary>
/// <param name="vm">BaseViewModel to assign controls to</param>
private void AssignPlayerControls(BaseViewModel vm)
{
_playerComponent.PlayButtonCommand = new Command(vm.OnPlayButtonCommandExecute, vm.CanPlayButtonCommandExecute);
_playerComponent.NextButtonCommand = new Command(vm.OnNextButtonExecute, vm.CanNextButtonCommandExecute);
_playerComponent.PreviousButtonCommand = new Command(vm.OnPreviousButtonExecute, vm.CanPreviousButtonCommandExecute);
vm.ChangePlayerState = ChangePlayerState;
vm.IsPlaying = () =>
{
return _playerService.PlaybackState == PlaybackState.Playing;
};
vm.ShowModal = this.ShowModal;
vm.HideModal = this.HideModal;
}
/// <summary>
/// Delegate handler for a view model controling music playback
/// </summary>
/// <param name="media"></param>
/// <param name="action"></param>
/// <returns></returns>
private async Task ChangePlayerState(BaseMedia media, PlayAction action)
{
if (media != null && media.Metadata is AudioMetadata)
{
AudioMetadata meta = (AudioMetadata)media.Metadata;
_playerComponent.ArtistName = meta.Artist;
_playerComponent.SongTitle = meta.Title;
}
switch (action)
{
case PlayAction.Pause:
{
_playerService.Pause();
_playerComponent.IsPlaying = false;
break;
}
case PlayAction.Play:
{
if (media == null)
{
break;
}
if (!_playerService.IsMediaLoaded(media))
{
await _playerService.LoadMedia(media).ConfigureAwait(true);
}
_playerService.Play();
_playerComponent.IsPlaying = true;
break;
}
case PlayAction.Resume:
{
_playerService.Play();
_playerComponent.IsPlaying = true;
break;
}
case PlayAction.Stop:
{
_playerService.Stop();
_playerComponent.IsPlaying = false;
break;
}
}
}
private void ShowModal(Type view, BaseDialogViewModel viewModel)
{
ContentPresenter modalContainer = (ContentPresenter)Modal.FindByName("ViewContent");
var vw = (View)Activator.CreateInstance(view);
vw.BindingContext = viewModel;
//Set modal container content
modalContainer.Content = vw;
//Set visibility
ChangeModalVisiblity(true);
}
private void HideModal()
{
ChangeModalVisiblity(false);
}
private void ChangeModalVisiblity(bool isVisible)
{
Modal.IsVisible = isVisible;
Content.IsVisible = !isVisible;
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Aurora.Design.Components.NavigationMenu;
using Aurora.Design.Views.Albums;
using Aurora.Design.Views.Artists;
using Aurora.Design.Views.Songs;
using Aurora.Design.Views.Stations;
using Aurora.Design.Views.Party;
using Aurora.Design.Views.Profile;
namespace Aurora.Design.Views.MainView
{
public class MainViewModel : BaseViewModel
{
private ObservableCollection<NavigationItem> _pages;
public ObservableCollection<NavigationItem> Pages
{
get { return _pages; }
set
{
if (value != _pages)
{
_pages = value;
OnPropertyChanged("Pages");
}
}
}
private NavigationItem _selectedItem;
public NavigationItem SelectedItem
{
get
{
return _selectedItem;
}
set
{
SetProperty(ref _selectedItem, value);
OnPropertyChanged("Title");
}
}
public string Title
{
get
{
return (_selectedItem != null && !string.IsNullOrWhiteSpace(_selectedItem.Title)) ?
_selectedItem.Title : "";
}
}
public MainViewModel()
{
_pages = new ObservableCollection<NavigationItem>(new[]
{
new NavigationItem { Id = 0, Title = "Songs", Group="Your Music", TargetType = typeof(SongsView), TargetViewModelType = typeof(SongsViewModel) },
new NavigationItem { Id = 1, Title = "Artists", Group="Your Music", TargetType = typeof(ArtistsView), TargetViewModelType = typeof(ArtistsViewModel)},
new NavigationItem { Id = 2, Title = "Albums", Group="Your Music", TargetType = typeof(AlbumsView), TargetViewModelType = typeof(AlbumsViewModel)},
new NavigationItem { Id = 3, Title = "Stations", Group="Your Music", TargetType = typeof(StationsView), TargetViewModelType = typeof(StationsViewModel)},
new NavigationItem { Id = 4, Title = "Party", Group="Social", TargetType = typeof(PartyView), TargetViewModelType = typeof(PartyViewModel)},
new NavigationItem { Id = 5, Title = "Profile", Group="Social", TargetType = typeof(ProfileView), TargetViewModelType = typeof(ProfileViewModel)},
new NavigationItem { Id = 6, Title = "A + B", Group="Playlists", TargetType = typeof(StationsView), TargetViewModelType = typeof(StationsViewModel)}
});
}
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Views.MainView.PageContainer">
<ContentView.Content>
<Grid
x:Name="Grid">
<ContentPresenter
x:Name="ViewContent"/>
</Grid>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.MainView
{
public partial class PageContainer : ContentView
{
public PageContainer()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,20 @@
using System;
namespace Aurora.Design.Views.Party.NewPartyDialog
{
public enum ConnectionType
{
Host,
Join
}
public class ConnectionDetails
{
public ConnectionDetails()
{
}
public string HostName { get; set; }
public ConnectionType ConnectionType { get; set; }
}
}

View File

@ -0,0 +1,25 @@
#View {
width: 300;
height: 500;
}
#DialogTitle {
text-align: center;
text-align-last: center;
margin-top: 20;
margin-bottom: 40;
margin-left: 20;
margin-right: 30;
color: white;
font-size: 50;
word-wrap: break-word;
}
#Container {
background-color: transparent;
}
Button {
background-color: transparent;
}

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Views.Party.NewPartyDialog.NewPartyDialog"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<ContentView.Resources>
<StyleSheet
Source="NewPartyDialog.css"/>
</ContentView.Resources>
<ContentView.Content>
<StackLayout
HorizontalOptions="FillAndExpand"
Orientation="Vertical">
<Label
x:Name="DialogTitle"
LineBreakMode="WordWrap"
Text="Join or Host a Party"/>
<StackLayout
x:Name="Container"
Orientation="Horizontal"
HorizontalOptions="Center"
VerticalOptions="Start">
<Entry
Text="{Binding Hostname}"
Placeholder="Enter a hostname"
x:Name="HostnameEntry"/>
<StackLayout
Orientation="Horizontal"
HorizontalOptions="Center">
<Button
HorizontalOptions="Center"
x:Name="buttonHost"
Text="Host"
Command="{Binding HostCommand}"/>
<Button
HorizontalOptions="Center"
x:Name="buttonClient"
Text="Join"
Command="{Binding JoinCommand}"/>
</StackLayout>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.Party.NewPartyDialog
{
public partial class NewPartyDialog : ContentView
{
public NewPartyDialog()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using Xamarin.Forms;
namespace Aurora.Design.Views.Party.NewPartyDialog
{
public class NewPartyDialogViewModel : BaseDialogViewModel
{
public NewPartyDialogViewModel()
{
this.ReturnObject = new ConnectionDetails();
HostCommand = new Command(OnHostExecute, OnHostCanExecute);
JoinCommand = new Command(OnJoinExecute, OnJoinCanCanExecute);
}
public string Hostname
{
get
{
if (ReturnObject is ConnectionDetails)
{
ConnectionDetails obj = ReturnObject as ConnectionDetails;
return obj.HostName;
};
return string.Empty;
}
set
{
if (ReturnObject is ConnectionDetails)
{
ConnectionDetails obj = ReturnObject as ConnectionDetails;
if (value != obj.HostName)
{
obj.HostName = value;
}
OnPropertyChanged(Hostname);
HostCommand.ChangeCanExecute();
JoinCommand.ChangeCanExecute();
}
}
}
public void OnHostExecute()
{
ConnectionDetails obj = base.ReturnObject as ConnectionDetails;
obj.ConnectionType = ConnectionType.Host;
Finish();
}
public Command HostCommand { get; private set; }
public Command JoinCommand { get; private set; }
public bool OnHostCanExecute()
{
return string.IsNullOrWhiteSpace(Hostname);
}
public void OnJoinExecute()
{
ConnectionDetails obj = base.ReturnObject as ConnectionDetails;
obj.ConnectionType = ConnectionType.Join;
Finish();
}
public bool OnJoinCanCanExecute()
{
return !string.IsNullOrWhiteSpace(Hostname);
}
}
}

View File

@ -0,0 +1,37 @@
Label {
height: 20;
}
#MembersList {
height: 100;
background-color: transparent;
}
#LeaveButton {
margin-top: 20;
margin-bottom: 20;
vertical-align: bottom;
align-self: center;
}
#MembersList {
background-color: #1e1e1e;
}
#MembersList Grid {
margin-left: 20;
margin-right: 20;
margin-top: 20;
margin-bottom: 20;
width: 150;
border-radius: 25;
background-color: #626363;
}
#MembersList Label {
text-align: center;
vertical-align: middle;
color: white;
font-size: 20;
}

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tabView="clr-namespace:Aurora.Design.Components.TabView"
xmlns:ml="clr-namespace:Aurora.Design.Components.MemberList"
xmlns:library="clr-namespace:Aurora.Design.Components.Library"
xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"
x:Class="Aurora.Design.Views.Party.PartyView">
<ContentView.Resources>
<StyleSheet
Source="./PartyView.css"/>
</ContentView.Resources>
<ContentView.Content>
<StackLayout
x:Name="TabHeader">
<tabView:TabViewControl
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
TabSizeOption="100"
SelectedTabIndex="{Binding SelectedTabIndex}"
HeaderBackgroundColor="#181818"
x:Name="TabView">
<tabView:TabViewControl.ItemSource>
<!-- Members Tab -->
<tabView:TabItem
HeaderText="Members">
<Grid
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition
Height="*"/>
<RowDefinition
Height="30"/>
</Grid.RowDefinitions>
<ml:MemberList
x:Name="MembersList"
Grid.Row="0"
VerticalOptions="FillAndExpand"
Members="{Binding Members}"/>
<!-- Leave Party Button -->
<Button
Grid.Row="1"
Text="Leave Party"
Command="{Binding LeavePartyCommand}"/>
</Grid>
</tabView:TabItem>
<!-- Library Tab -->
<tabView:TabItem
HeaderText="Queue">
<library:Library
ItemsSource="{Binding Queue}"
SelectedItem="{Binding SelectedSong}"
ItemDoubleClicked="{Binding PlayCommand}"/>
</tabView:TabItem>
</tabView:TabViewControl.ItemSource>
</tabView:TabViewControl>
</StackLayout>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,13 @@
using System;
using Xamarin.Forms;
namespace Aurora.Design.Views.Party
{
public partial class PartyView : ContentView
{
public PartyView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,577 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using System.Linq;
using Xamarin.Forms;
using Aurora.Proto.Party;
using Aurora.Models.Media;
using Aurora.Services.Client;
using Aurora.Design.Views.Party.NewPartyDialog;
using Aurora.Services.Settings;
using Aurora.Services.Server;
using Aurora.Services.EventManager;
using Grpc.Core;
namespace Aurora.Design.Views.Party
{
//TODO refactor
enum PartyState
{
SelectingHost,
InParty,
Hosting,
Connecting,
}
delegate void EventHandler(BaseEvent e);
public class PartyViewModel : BaseViewModel
{
private PartyState _state;
private string _hostname = "";
private ObservableCollection<Member> _members;
private ObservableCollection<BaseMedia> _queue;
private BaseMedia _selectedMedia;
private ISettingsService _settingsService;
private IClientService _clientService;
private IServerService _serverService;
private IEventManager _eventManager;
private CancellationTokenSource _eventCancellationTokenSource;
private Dictionary<BaseEvent.DerivedEventOneofCase, EventHandler> _eventHandlers;
private int _selectedTabIndex;
public PartyViewModel(
ISettingsService settingsService,
IServerService serverService,
IEventManager eventManager,
IClientService clientService)
{
_members = new ObservableCollection<Member>();
_queue = new ObservableCollection<BaseMedia>();
this._settingsService = settingsService;
this._serverService = serverService;
this._eventManager = eventManager;
this._clientService = clientService;
SetState(PartyState.SelectingHost);
PlayCommand = new Command(OnDoubleClickCommandExecute, CanDoubleClickCommandExecute);
LeavePartyCommand = new Command(OnLeavePartyCommandExecute, CanLeavePartyCommandExecute);
//Setup event handlers
_eventHandlers = new Dictionary<BaseEvent.DerivedEventOneofCase, EventHandler>()
{
{BaseEvent.DerivedEventOneofCase.MediaPausedEvent, this.OnRemoteMediaPaused},
{BaseEvent.DerivedEventOneofCase.MediaResumedEvent, this.OnRemoteMediaResumed},
{BaseEvent.DerivedEventOneofCase.NewMediaPlayingEvent, this.OnNewRemoteMediaPlaying},
{BaseEvent.DerivedEventOneofCase.MemberCreatedEvent, this.OnPartyMemberJoined},
{BaseEvent.DerivedEventOneofCase.MemberDeletedEvent, this.OnPartyMemberLeft}
};
}
#region Properties
public int SelectedTabIndex
{
get { return _selectedTabIndex; }
set { SetProperty(ref _selectedTabIndex, value); }
}
/// <summary>
/// Publc property for the members list
/// </summary>
/// <value></value>
public ObservableCollection<Member> Members
{
get
{
return _members;
}
set
{
SetProperty(ref _members, value);
}
}
/// <summary>
/// Public property for queue item source
/// </summary>
/// <value></value>
public ObservableCollection<BaseMedia> Queue
{
get
{
return _queue;
}
set
{
if (value != _queue)
{
SetProperty(ref _queue, value);
}
}
}
/// <summary>
/// Public property for the currently selected song.
/// </summary>
/// <value></value>
public BaseMedia SelectedSong
{
get { return _selectedMedia; }
set { SetProperty(ref _selectedMedia, value); }
}
/// <summary>
/// Public property for playing media
/// </summary>
/// <value></value>
public Command PlayCommand { get; private set; }
public Command LeavePartyCommand { get; private set; }
#endregion Properties
#region Events
/// <summary>
/// Called by framework when view becomes active
/// </summary>
/// <returns></returns>
public override async Task OnActive()
{
OnPropertyChanged("SelectedTabIndex");
if (this._state == PartyState.Hosting ||
this._state == PartyState.InParty)
{
await this.GetEvents().ConfigureAwait(false);
}
else
{
//Open host selection modal
NewPartyDialogViewModel vm = new NewPartyDialogViewModel();
ConnectionDetails details = new ConnectionDetails();
vm.Finish = () =>
{
this.HideModal();
details = vm.ReturnObject as ConnectionDetails;
_hostname = details.HostName;
switch (details.ConnectionType)
{
case ConnectionType.Host:
{
OnHostCommandExecute();
break;
}
case ConnectionType.Join:
{
OnJoinCommandExecute();
break;
}
}
};
this.ShowModal(typeof(NewPartyDialog.NewPartyDialog), vm);
}
}
/// <summary>
/// Called by framework when view becomes inactive
/// </summary>
/// <returns></returns>
public override Task OnInactive()
{
if(this._eventCancellationTokenSource != null){
this._eventCancellationTokenSource.Cancel();
}
return Task.FromResult<object>(null);
}
/// <summary>
/// Remote media paused event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnRemoteMediaPaused(BaseEvent e)
{
StopPlaying();
}
/// <summary>
/// Remote playing new media event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnNewRemoteMediaPlaying(BaseEvent e)
{
PlayFromBeginning(GetMediaFromQueue(e.NewMediaPlayingEvent.Media.Name));
}
/// <summary>
/// Remote resumed playing event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnRemoteMediaResumed(BaseEvent e)
{
PlayResume();
}
/// <summary>
/// Member joined party event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnPartyMemberJoined(BaseEvent e)
{
Members.Add(e.MemberCreatedEvent.Member);
}
/// <summary>
/// Member left party event
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
public void OnPartyMemberLeft(BaseEvent e)
{
var found = Members.Where(x => x.Name == e.MemberDeletedEvent.MemberName);
foreach (Member member in found)
{
_members.Remove(member);
}
}
#endregion Events
#region Commands
private async void OnJoinCommandExecute()
{
SetState(PartyState.Connecting);
_clientService.Start(_hostname, this._settingsService.DefaultPort.ToString());
await JoinParty(false);
//TODO add cancellation token
try
{
SetState(PartyState.InParty);
await GetEvents().ConfigureAwait(true);
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred while receiviing events: ", ex.Message);
}
}
private bool CanJoinCommandExecute()
{
return true;
}
private async void OnHostCommandExecute()
{
//Change state
SetState(PartyState.Connecting);
_serverService.Start("test", "asdf");
string localHost = ServerService.GetLocalIPAddress();
_clientService.Start(localHost, this._settingsService.DefaultPort.ToString());
await JoinParty(true);
//TODO add cancellation token
try
{
SetState(PartyState.Hosting);
await GetEvents().ConfigureAwait(false);
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred while receiviing events: ", ex.Message);
}
}
private bool CanHostCommandExecute()
{
return true;
}
private async void OnLeavePartyCommandExecute()
{
await _clientService.RemotePartyServiceClient.DeleteMemberAsync(new DeleteMemberRequest()
{
Name = _settingsService.ClientName
});
}
private bool CanLeavePartyCommandExecute()
{
return (this._state == PartyState.InParty || this._state == PartyState.Hosting) ? true : false;
}
public override void OnPlayButtonCommandExecute()
{
if (base.IsPlaying())
{
//Fire play stopped event
AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
MediaPausedEvent mediaPaused = new MediaPausedEvent();
_eventManager.FireEvent(new BaseEvent()
{
MediaPausedEvent = mediaPaused
});
}
else
{
//Fire play resume event
AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
MediaResumedEvent mediaResumed = new MediaResumedEvent();
_eventManager.FireEvent(new BaseEvent()
{
MediaResumedEvent = mediaResumed
});
}
}
public override bool CanPlayButtonCommandExecute()
{
return this._state == PartyState.Hosting;
}
public override bool CanNextButtonCommandExecute()
{
return this._state == PartyState.Hosting;
}
public override bool CanPreviousButtonCommandExecute()
{
return this._state == PartyState.Hosting;
}
/// <summary>
/// On double click execute, fire media playing event
/// </summary>
public void OnDoubleClickCommandExecute()
{
//Fire Playing event
AudioMetadata meta = _selectedMedia.Metadata as AudioMetadata;
NewMediaPlayingEvent mediaPlaying = new NewMediaPlayingEvent()
{
Media = new Media()
{
//TODO need full resource name
Name = _selectedMedia.Id,
Title = meta.Title,
Artist = meta.Artist,
Album = meta.Album,
}
};
_eventManager.FireEvent(new BaseEvent()
{
NewMediaPlayingEvent = mediaPlaying
});
}
public bool CanDoubleClickCommandExecute()
{
return this._state == PartyState.Hosting;
}
#endregion Commands
#region Private Methods
/// <summary>
/// Join the remote party.
/// </summary>
/// <returns></returns>
private async Task JoinParty(bool asHost)
{
try
{
Member resp = await _clientService.RemotePartyServiceClient.CreateMemberAsync(new CreateMemberRequest
{
Member = new Member()
{
UserName = this._settingsService.Username,
}
});
this._settingsService.ClientName = resp.Name;
await RefreshMembers();
//Subscribe to events
await SubscribeToEvents();
Queue.Clear();
ListMediaResponse mediaResponse = await _clientService.RemotePartyServiceClient.ListMediaAsync(new ListMediaRequest()
{
PageSize = 50,
Parent = "TODO"
});
//Convert received data to remote audio models
foreach (Media data in mediaResponse.Media)
{
//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.Name,
asHost,
meta,
_clientService.RemotePartyServiceClient);
Queue.Add(remote);
OnPropertyChanged("Queue");
}
}
catch (Exception ex)
{
Console.WriteLine("Error subscribing to events: " + ex.Message);
}
}
private async Task LeaveParty()
{
//Stop receiving events
// _client.StopEvents();
//Unsubscribe
await UnsubscribeFromEvents();
//Leave party
DeleteMemberRequest req = new DeleteMemberRequest()
{
Name = _settingsService.ClientName
};
await _clientService.RemotePartyServiceClient.DeleteMemberAsync(req);
}
private async Task SubscribeToEvents()
{
CreateEventSubscriptionListRequest req = new CreateEventSubscriptionListRequest();
req.Parent = this._settingsService.ClientName;
req.EventSubscriptions.Add(new EventSubscription() { Type = EventType.MemberCreated });
req.EventSubscriptions.Add(new EventSubscription() { Type = EventType.MemberDeleted });
req.EventSubscriptions.Add(new EventSubscription() { Type = EventType.MediaPlaying });
req.EventSubscriptions.Add(new EventSubscription() { Type = EventType.MediaStopped });
Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", this._settingsService.ClientName));
await _clientService.RemotePartyServiceClient.CreateEventSubscriptionListAsync(req);
}
private async Task UnsubscribeFromEvents()
{
DeleteAllEventSubscriptionsRequest unsubscribeReq = new DeleteAllEventSubscriptionsRequest();
await _clientService.RemotePartyServiceClient.DeleteAllEventSubscriptionsAsync(unsubscribeReq);
}
/// <summary>
/// Refresh members list.
/// </summary>
private async Task RefreshMembers()
{
Members.Clear();
ListMembersResponse response = await _clientService.RemotePartyServiceClient.ListMembersAsync(
new ListMembersRequest()
{
Parent = "TODO",
PageSize = 50,
});
//Add members
foreach (Member member in response.Members)
{
Members.Add(member);
}
}
private void SetState(PartyState state)
{
_state = state;
OnPropertyChanged("IsSelectingHost");
OnPropertyChanged("IsNotSelectingHost");
}
private BaseMedia GetMediaFromQueue(string Id)
{
if (_queue.Any((BaseMedia media) => media.Id == Id))
{
BaseMedia media = _queue.First((BaseMedia med) => med.Id == Id);
return media;
}
else
{
return null;
}
}
private void PlayFromBeginning(BaseMedia args)
{
base.ChangePlayerState(args, Main.PlayAction.Play);
}
private void PlayResume()
{
base.ChangePlayerState(null, Main.PlayAction.Resume);
}
private void StopPlaying()
{
base.ChangePlayerState(null, Main.PlayAction.Pause);
}
/// <summary>
/// Asynchronous function for processing events off of the event stream.
/// </summary>
/// <returns></returns>
public async Task GetEvents()
{
_eventCancellationTokenSource = new CancellationTokenSource();
string clientName = this._settingsService.ClientName;
Console.WriteLine(string.Format("CLIENT {0} - GetEvents called from client with id", clientName));
using (AsyncServerStreamingCall<BaseEvent> eventStream = _clientService.RemotePartyServiceClient
.GetEvents(new GetEventsRequest { Parent = this._settingsService.ClientName }))
{
try
{
while (!_eventCancellationTokenSource.Token.IsCancellationRequested &&
await eventStream.ResponseStream.MoveNext(_eventCancellationTokenSource.Token))
{
try
{
BaseEvent e = new BaseEvent(eventStream.ResponseStream.Current);
_eventHandlers.TryGetValue(e.DerivedEventCase, out EventHandler handler);
if (handler != null && handler != null)
{
handler.Invoke(e);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception while parsing event ---" + ex.Message);
}
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("EXCEPTION while parsing events --- " + ex.Message));
}
}
}
#endregion Private Methods
}
}

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Views.Profile.ProfileView">
<ContentView.Content>
<StackLayout
Orientation="Vertical">
<StackLayout
Orientation="Horizontal">
<Label
VerticalOptions="Center"
Text="Username"/>
<Entry
Text="{Binding Username}"/>
</StackLayout>
<StackLayout
Orientation="Horizontal">
<Label
VerticalOptions="Center"
Text="Default Port"/>
<Entry
Text="{Binding Port}"/>
</StackLayout>
<StackLayout
Orientation="Horizontal">
<Label
VerticalOptions="Center"
Text="Path to Library"/>
<Entry
Text="{Binding LibraryPath}"/>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.Profile
{
public partial class ProfileView : ContentView
{
public ProfileView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using Aurora.Services.Settings;
namespace Aurora.Design.Views.Profile
{
public class ProfileViewModel : BaseViewModel
{
private ISettingsService _settingsService;
public ProfileViewModel(ISettingsService settingsService)
{
this._settingsService = settingsService;
}
public string Username
{
get { return this._settingsService.Username; }
set
{
this._settingsService.Username = value;
OnPropertyChanged("Username");
}
}
public string Port
{
get { return this._settingsService.DefaultPort.ToString(); }
set
{
Int32.TryParse(value, out int portNum);
this._settingsService.DefaultPort = portNum;
OnPropertyChanged("Port");
}
}
public string LibraryPath
{
get { return this._settingsService.LibraryLocation; }
set
{
this._settingsService.LibraryLocation = value;
OnPropertyChanged("LibraryPath");
}
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:library="clr-namespace:Aurora.Design.Components.Library"
x:Class="Aurora.Design.Views.Songs.SongsView">
<ContentView.Content>
<library:Library
ItemsSource="{Binding SongsList}"
SelectedItem="{Binding SelectedSong}"
ItemDoubleClicked="{Binding DoubleClickCommand}"/>
</ContentView.Content>
</ContentView>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.Songs
{
public partial class SongsView : ContentView
{
public SongsView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,115 @@
using System.Collections.ObjectModel;
using Aurora.Models.Media;
using Aurora.Services.Library;
using Xamarin.Forms;
namespace Aurora.Design.Views.Songs
{
public class SongsViewModel : BaseViewModel
{
#region Fields
private ObservableCollection<BaseMedia> _songsList;
private BaseMedia _selectedSong;
private ILibraryService _libraryService;
#endregion Fields
#region Constructor
public SongsViewModel(ILibraryService libraryService)
{
_songsList = new ObservableCollection<BaseMedia>();
DoubleClickCommand = new Command(OnDoubleClickExecute, OnDoubleClickCanExecute);
this._libraryService = libraryService;
Initialize();
}
#endregion Constructor
#region Properties
public ObservableCollection<BaseMedia> SongsList
{
get { return _songsList; }
set { SetProperty(ref _songsList, value); }
}
public BaseMedia SelectedSong
{
get { return _selectedSong; }
set { SetProperty(ref _selectedSong, value); }
}
public Command DoubleClickCommand { get; private set; }
#endregion Properties
#region Methods
public void Initialize()
{
SongsList = this._libraryService.GetLibrary();
}
#endregion Methods
#region Commmands
public override bool CanPreviousButtonCommandExecute()
{
return true;
}
public override void OnPreviousButtonExecute()
{
}
public override bool CanPlayButtonCommandExecute()
{
return true;
}
public override void OnPlayButtonCommandExecute()
{
if (_selectedSong == null)
{
return;
}
if (base.IsPlaying())
{
base.ChangePlayerState(_selectedSong, Main.PlayAction.Pause);
}
else
{
base.ChangePlayerState(_selectedSong, Main.PlayAction.Play);
}
}
public override bool CanNextButtonCommandExecute()
{
return true;
}
public override void OnNextButtonExecute()
{
}
public void OnDoubleClickExecute()
{
if (_selectedSong == null)
{
return;
}
base.ChangePlayerState(_selectedSong, Main.PlayAction.Play);
}
public bool OnDoubleClickCanExecute()
{
return true;
}
#endregion Commands
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Aurora.Design.Views.Stations.StationsView">
<ContentPage.Content></ContentPage.Content>
</ContentView>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Aurora.Design.Views.Stations
{
public partial class StationsView : ContentView
{
public StationsView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace Aurora.Design.Views.Stations
{
public class StationsViewModel : BaseViewModel
{
public StationsViewModel()
{
}
}
}