From 7560e122f8f324d21cd491a98ca18582da0e1717 Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sat, 21 Dec 2019 22:21:07 -0500 Subject: [PATCH] Added tab view (not working) --- Aurora.gtk/Aurora.gtk.csproj | 6 + Aurora.gtk/Program.cs | 1 - Aurora.gtk/packages.config | 2 + Aurora/Aurora.csproj | 4 +- Aurora/Design/Components/TabView/TabItem.cs | 111 +++ Aurora/Design/Components/TabView/TabView.cs | 630 ++++++++++++++++++ .../Converters/DoubleToLayoutOptions.cs | 24 + .../Design/Converters/NullToBullConverter.cs | 19 + ...dTabHeaderToTabBackgroundColorConverter.cs | 31 + Aurora/Design/Views/Party/PartyView.xaml | 48 +- 10 files changed, 849 insertions(+), 27 deletions(-) create mode 100644 Aurora/Design/Components/TabView/TabItem.cs create mode 100644 Aurora/Design/Components/TabView/TabView.cs create mode 100644 Aurora/Design/Converters/DoubleToLayoutOptions.cs create mode 100644 Aurora/Design/Converters/NullToBullConverter.cs create mode 100644 Aurora/Design/Converters/SelectedTabHeaderToTabBackgroundColorConverter.cs 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..db78a8b 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 { 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/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/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..11fc10c --- /dev/null +++ b/Aurora/Design/Components/TabView/TabView.cs @@ -0,0 +1,630 @@ +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, PositionChangingEventArgs e); + public delegate void PositionChangedEventHandler(object sender, PositionChangedEventArgs e); + + public class PositionChangingEventArgs : EventArgs + { + public bool Canceled { get; set; } + public int NewPosition { get; set; } + public int OldPosition { get; set; } + } + + public class PositionChangedEventArgs : 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 CarouselViewControl _carouselView; + private ScrollView _tabHeadersContainerSv; + + public event PositionChangingEventHandler PositionChanging; + public event PositionChangedEventHandler PositionChanged; + + protected virtual void OnPositionChanging(ref PositionChangingEventArgs e) + { + PositionChangingEventHandler handler = PositionChanging; + handler?.Invoke(this, e); + } + + protected virtual void OnPositionChanged(PositionChangedEventArgs 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 bool _supressCarouselViewPositionChangedEvent; + private void _carouselView_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(_carouselView.Position) && !_supressCarouselViewPositionChangedEvent) + { + var positionChangingArgs = new PositionChangingEventArgs() + { + Canceled = false, + NewPosition = _carouselView.Position, + OldPosition = SelectedTabIndex + }; + + OnPositionChanging(ref positionChangingArgs); + + if (positionChangingArgs != null && positionChangingArgs.Canceled) + { + _supressCarouselViewPositionChangedEvent = true; + _carouselView.PositionSelected -= _carouselView_PositionSelected; + _carouselView.PropertyChanged -= _carouselView_PropertyChanged; + _carouselView.Position = SelectedTabIndex; + _carouselView.PositionSelected += _carouselView_PositionSelected; + _carouselView.PropertyChanged += _carouselView_PropertyChanged; + _supressCarouselViewPositionChangedEvent = false; + } + + SetPosition(positionChangingArgs.NewPosition); + } + } + + 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 + }; + + _carouselView = new CarouselViewControl + { + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.FillAndExpand, + HeightRequest = ContentHeight, + ShowArrows = false, + ShowIndicators = false, + BindingContext = this + }; + + _carouselView.PropertyChanged += _carouselView_PropertyChanged; + _carouselView.PositionSelected += _carouselView_PositionSelected; + + _mainContainerSL = new StackLayout + { + HorizontalOptions = LayoutOptions.FillAndExpand, + VerticalOptions = LayoutOptions.FillAndExpand, + Children = { _tabHeadersContainerSv, _carouselView }, + Spacing = 0 + }; + + Content = _mainContainerSL; + ItemSource.CollectionChanged += ItemSource_CollectionChanged; + SetPosition(SelectedTabIndex, true); + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + if (BindingContext != null) + { + foreach (var tab in ItemSource) + { + if (tab is TabItem view) + { + view.Content.BindingContext = BindingContext; + } + } + } + } + + private void _carouselView_PositionSelected(object sender, PositionSelectedEventArgs e) + { + if (_carouselView.Position != e.NewValue || SelectedTabIndex != e.NewValue) + { + SetPosition(e.NewValue); + } + } + + 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 + }; + //selectionBarBoxView.SetBinding(IsVisibleProperty, nameof(TabItem.IsCurrent)); + var underlineColorBinding = new Binding(nameof(TabItem.IsCurrent), BindingMode.OneWay, new SelectedTabHeaderToTabBackgroundColorConverter(), this); + //selectionBarBoxView.SetBinding(BoxView.ColorProperty, nameof(TabItem.HeaderSelectionUnderlineColor), BindingMode.OneWay, new SelectedTabHeaderToTabBackgroundColorConverter(), ); + 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)) + { + SetPosition(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) => + { + _supressCarouselViewPositionChangedEvent = true; + var capturedIndex = _headerContainerGrid.Children.IndexOf((View)s); + SetPosition(capturedIndex); + _supressCarouselViewPositionChangedEvent = false; + }; + headerItemSL.GestureRecognizers.Add(tapRecognizer); + _headerContainerGrid.Children.Add(headerItemSL, _headerContainerGrid.ColumnDefinitions.Count - 1, 0); + _carouselView.ItemsSource = ItemSource.Select(t => t.Content); + } + + #region IsSwipingEnabled + public bool IsSwipingEnabled + { + get { return (bool)GetValue(IsSwipingEnabledProperty); } + set { SetValue(IsSwipingEnabledProperty, value); } + } + private static void IsSwipingEnabledChanged(BindableObject bindable, object oldValue, object newValue) + { + if (bindable is TabViewControl tabViewControl) + { + tabViewControl._carouselView.IsSwipeEnabled = (bool)newValue; + } + } + public static readonly BindableProperty IsSwipingEnabledProperty = BindableProperty.Create(nameof(IsSwipingEnabled), typeof(bool), typeof(TabViewControl), true, BindingMode.Default, null, IsSwipingEnabledChanged); + #endregion + + #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) + { + 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._carouselView.Position != (int)newValue) + { + tabViewControl.SetPosition((int)newValue); + } + } + public int SelectedTabIndex + { + get => (int)GetValue(SelectedTabIndexProperty); + set { SetValue(SelectedTabIndexProperty, value); } + } + #endregion + + public void SetPosition(int position, bool initialRun = false) + { + if (SelectedTabIndex == position && !initialRun) + { + return; + } + int oldPosition = SelectedTabIndex; + + var positionChangingArgs = new PositionChangingEventArgs() + { + Canceled = false, + NewPosition = position, + OldPosition = oldPosition + }; + OnPositionChanging(ref positionChangingArgs); + + if (positionChangingArgs != null && positionChangingArgs.Canceled) + { + return; + } + + if ((position >= 0 && position < ItemSource.Count) || initialRun) + { + if (_carouselView.Position != position || initialRun) + { + _carouselView.PositionSelected -= _carouselView_PositionSelected; + _carouselView.Position = position; + _carouselView.PositionSelected += _carouselView_PositionSelected; + } + if (oldPosition != position) + { + if (oldPosition < ItemSource.Count) + { + ItemSource[oldPosition].IsCurrent = false; + } + ItemSource[position].IsCurrent = true; + SelectedTabIndex = position; + + Device.BeginInvokeOnMainThread(async () => await _tabHeadersContainerSv.ScrollToAsync(_headerContainerGrid.Children[position], ScrollToPosition.MakeVisible, false)); + } + } + + var positionChangedArgs = new PositionChangedEventArgs() + { + NewPosition = SelectedTabIndex, + OldPosition = oldPosition + }; + OnPositionChanged(positionChangedArgs); + } + + public void SelectNext() + { + SetPosition(SelectedTabIndex + 1); + } + + public void SelectPrevious() + { + SetPosition(SelectedTabIndex - 1); + } + + public void SelectFirst() + { + SetPosition(0); + } + + public void SelectLast() + { + SetPosition(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()); + } + _carouselView.ItemsSource = ItemSource.Select(t => t.Content); + 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/Party/PartyView.xaml b/Aurora/Design/Views/Party/PartyView.xaml index 3b049fc..ad79ae7 100644 --- a/Aurora/Design/Views/Party/PartyView.xaml +++ b/Aurora/Design/Views/Party/PartyView.xaml @@ -2,7 +2,7 @@ @@ -11,29 +11,27 @@ Source="./PartyView.css"/> - - - - - - - - - + + + + + + + + + + + \ No newline at end of file