From 7560e122f8f324d21cd491a98ca18582da0e1717 Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sat, 21 Dec 2019 22:21:07 -0500 Subject: [PATCH 1/4] 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 From 945b7e8e1120660d1878f428f00ad6b22837f4de Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sun, 22 Dec 2019 17:10:06 -0500 Subject: [PATCH 2/4] First pass at tab view --- Aurora/Design/Components/TabView/TabView.cs | 216 +++++++++++--------- 1 file changed, 115 insertions(+), 101 deletions(-) diff --git a/Aurora/Design/Components/TabView/TabView.cs b/Aurora/Design/Components/TabView/TabView.cs index 11fc10c..2c54d59 100644 --- a/Aurora/Design/Components/TabView/TabView.cs +++ b/Aurora/Design/Components/TabView/TabView.cs @@ -1,4 +1,4 @@ -using CarouselView.FormsPlugin.Abstractions; +// using CarouselView.FormsPlugin.Abstractions; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -10,7 +10,7 @@ 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 delegate void PositionChangedEventHandler(object sender, TabChangedEventArgs e); public class PositionChangingEventArgs : EventArgs { @@ -19,7 +19,7 @@ namespace Aurora.Design.Components.TabView public int OldPosition { get; set; } } - public class PositionChangedEventArgs : EventArgs + public class TabChangedEventArgs : EventArgs { public int NewPosition { get; set; } public int OldPosition { get; set; } @@ -36,19 +36,21 @@ namespace Aurora.Design.Components.TabView { private StackLayout _mainContainerSL; private Grid _headerContainerGrid; - private CarouselViewControl _carouselView; + // private CarouselViewControl _carouselView; private ScrollView _tabHeadersContainerSv; + private ContentPresenter _tabPresenter; + public event PositionChangingEventHandler PositionChanging; public event PositionChangedEventHandler PositionChanged; - protected virtual void OnPositionChanging(ref PositionChangingEventArgs e) + protected virtual void OnTabChanging(ref PositionChangingEventArgs e) { PositionChangingEventHandler handler = PositionChanging; handler?.Invoke(this, e); } - protected virtual void OnPositionChanged(PositionChangedEventArgs e) + protected virtual void OnTabChanged(TabChangedEventArgs e) { PositionChangedEventHandler handler = PositionChanged; handler?.Invoke(this, e); @@ -108,33 +110,39 @@ namespace Aurora.Design.Components.TabView } 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); + /// + /// Allows for intercepting carousel property changing + /// + /// + /// + // 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 + // }; - 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; - } + // OnPositionChanging(ref positionChangingArgs); - SetPosition(positionChangingArgs.NewPosition); - } - } + // 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() { @@ -158,30 +166,32 @@ namespace Aurora.Design.Components.TabView HorizontalOptions = LayoutOptions.FillAndExpand }; - _carouselView = new CarouselViewControl - { - HorizontalOptions = LayoutOptions.FillAndExpand, - VerticalOptions = LayoutOptions.FillAndExpand, - HeightRequest = ContentHeight, - ShowArrows = false, - ShowIndicators = false, - BindingContext = this - }; + _tabPresenter = new ContentPresenter(); + // _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; + // _carouselView.PropertyChanged += _carouselView_PropertyChanged; + // _carouselView.PositionSelected += _carouselView_PositionSelected; _mainContainerSL = new StackLayout { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand, - Children = { _tabHeadersContainerSv, _carouselView }, + Children = { _tabHeadersContainerSv, _tabPresenter }, + // Children = { _tabHeadersContainerSv, _carouselView }, //Need to set new child in place of carousel Spacing = 0 }; Content = _mainContainerSL; ItemSource.CollectionChanged += ItemSource_CollectionChanged; - SetPosition(SelectedTabIndex, true); + SetCurrentTab(SelectedTabIndex, true); } protected override void OnBindingContextChanged() @@ -199,13 +209,13 @@ namespace Aurora.Design.Components.TabView } } - private void _carouselView_PositionSelected(object sender, PositionSelectedEventArgs e) - { - if (_carouselView.Position != e.NewValue || SelectedTabIndex != e.NewValue) - { - SetPosition(e.NewValue); - } - } + // private void _carouselView_PositionSelected(object sender, PositionSelectedEventArgs e) + // { + // if (_carouselView.Position != e.NewValue || SelectedTabIndex != e.NewValue) + // { + // SetPosition(e.NewValue); + // } + // } private void AddTabToView(TabItem tab) { @@ -266,7 +276,7 @@ namespace Aurora.Design.Components.TabView { if (e.PropertyName == nameof(TabItem.IsCurrent)) { - SetPosition(ItemSource.IndexOf((TabItem)((BoxView)sender).BindingContext)); + SetCurrentTab(ItemSource.IndexOf((TabItem)((BoxView)sender).BindingContext)); } if (e.PropertyName == nameof(WidthRequest)) { @@ -282,33 +292,21 @@ namespace Aurora.Design.Components.TabView Spacing = 0 }; var tapRecognizer = new TapGestureRecognizer(); + + //Appears to set the current view tapRecognizer.Tapped += (object s, EventArgs e) => { - _supressCarouselViewPositionChangedEvent = true; + // _supressCarouselViewPositionChangedEvent = true; var capturedIndex = _headerContainerGrid.Children.IndexOf((View)s); - SetPosition(capturedIndex); - _supressCarouselViewPositionChangedEvent = false; + SetCurrentTab(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); } + //Sets caourselview itemssource to current tab + // _carouselView.ItemsSource = ItemSource.Select(t => t.Content); } - 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 @@ -354,10 +352,11 @@ namespace Aurora.Design.Components.TabView } private static void ContentHeightChanged(BindableObject bindable, object oldValue, object newValue) { - if (bindable is TabViewControl tabViewControl && tabViewControl._carouselView != null) - { - tabViewControl._carouselView.HeightRequest = (double)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 @@ -510,10 +509,9 @@ namespace Aurora.Design.Components.TabView 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) + if (bindable is TabViewControl tabViewControl && tabViewControl.ItemSource != null) { - tabViewControl.SetPosition((int)newValue); + tabViewControl.SetCurrentTab((int)newValue); } } public int SelectedTabIndex @@ -523,7 +521,7 @@ namespace Aurora.Design.Components.TabView } #endregion - public void SetPosition(int position, bool initialRun = false) + public void SetCurrentTab(int position, bool initialRun = false) { if (SelectedTabIndex == position && !initialRun) { @@ -537,60 +535,76 @@ namespace Aurora.Design.Components.TabView NewPosition = position, OldPosition = oldPosition }; - OnPositionChanging(ref positionChangingArgs); + OnTabChanging(ref positionChangingArgs); if (positionChangingArgs != null && positionChangingArgs.Canceled) { return; } - if ((position >= 0 && position < ItemSource.Count) || initialRun) + if (((position >= 0 && position < ItemSource.Count) || initialRun) && + oldPosition != position) { - if (_carouselView.Position != position || initialRun) + if (oldPosition < ItemSource.Count) { - _carouselView.PositionSelected -= _carouselView_PositionSelected; - _carouselView.Position = position; - _carouselView.PositionSelected += _carouselView_PositionSelected; + ItemSource[oldPosition].IsCurrent = false; } - if (oldPosition != position) - { - if (oldPosition < ItemSource.Count) - { - ItemSource[oldPosition].IsCurrent = false; - } - ItemSource[position].IsCurrent = true; - SelectedTabIndex = position; + _tabPresenter.Content = ItemSource[position].Content; + ItemSource[position].IsCurrent = true; + SelectedTabIndex = position; + Device.BeginInvokeOnMainThread(async () => await _tabHeadersContainerSv.ScrollToAsync(_headerContainerGrid.Children[position], ScrollToPosition.MakeVisible, false)); - Device.BeginInvokeOnMainThread(async () => await _tabHeadersContainerSv.ScrollToAsync(_headerContainerGrid.Children[position], ScrollToPosition.MakeVisible, false)); - } } - var positionChangedArgs = new PositionChangedEventArgs() + //Need to change to not use carouselView + // 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 tabChangedArgs = new TabChangedEventArgs() { NewPosition = SelectedTabIndex, OldPosition = oldPosition }; - OnPositionChanged(positionChangedArgs); + OnTabChanged(tabChangedArgs); } public void SelectNext() { - SetPosition(SelectedTabIndex + 1); + SetCurrentTab(SelectedTabIndex + 1); } public void SelectPrevious() { - SetPosition(SelectedTabIndex - 1); + SetCurrentTab(SelectedTabIndex - 1); } public void SelectFirst() { - SetPosition(0); + SetCurrentTab(0); } public void SelectLast() { - SetPosition(ItemSource.Count - 1); + SetCurrentTab(ItemSource.Count - 1); } public void AddTab(TabItem tab, int position = -1, bool selectNewPosition = false) @@ -623,7 +637,7 @@ namespace Aurora.Design.Components.TabView _headerContainerGrid.Children.RemoveAt(_headerContainerGrid.Children.Count - 1); _headerContainerGrid.ColumnDefinitions.Remove(_headerContainerGrid.ColumnDefinitions.Last()); } - _carouselView.ItemsSource = ItemSource.Select(t => t.Content); + // _carouselView.ItemsSource = ItemSource.Select(t => t.Content); SelectedTabIndex = position >= 0 && position < ItemSource.Count ? position : ItemSource.Count - 1; } } From cc0d11320493aeedde48f8a86c5f640cd9fea05e Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sun, 22 Dec 2019 19:30:58 -0500 Subject: [PATCH 3/4] Working tab view --- Aurora/Design/Components/TabView/TabView.cs | 120 +++----------------- Aurora/Design/Views/Party/PartyView.xaml | 10 +- 2 files changed, 20 insertions(+), 110 deletions(-) diff --git a/Aurora/Design/Components/TabView/TabView.cs b/Aurora/Design/Components/TabView/TabView.cs index 2c54d59..659e42f 100644 --- a/Aurora/Design/Components/TabView/TabView.cs +++ b/Aurora/Design/Components/TabView/TabView.cs @@ -9,10 +9,10 @@ using Aurora.Design.Converters; namespace Aurora.Design.Components.TabView { - public delegate void PositionChangingEventHandler(object sender, PositionChangingEventArgs e); + public delegate void PositionChangingEventHandler(object sender, TabChangingEventArgs e); public delegate void PositionChangedEventHandler(object sender, TabChangedEventArgs e); - public class PositionChangingEventArgs : EventArgs + public class TabChangingEventArgs : EventArgs { public bool Canceled { get; set; } public int NewPosition { get; set; } @@ -36,15 +36,12 @@ namespace Aurora.Design.Components.TabView { private StackLayout _mainContainerSL; private Grid _headerContainerGrid; - // private CarouselViewControl _carouselView; private ScrollView _tabHeadersContainerSv; - private ContentPresenter _tabPresenter; - public event PositionChangingEventHandler PositionChanging; public event PositionChangedEventHandler PositionChanged; - protected virtual void OnTabChanging(ref PositionChangingEventArgs e) + protected virtual void OnTabChanging(ref TabChangingEventArgs e) { PositionChangingEventHandler handler = PositionChanging; handler?.Invoke(this, e); @@ -109,41 +106,6 @@ namespace Aurora.Design.Components.TabView tab.HeaderTabTextFontAttributes = HeaderTabTextFontAttributes; } - private bool _supressCarouselViewPositionChangedEvent; - - /// - /// Allows for intercepting carousel property changing - /// - /// - /// - // 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(); @@ -166,32 +128,16 @@ namespace Aurora.Design.Components.TabView HorizontalOptions = LayoutOptions.FillAndExpand }; - _tabPresenter = new ContentPresenter(); - // _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, _tabPresenter }, - // Children = { _tabHeadersContainerSv, _carouselView }, //Need to set new child in place of carousel + Children = { _tabHeadersContainerSv }, Spacing = 0 }; Content = _mainContainerSL; ItemSource.CollectionChanged += ItemSource_CollectionChanged; - SetCurrentTab(SelectedTabIndex, true); } protected override void OnBindingContextChanged() @@ -206,17 +152,11 @@ namespace Aurora.Design.Components.TabView view.Content.BindingContext = BindingContext; } } + + SetCurrentTab(0, true); } } - // 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; @@ -261,9 +201,7 @@ namespace Aurora.Design.Components.TabView 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)); @@ -293,19 +231,14 @@ namespace Aurora.Design.Components.TabView }; var tapRecognizer = new TapGestureRecognizer(); - //Appears to set the current view tapRecognizer.Tapped += (object s, EventArgs e) => { - // _supressCarouselViewPositionChangedEvent = true; var capturedIndex = _headerContainerGrid.Children.IndexOf((View)s); SetCurrentTab(capturedIndex); - // _supressCarouselViewPositionChangedEvent = false; }; + headerItemSL.GestureRecognizers.Add(tapRecognizer); _headerContainerGrid.Children.Add(headerItemSL, _headerContainerGrid.ColumnDefinitions.Count - 1, 0); - - //Sets caourselview itemssource to current tab - // _carouselView.ItemsSource = ItemSource.Select(t => t.Content); } #region HeaderBackgroundColor @@ -529,56 +462,34 @@ namespace Aurora.Design.Components.TabView } int oldPosition = SelectedTabIndex; - var positionChangingArgs = new PositionChangingEventArgs() + var tabChangingArgs = new TabChangingEventArgs() { Canceled = false, NewPosition = position, OldPosition = oldPosition }; - OnTabChanging(ref positionChangingArgs); + OnTabChanging(ref tabChangingArgs); - if (positionChangingArgs != null && positionChangingArgs.Canceled) + if (tabChangingArgs != null && tabChangingArgs.Canceled) { return; } - if (((position >= 0 && position < ItemSource.Count) || initialRun) && - oldPosition != position) + if (((position >= 0 && position < ItemSource.Count) || initialRun)) { - if (oldPosition < ItemSource.Count) + if (oldPosition < ItemSource.Count && _mainContainerSL.Children.Count == 2) { ItemSource[oldPosition].IsCurrent = false; + //Remove second child + _mainContainerSL.Children.RemoveAt(1); } - _tabPresenter.Content = ItemSource[position].Content; + _mainContainerSL.Children.Add(ItemSource[position].Content); ItemSource[position].IsCurrent = true; SelectedTabIndex = position; Device.BeginInvokeOnMainThread(async () => await _tabHeadersContainerSv.ScrollToAsync(_headerContainerGrid.Children[position], ScrollToPosition.MakeVisible, false)); } - //Need to change to not use carouselView - // 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 tabChangedArgs = new TabChangedEventArgs() { NewPosition = SelectedTabIndex, @@ -637,7 +548,6 @@ namespace Aurora.Design.Components.TabView _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; } } diff --git a/Aurora/Design/Views/Party/PartyView.xaml b/Aurora/Design/Views/Party/PartyView.xaml index ad79ae7..818fb62 100644 --- a/Aurora/Design/Views/Party/PartyView.xaml +++ b/Aurora/Design/Views/Party/PartyView.xaml @@ -18,6 +18,11 @@ VerticalOptions="FillAndExpand" x:Name="TabView"> + + - - From 1a55ce0be135794933f16ec194d433ecf07036bf Mon Sep 17 00:00:00 2001 From: watsonb8 Date: Sun, 22 Dec 2019 23:58:29 -0500 Subject: [PATCH 4/4] Progress on party page styling --- Aurora.gtk/Program.cs | 2 + Aurora/App.css | 7 +++ Aurora/App.xaml | 2 + .../Components/MemberList/MemberList.css | 12 ++++ .../Components/MemberList/MemberList.xaml | 39 +++++++----- .../Components/MemberList/MemberList.xaml.cs | 61 ++----------------- Aurora/Design/Views/MainView/MainView.css | 6 +- Aurora/Design/Views/MainView/MainView.xaml | 3 +- Aurora/Design/Views/Party/PartyView.xaml | 7 ++- 9 files changed, 60 insertions(+), 79 deletions(-) create mode 100644 Aurora/App.css create mode 100644 Aurora/Design/Components/MemberList/MemberList.css diff --git a/Aurora.gtk/Program.cs b/Aurora.gtk/Program.cs index db78a8b..b3ef8c5 100644 --- a/Aurora.gtk/Program.cs +++ b/Aurora.gtk/Program.cs @@ -11,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/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/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/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 818fb62..1422ee1 100644 --- a/Aurora/Design/Views/Party/PartyView.xaml +++ b/Aurora/Design/Views/Party/PartyView.xaml @@ -3,6 +3,7 @@ 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"> @@ -20,8 +21,10 @@ -