diff --git a/Aurora.gtk/Aurora.gtk.csproj b/Aurora.gtk/Aurora.gtk.csproj index f8b3f26..34acb22 100644 --- a/Aurora.gtk/Aurora.gtk.csproj +++ b/Aurora.gtk/Aurora.gtk.csproj @@ -158,6 +158,12 @@ ..\packages\OpenTK.GLControl.3.0.1\lib\net20\OpenTK.GLControl.dll + + ..\packages\DLToolkit.Forms.Controls.FlowListView.2.0.11\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+netstandard1.0\DLToolkit.Forms.Controls.FlowListView.dll + + + ..\packages\CarouselView.FormsPlugin.5.2.0\lib\netstandard2.0\CarouselView.FormsPlugin.Abstractions.dll + diff --git a/Aurora.gtk/Program.cs b/Aurora.gtk/Program.cs index db0296c..b3ef8c5 100644 --- a/Aurora.gtk/Program.cs +++ b/Aurora.gtk/Program.cs @@ -1,7 +1,6 @@ using System; using LibVLCSharp.Forms.Shared; using Xamarin.Forms.Platform.GTK; -using Xamarin.Forms.Platform.GTK.Helpers; namespace Aurora.gtk { @@ -12,6 +11,8 @@ namespace Aurora.gtk { Gtk.Application.Init(); LibVLCSharpFormsRenderer.Init(); + DLToolkit.Forms.Controls.FlowListView.Init(); + // For some reason, Xamarin does not pick the LibVLCSharp.Form.Platforms.Gtk assembly as a renderer assembly. // Add it manually. diff --git a/Aurora.gtk/packages.config b/Aurora.gtk/packages.config index 5a9a979..652707f 100644 --- a/Aurora.gtk/packages.config +++ b/Aurora.gtk/packages.config @@ -1,5 +1,7 @@  + + diff --git a/Aurora/App.css b/Aurora/App.css new file mode 100644 index 0000000..277a308 --- /dev/null +++ b/Aurora/App.css @@ -0,0 +1,7 @@ +.primaryColor { + background-color: #232323; +} + +.accentColor { + background-color: #3a3a3a; +} \ No newline at end of file diff --git a/Aurora/App.xaml b/Aurora/App.xaml index f995cb5..ffbf554 100644 --- a/Aurora/App.xaml +++ b/Aurora/App.xaml @@ -24,6 +24,8 @@ x:Key="InverseBoolConverter"/> + \ No newline at end of file diff --git a/Aurora/Aurora.csproj b/Aurora/Aurora.csproj index 11afbaa..1c6f392 100644 --- a/Aurora/Aurora.csproj +++ b/Aurora/Aurora.csproj @@ -21,6 +21,8 @@ + + @@ -37,7 +39,6 @@ - @@ -47,6 +48,7 @@ + diff --git a/Aurora/Design/Components/MemberList/MemberList.css b/Aurora/Design/Components/MemberList/MemberList.css new file mode 100644 index 0000000..cbb6fa2 --- /dev/null +++ b/Aurora/Design/Components/MemberList/MemberList.css @@ -0,0 +1,12 @@ +Frame { + margin-left: 20; + margin-right: 20; + margin-top: 20; + margin-bottom: 20; + width: 80; +} + +Frame Label { + color: black; + background-color: white; +} \ No newline at end of file diff --git a/Aurora/Design/Components/MemberList/MemberList.xaml b/Aurora/Design/Components/MemberList/MemberList.xaml index c000d99..df906ce 100644 --- a/Aurora/Design/Components/MemberList/MemberList.xaml +++ b/Aurora/Design/Components/MemberList/MemberList.xaml @@ -3,23 +3,30 @@ xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:hl="clr-namespace:Aurora.Design.Components.HorizontalList" + xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView" x:Class="Aurora.Design.Components.MemberList.MemberList"> + + + - - - - - - - - - + + + + + + + \ No newline at end of file diff --git a/Aurora/Design/Components/MemberList/MemberList.xaml.cs b/Aurora/Design/Components/MemberList/MemberList.xaml.cs index f676404..7a61fe4 100644 --- a/Aurora/Design/Components/MemberList/MemberList.xaml.cs +++ b/Aurora/Design/Components/MemberList/MemberList.xaml.cs @@ -1,16 +1,16 @@ 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 { - private static ObservableCollection _newSource; - // private static NotifyCollectionChangedEventHandler _collectionChangedHandler; public MemberList() { InitializeComponent(); @@ -55,60 +55,11 @@ namespace Aurora.Design.Components.MemberList private static void OnMembersChanged(BindableObject bindable, object oldValue, object newValue) { var control = (MemberList)bindable; - var membersList = control.FindByName("MembersHorizontalList") as HorizontalList.HorizontalList; - if (membersList != null) + var membersList = control.FindByName("MembersList") as FlowListView; + + if (newValue is ICollection source) { - _newSource = newValue as ObservableCollection; - membersList.ItemsSource = new ObservableCollection(_newSource); - - //Setup collection changed listeners - //TODO evaluate for memory leak - _newSource.CollectionChanged += (sender, e) => HandleCollectionChanged(sender, e, bindable); - } - } - - private static void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e, BindableObject bindable) - { - MemberList self = bindable as MemberList; - var membersList = self.FindByName("MembersHorizontalList") as HorizontalList.HorizontalList; - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - { - foreach (PartyMember member in e.NewItems) - { - membersList.ItemsSource.Add(member); - } - - break; - } - case NotifyCollectionChangedAction.Remove: - { - foreach (PartyMember member in e.NewItems) - { - //Find all matches - var sourceMembers = membersList.ItemsSource.Where((object obj) => - { - bool match = false; - if (obj is PartyMember) - { - PartyMember tmp = obj as PartyMember; - match = tmp.Id == member.Id; - } - - return match; - }); - - //Remove found matches - foreach (object obj in sourceMembers) - { - membersList.ItemsSource.Remove(obj); - } - } - - break; - } + membersList.FlowItemsSource = source; } } } diff --git a/Aurora/Design/Components/TabView/TabItem.cs b/Aurora/Design/Components/TabView/TabItem.cs new file mode 100644 index 0000000..9e1ff02 --- /dev/null +++ b/Aurora/Design/Components/TabView/TabItem.cs @@ -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); } + } + } +} \ No newline at end of file diff --git a/Aurora/Design/Components/TabView/TabView.cs b/Aurora/Design/Components/TabView/TabView.cs new file mode 100644 index 0000000..659e42f --- /dev/null +++ b/Aurora/Design/Components/TabView/TabView.cs @@ -0,0 +1,554 @@ +// 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 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(); + + _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(0, 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), typeof(TabViewControl)); + public ObservableCollection ItemSource + { + get => (ObservableCollection)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), 0, 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 && _mainContainerSL.Children.Count == 2) + { + ItemSource[oldPosition].IsCurrent = false; + //Remove second child + _mainContainerSL.Children.RemoveAt(1); + } + _mainContainerSL.Children.Add(ItemSource[position].Content); + ItemSource[position].IsCurrent = true; + 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; + } + } +} \ No newline at end of file diff --git a/Aurora/Design/Converters/DoubleToLayoutOptions.cs b/Aurora/Design/Converters/DoubleToLayoutOptions.cs new file mode 100644 index 0000000..eb690cb --- /dev/null +++ b/Aurora/Design/Converters/DoubleToLayoutOptions.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/Aurora/Design/Converters/NullToBullConverter.cs b/Aurora/Design/Converters/NullToBullConverter.cs new file mode 100644 index 0000000..45a2b4a --- /dev/null +++ b/Aurora/Design/Converters/NullToBullConverter.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs b/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs new file mode 100644 index 0000000..246360a --- /dev/null +++ b/Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs @@ -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(); + } + } +} diff --git a/Aurora/Design/Views/MainView/MainView.css b/Aurora/Design/Views/MainView/MainView.css index e1a2e99..76c0ca5 100644 --- a/Aurora/Design/Views/MainView/MainView.css +++ b/Aurora/Design/Views/MainView/MainView.css @@ -1,8 +1,4 @@ -^ContentPage { - background-color: #232323; -} - -#Header { +#Header { background-color: transparent; margin-top: 10; } diff --git a/Aurora/Design/Views/MainView/MainView.xaml b/Aurora/Design/Views/MainView/MainView.xaml index ef68530..bb029d5 100644 --- a/Aurora/Design/Views/MainView/MainView.xaml +++ b/Aurora/Design/Views/MainView/MainView.xaml @@ -6,7 +6,8 @@ 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"> + x:Class="Aurora.Design.Views.Main.MainView" + StyleClass="primaryColor"> diff --git a/Aurora/Design/Views/Party/PartyView.xaml b/Aurora/Design/Views/Party/PartyView.xaml index 3b049fc..1422ee1 100644 --- a/Aurora/Design/Views/Party/PartyView.xaml +++ b/Aurora/Design/Views/Party/PartyView.xaml @@ -2,6 +2,7 @@ - - - - - - - - - + + + + + + + + + + + + \ No newline at end of file