diff --git a/Avalonia.Labs.sln b/Avalonia.Labs.sln index 2d54646..0d7d0bf 100644 --- a/Avalonia.Labs.sln +++ b/Avalonia.Labs.sln @@ -44,7 +44,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Labs.Catalog.Deskt EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Labs.Qr", "src\Avalonia.Labs.Qr\Avalonia.Labs.Qr.csproj", "{D7196459-710E-4057-BA38-8265C7C94854}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Labs.Lottie", "src\Avalonia.Labs.Lottie\Avalonia.Labs.Lottie.csproj", "{633A51E9-65E7-4350-9AE6-E527FECD15F9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Labs.Lottie", "src\Avalonia.Labs.Lottie\Avalonia.Labs.Lottie.csproj", "{633A51E9-65E7-4350-9AE6-E527FECD15F9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Labs.Panels", "src\Avalonia.Labs.Panels\Avalonia.Labs.Panels.csproj", "{BEDDF9B6-5B8D-4524-975C-485F87DDE7A2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -94,6 +96,10 @@ Global {633A51E9-65E7-4350-9AE6-E527FECD15F9}.Debug|Any CPU.Build.0 = Debug|Any CPU {633A51E9-65E7-4350-9AE6-E527FECD15F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {633A51E9-65E7-4350-9AE6-E527FECD15F9}.Release|Any CPU.Build.0 = Release|Any CPU + {BEDDF9B6-5B8D-4524-975C-485F87DDE7A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BEDDF9B6-5B8D-4524-975C-485F87DDE7A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BEDDF9B6-5B8D-4524-975C-485F87DDE7A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BEDDF9B6-5B8D-4524-975C-485F87DDE7A2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/Avalonia.Labs.Catalog.Desktop/Program.cs b/samples/Avalonia.Labs.Catalog.Desktop/Program.cs index 7d45cd2..08048ba 100644 --- a/samples/Avalonia.Labs.Catalog.Desktop/Program.cs +++ b/samples/Avalonia.Labs.Catalog.Desktop/Program.cs @@ -2,6 +2,7 @@ using System.IO; using Avalonia; using Avalonia.Labs.Controls.Cache; +using Avalonia.ReactiveUI; namespace Avalonia.Labs.Catalog.Desktop; @@ -18,6 +19,7 @@ public static void Main(string[] args) => BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() + .UseReactiveUI() .AfterSetup(builder => { CacheOptions.SetDefault(new CacheOptions() diff --git a/samples/Avalonia.Labs.Catalog/Avalonia.Labs.Catalog.csproj b/samples/Avalonia.Labs.Catalog/Avalonia.Labs.Catalog.csproj index 72ec03c..a44dab8 100644 --- a/samples/Avalonia.Labs.Catalog/Avalonia.Labs.Catalog.csproj +++ b/samples/Avalonia.Labs.Catalog/Avalonia.Labs.Catalog.csproj @@ -21,6 +21,7 @@ + diff --git a/samples/Avalonia.Labs.Catalog/Converters/FlexDemoNumberToThicknessConverter.cs b/samples/Avalonia.Labs.Catalog/Converters/FlexDemoNumberToThicknessConverter.cs new file mode 100644 index 0000000..5718388 --- /dev/null +++ b/samples/Avalonia.Labs.Catalog/Converters/FlexDemoNumberToThicknessConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Globalization; + +using Avalonia.Data.Converters; + +namespace Avalonia.Labs.Catalog.Converters +{ + internal sealed class FlexDemoNumberToThicknessConverter : IValueConverter + { + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is int x && targetType.IsAssignableFrom(typeof(Thickness))) + { + var y = 16 + 2 * ((x * 5) % 9); + return new Thickness(2 * y, y); + } + + throw new NotSupportedException(); + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) => + throw new NotSupportedException(); + } +} diff --git a/samples/Avalonia.Labs.Catalog/ViewModels/FlexItemViewModel.cs b/samples/Avalonia.Labs.Catalog/ViewModels/FlexItemViewModel.cs new file mode 100644 index 0000000..b23708f --- /dev/null +++ b/samples/Avalonia.Labs.Catalog/ViewModels/FlexItemViewModel.cs @@ -0,0 +1,57 @@ +using System.Reactive.Linq; + +using Avalonia.Labs.Panels; + +using ReactiveUI; + +namespace Avalonia.Labs.Catalog.ViewModels +{ + public sealed class FlexItemViewModel : ReactiveObject + { + internal const AlignItems AlignSelfAuto = (AlignItems)(-1); + + private readonly ObservableAsPropertyHelper _alignSelf; + + private bool _isSelected; + private bool _isVisible = true; + + private AlignItems _alignSelfItem = AlignSelfAuto; + private int _order; + + public FlexItemViewModel(int value) + { + Value = value; + + _alignSelf = (from item in this.WhenAnyValue(vm => vm.AlignSelfItem) + select item == AlignSelfAuto ? default(AlignItems?) : item).ToProperty(this, nameof(AlignSelf)); + } + + public int Value { get; } + + public bool IsSelected + { + get => _isSelected; + set => this.RaiseAndSetIfChanged(ref _isSelected, value); + } + + public bool IsVisible + { + get => _isVisible; + set => this.RaiseAndSetIfChanged(ref _isVisible, value); + } + + public AlignItems AlignSelfItem + { + get => _alignSelfItem; + set => this.RaiseAndSetIfChanged(ref _alignSelfItem, value); + } + + public AlignItems? AlignSelf => _alignSelf.Value; + + public int Order + { + get => _order; + set => this.RaiseAndSetIfChanged(ref _order, value); + } + } +} diff --git a/samples/Avalonia.Labs.Catalog/ViewModels/FlexViewModel.cs b/samples/Avalonia.Labs.Catalog/ViewModels/FlexViewModel.cs new file mode 100644 index 0000000..1bf5546 --- /dev/null +++ b/samples/Avalonia.Labs.Catalog/ViewModels/FlexViewModel.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Linq; +using System.Windows.Input; + +using Avalonia.Labs.Catalog.Views; +using Avalonia.Labs.Panels; + +using ReactiveUI; + +namespace Avalonia.Labs.Catalog.ViewModels +{ + public sealed class FlexViewModel : ViewModelBase + { + private readonly ObservableCollection _numbers; + + private FlexDirection _direction = FlexDirection.Row; + private JustifyContent _justifyContent = JustifyContent.FlexStart; + private AlignItems _alignItems = AlignItems.FlexStart; + private AlignContent _alignContent = AlignContent.FlexStart; + private FlexWrap _wrap = FlexWrap.Wrap; + + private int _columnSpacing = 8; + private int _rowSpacing = 32; + + private int _currentNumber = 41; + + private FlexItemViewModel? _selectedItem; + + static FlexViewModel() + { + ViewLocator.Register(typeof(FlexViewModel), () => new FlexView()); + } + + public FlexViewModel() + { + Title = "Flex View"; + + _numbers = new ObservableCollection(Enumerable.Range(1, 40).Select(x => new FlexItemViewModel(x))); + + Numbers = new ReadOnlyObservableCollection(_numbers); + + AddItemCommand = ReactiveCommand.Create(AddItem); + RemoveItemCommand = ReactiveCommand.Create(RemoveItem, this.WhenAnyValue(vm => vm.SelectedItem).Select(x => x != null)); + } + + public IEnumerable DirectionValues { get; } = Enum.GetValues(typeof(FlexDirection)); + + public IEnumerable JustifyContentValues { get; } = Enum.GetValues(typeof(JustifyContent)); + + public IEnumerable AlignItemsValues { get; } = Enum.GetValues(typeof(AlignItems)); + + public IEnumerable AlignContentValues { get; } = Enum.GetValues(typeof(AlignContent)); + + public IEnumerable WrapValues { get; } = Enum.GetValues(typeof(FlexWrap)); + + public IEnumerable AlignSelfValues { get; } = Enum.GetValues(typeof(AlignItems)).Cast().Prepend(FlexItemViewModel.AlignSelfAuto); + + public FlexDirection Direction + { + get => _direction; + set => this.RaiseAndSetIfChanged(ref _direction, value); + } + + public JustifyContent JustifyContent + { + get => _justifyContent; + set => this.RaiseAndSetIfChanged(ref _justifyContent, value); + } + + public AlignItems AlignItems + { + get => _alignItems; + set => this.RaiseAndSetIfChanged(ref _alignItems, value); + } + + public AlignContent AlignContent + { + get => _alignContent; + set => this.RaiseAndSetIfChanged(ref _alignContent, value); + } + + public FlexWrap Wrap + { + get => _wrap; + set => this.RaiseAndSetIfChanged(ref _wrap, value); + } + + public int ColumnSpacing + { + get => _columnSpacing; + set => this.RaiseAndSetIfChanged(ref _columnSpacing, value); + } + + public int RowSpacing + { + get => _rowSpacing; + set => this.RaiseAndSetIfChanged(ref _rowSpacing, value); + } + + public ReadOnlyObservableCollection Numbers { get; } + + public FlexItemViewModel? SelectedItem + { + get => _selectedItem; + set => this.RaiseAndSetIfChanged(ref _selectedItem, value); + } + + public ICommand AddItemCommand { get; } + + public ICommand RemoveItemCommand { get; } + + private void AddItem() => _numbers.Add(new FlexItemViewModel(_currentNumber++)); + + private void RemoveItem() + { + if (SelectedItem is null) + { + throw new InvalidOperationException(); + } + + _numbers.Remove(SelectedItem); + + SelectedItem.IsSelected = false; + SelectedItem = null; + } + } +} diff --git a/samples/Avalonia.Labs.Catalog/Views/FlexView.axaml b/samples/Avalonia.Labs.Catalog/Views/FlexView.axaml new file mode 100644 index 0000000..abef942 --- /dev/null +++ b/samples/Avalonia.Labs.Catalog/Views/FlexView.axaml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +