Browse Source

Added ability to set AvaloniaModule.IsVisible at creation
Added StringWithDefaultConverter
Tweaked SelectedDtaeButton and TabControl/TabItem layouts

frankvandenbos 2 months ago
parent
commit
5ec920661b

+ 1 - 1
InABox.Avalonia/Components/Modules/ModuleGrid/AvaloniaModuleGrid.axaml

@@ -98,7 +98,7 @@
 
 
     <ItemsControl
     <ItemsControl
         DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType = moduleGrid:AvaloniaModuleGrid}}"
         DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType = moduleGrid:AvaloniaModuleGrid}}"
-        ItemsSource="{Binding Modules.Items}"
+        ItemsSource="{Binding Modules.VisibleItems}"
         ItemTemplate="{StaticResource ToolGrid}"
         ItemTemplate="{StaticResource ToolGrid}"
         ItemsPanel="{StaticResource ToolGridTemplate}"
         ItemsPanel="{StaticResource ToolGridTemplate}"
         Margin="{Binding Converter={StaticResource MarginInverter}, ConverterParameter={StaticResource PrsControlSpacing}}" />
         Margin="{Binding Converter={StaticResource MarginInverter}, ConverterParameter={StaticResource PrsControlSpacing}}" />

+ 10 - 1
InABox.Avalonia/Components/Modules/ModuleList/AvaloniaModule.cs

@@ -1,4 +1,5 @@
-using Avalonia.Svg.Skia;
+using System.ComponentModel;
+using Avalonia.Svg.Skia;
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
 using CommunityToolkit.Mvvm.Input;
 
 
@@ -6,6 +7,8 @@ namespace InABox.Avalonia.Components;
 
 
 public partial class AvaloniaModule : ObservableObject
 public partial class AvaloniaModule : ObservableObject
 {
 {
+    public event PropertyChangedEventHandler? PropertyChanged;
+    
     [ObservableProperty] private string? _alert;
     [ObservableProperty] private string? _alert;
 
 
     [ObservableProperty] private string? _description;
     [ObservableProperty] private string? _description;
@@ -19,4 +22,10 @@ public partial class AvaloniaModule : ObservableObject
     [ObservableProperty] private RelayCommand? _tapCommand;
     [ObservableProperty] private RelayCommand? _tapCommand;
 
 
     [ObservableProperty] private string? _title;
     [ObservableProperty] private string? _title;
+
+    protected override void OnPropertyChanged(PropertyChangedEventArgs e)
+    {
+        PropertyChanged?.Invoke(this,e);
+        base.OnPropertyChanged(e);
+    }
 }
 }

+ 30 - 6
InABox.Avalonia/Components/Modules/ModuleList/AvaloniaModuleCollection.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
+using System.ComponentModel;
 using System.Linq;
 using System.Linq;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Avalonia.Svg.Skia;
 using Avalonia.Svg.Skia;
@@ -15,13 +16,32 @@ public partial class AvaloniaModuleCollection : ObservableObject
 
 
     public AvaloniaModule? this[string name] => Items.FirstOrDefault(x => Equals(x.Title, name));
     public AvaloniaModule? this[string name] => Items.FirstOrDefault(x => Equals(x.Title, name));
 
 
+    [ObservableProperty] private AvaloniaModule[] _visibleItems = [];
+
+    public AvaloniaModuleCollection()
+    {
+        Items.CollectionChanged += (sender, args) => UpdateVisibleItems();
+    }
+    
     public void Add()
     public void Add()
     {
     {
         var module = new AvaloniaModule();
         var module = new AvaloniaModule();
+        module.PropertyChanged += DoPropertyChanged;
         Items.Add(module);
         Items.Add(module);
     }
     }
 
 
-    public AvaloniaModule Add(string title, string description, SvgImage? image, Action action
+    private void DoPropertyChanged(object? sender, PropertyChangedEventArgs e)
+    {
+        if (e.PropertyName == nameof(AvaloniaModule.IsVisible))
+            UpdateVisibleItems();
+    }
+
+    private void UpdateVisibleItems()
+    {
+        VisibleItems = Items.Where(x=>x.IsVisible == true).ToArray();
+    }
+
+    public AvaloniaModule Add(string title, string description, SvgImage? image, Action action, bool? isVisible = null
         /* Func<PrsModule, Task>? configure = null */)
         /* Func<PrsModule, Task>? configure = null */)
     {
     {
         var module = new AvaloniaModule
         var module = new AvaloniaModule
@@ -29,15 +49,17 @@ public partial class AvaloniaModuleCollection : ObservableObject
             Title = title,
             Title = title,
             Description = description,
             Description = description,
             Image = image,
             Image = image,
-            TapCommand = new RelayCommand(action)
+            TapCommand = new RelayCommand(action),
+            IsVisible = isVisible ?? true
         };
         };
+        module.PropertyChanged += DoPropertyChanged;
         Items.Add(module);
         Items.Add(module);
         // _ = configure?.Invoke(module);
         // _ = configure?.Invoke(module);
         return module;
         return module;
     }
     }
 
 
     public AvaloniaModule Add<TViewModel>(string title, string description, SvgImage? image,
     public AvaloniaModule Add<TViewModel>(string title, string description, SvgImage? image,
-        /* Func<PrsModule, Task>? configure = null */ Action<TViewModel>? configure = null)
+        /* Func<PrsModule, Task>? configure = null */ Action<TViewModel>? configure = null, bool? isVisible = null)
         where TViewModel : IViewModelBase
         where TViewModel : IViewModelBase
     {
     {
         var module = new AvaloniaModule
         var module = new AvaloniaModule
@@ -45,20 +67,22 @@ public partial class AvaloniaModuleCollection : ObservableObject
             Title = title,
             Title = title,
             Description = description,
             Description = description,
             Image = image,
             Image = image,
-            TapCommand = new RelayCommand(() => Navigation.Navigate<TViewModel>(configure))
+            TapCommand = new RelayCommand(() => Navigation.Navigate<TViewModel>(configure)),
+            IsVisible = isVisible ?? true
         };
         };
+        module.PropertyChanged += DoPropertyChanged;
         Items.Add(module);
         Items.Add(module);
         // _ = configure?.Invoke(module);
         // _ = configure?.Invoke(module);
         return module;
         return module;
     }
     }
 
 
     public AvaloniaModule? Add<TToken, TViewModel>(string title, string description, SvgImage? image,
     public AvaloniaModule? Add<TToken, TViewModel>(string title, string description, SvgImage? image,
-        /* Func<PrsModule, Task>? configure = null */ Action<TViewModel>? configure = null)
+        /* Func<PrsModule, Task>? configure = null */ Action<TViewModel>? configure = null, bool? isVisible = null)
         where TToken : ISecurityDescriptor, new()
         where TToken : ISecurityDescriptor, new()
         where TViewModel : IViewModelBase
         where TViewModel : IViewModelBase
     {
     {
         if (Security.IsAllowed<TToken>())
         if (Security.IsAllowed<TToken>())
-            return Add<TViewModel>(title, description, image, configure);
+            return Add<TViewModel>(title, description, image, configure, isVisible);
         return null;
         return null;
     }
     }
 }
 }

+ 1 - 1
InABox.Avalonia/Components/Modules/ModuleList/AvaloniaModuleList.axaml

@@ -106,7 +106,7 @@
 
 
     <ItemsControl
     <ItemsControl
         DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType = components:AvaloniaModuleList}}"
         DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType = components:AvaloniaModuleList}}"
-        ItemsSource="{Binding Modules.Items}"
+        ItemsSource="{Binding Modules.VisibleItems}"
         ItemTemplate="{StaticResource ModuleList}"
         ItemTemplate="{StaticResource ModuleList}"
         Margin="{Binding Converter={StaticResource MarginInverter}, ConverterParameter={StaticResource PrsControlSpacing}}" />
         Margin="{Binding Converter={StaticResource MarginInverter}, ConverterParameter={StaticResource PrsControlSpacing}}" />
 
 

+ 17 - 0
InABox.Avalonia/Converters/StringWithDefaultConverter.cs

@@ -0,0 +1,17 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace InABox.Avalonia.Converters;
+
+public partial class StringWithDefaultConverter : AbstractConverter<string?,string?>
+{
+    [ObservableProperty] 
+    private string? _default = "";
+
+    protected override string? Convert(string? value, object? parameter = null)
+    {
+        return String.IsNullOrWhiteSpace(value)
+            ? _default
+            : value;
+    }
+    
+}

+ 10 - 1
InABox.Avalonia/Theme/Classes/DateSelectorButton.axaml

@@ -2,7 +2,16 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 		xmlns:components="using:InABox.Avalonia.Components">
 		xmlns:components="using:InABox.Avalonia.Components">
 	<Style Selector="components|DateSelectorButton">
 	<Style Selector="components|DateSelectorButton">
+		<Setter Property="Margin" Value="{DynamicResource PrsControlSpacing}" />
+		<Setter Property="BorderBrush" Value="{DynamicResource PrsButtonBorder}" />
+		<Setter Property="BorderThickness">
+			<Setter.Value>
+				<DynamicResource ResourceKey="PrsBorderThickness" />
+			</Setter.Value>
+		</Setter>
 		<Setter Property="Background" Value="{DynamicResource PrsButtonBackground}"/>
 		<Setter Property="Background" Value="{DynamicResource PrsButtonBackground}"/>
-        <Setter Property="BorderBrush" Value="{DynamicResource PrsButtonBorder}" />
+		<Setter Property="Foreground" Value="{DynamicResource PrsButtonForeground}" />
+		<Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}" />
+		<Setter Property="Padding" Value="10" />
 	</Style>
 	</Style>
 </Styles>
 </Styles>

+ 19 - 8
InABox.Avalonia/Theme/Classes/TabItem.axaml

@@ -1,6 +1,11 @@
 <Styles xmlns="https://github.com/avaloniaui"
 <Styles xmlns="https://github.com/avaloniaui"
-        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:classes="clr-namespace:InABox.Avalonia.Theme.Classes">
+	
 	<Style Selector="TabControl">
 	<Style Selector="TabControl">
+		<Style.Resources>
+			<classes:TabItemHeaderMarginConverter x:Key="TabItemHeaderMarginConverter" Padding="2"/>
+		</Style.Resources>
 		<Setter Property="Padding" Value="0"/>
 		<Setter Property="Padding" Value="0"/>
 		<Setter Property="ItemsPanel">
 		<Setter Property="ItemsPanel">
 			<Setter.Value>
 			<Setter.Value>
@@ -19,7 +24,8 @@
 						VerticalAlignment="{TemplateBinding VerticalAlignment}">
 						VerticalAlignment="{TemplateBinding VerticalAlignment}">
 					<DockPanel>
 					<DockPanel>
 						<Border DockPanel.Dock="{TemplateBinding TabStripPlacement}"
 						<Border DockPanel.Dock="{TemplateBinding TabStripPlacement}"
-								Name="PART_HeaderBorder">
+								Name="PART_HeaderBorder"
+								Margin="{TemplateBinding TabStripPlacement, Converter={StaticResource TabItemHeaderMarginConverter}}">
 							<ItemsPresenter Name="PART_ItemsPresenter"
 							<ItemsPresenter Name="PART_ItemsPresenter"
 											ItemsPanel="{TemplateBinding ItemsPanel}"/>
 											ItemsPanel="{TemplateBinding ItemsPanel}"/>
 						</Border>
 						</Border>
@@ -34,22 +40,25 @@
 			</ControlTemplate>
 			</ControlTemplate>
         </Setter>
         </Setter>
 	</Style>
 	</Style>
+	
 	<Style Selector="TabControl Border#PART_HeaderBorder">
 	<Style Selector="TabControl Border#PART_HeaderBorder">
 		<Setter Property="Background" Value="{DynamicResource PrsMenuBackground}"/>
 		<Setter Property="Background" Value="{DynamicResource PrsMenuBackground}"/>
 		<Setter Property="BorderBrush" Value="{DynamicResource PrsMenuBackground}"/>
 		<Setter Property="BorderBrush" Value="{DynamicResource PrsMenuBackground}"/>
-		<Setter Property="BorderThickness" Value="2"/>
+		<Setter Property="BorderThickness" Value="1"/>
 		<Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}"/>
 		<Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}"/>
 	</Style>
 	</Style>
+	
 	<Style Selector="TabItem">
 	<Style Selector="TabItem">
-		<Setter Property="Height" Value="30"/>
-		<Setter Property="MinHeight" Value="0"/>
+		<!-- <Setter Property="Height" Value="0"/> -->
+		<Setter Property="MinHeight" Value="30"/>
 		<Setter Property="FontSize" Value="{DynamicResource PrsFontSizeSmall}"/>
 		<Setter Property="FontSize" Value="{DynamicResource PrsFontSizeSmall}"/>
-		
+		<Setter Property="FontWeight" Value="{DynamicResource PrsFontWeightBold}" />
 		<Setter Property="HorizontalContentAlignment" Value="Center"/>
 		<Setter Property="HorizontalContentAlignment" Value="Center"/>
-		
 		<Setter Property="Background" Value="{DynamicResource PrsMenuBackground}"/>
 		<Setter Property="Background" Value="{DynamicResource PrsMenuBackground}"/>
 		<Setter Property="Foreground" Value="White"/>
 		<Setter Property="Foreground" Value="White"/>
-		<Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}"/>
+		<Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}" />
+		<Setter Property="Padding" Value="0,10,0,10"/>
+		
 	</Style>
 	</Style>
 	
 	
 	<Style Selector="TabItem:pointerover /template/ Border#PART_LayoutRoot">
 	<Style Selector="TabItem:pointerover /template/ Border#PART_LayoutRoot">
@@ -60,6 +69,7 @@
 	<Style Selector="TabItem:selected">
 	<Style Selector="TabItem:selected">
 		<Setter Property="Background" Value="{DynamicResource PrsTileBackground}"/>
 		<Setter Property="Background" Value="{DynamicResource PrsTileBackground}"/>
 	</Style>
 	</Style>
+	
 	<Style Selector="TabItem:selected:pointerover /template/ Border#PART_LayoutRoot">
 	<Style Selector="TabItem:selected:pointerover /template/ Border#PART_LayoutRoot">
 		<Setter Property="Background" Value="{DynamicResource PrsTileBackground}"/>
 		<Setter Property="Background" Value="{DynamicResource PrsTileBackground}"/>
 		<Setter Property="TextElement.Foreground" Value="Black"/>
 		<Setter Property="TextElement.Foreground" Value="Black"/>
@@ -68,4 +78,5 @@
 	<Style Selector="TabItem:selected /template/ Border#PART_SelectedPipe">
 	<Style Selector="TabItem:selected /template/ Border#PART_SelectedPipe">
 		<Setter Property="IsVisible" Value="False"/>
 		<Setter Property="IsVisible" Value="False"/>
 	</Style>
 	</Style>
+	
 </Styles>
 </Styles>

+ 21 - 0
InABox.Avalonia/Theme/Classes/TabItemHeaderMarginConverter.cs

@@ -0,0 +1,21 @@
+using Avalonia;
+using Avalonia.Controls;
+using InABox.Avalonia.Converters;
+
+namespace InABox.Avalonia.Theme.Classes;
+
+public class TabItemHeaderMarginConverter : AbstractConverter<Dock, Thickness>
+{
+    public double Padding { get; set; } = 2.0;
+
+    protected override Thickness Convert(Dock value, object? parameter = null)
+    {
+        return value == Dock.Bottom 
+            ? new Thickness(0, Padding, 0, 0)
+            : value == Dock.Top 
+                ? new Thickness(0, 0, 0, Padding)
+                : value == Dock.Left 
+                    ? new Thickness(0, 0, Padding, 0)
+                    : new Thickness(Padding, 0, 0, 0);
+    }
+}