From ba06047a6878919447c41dc7e68dbb069db16b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20Kov=C3=A1cs?= Date: Mon, 28 Aug 2023 21:29:15 +0200 Subject: [PATCH] Console size scan --- .../ChildElementPreview.cs | 3 +- .../SizeScanElement.cs | 3 + .../SizeScanTask.cs | 6 +- .../FileTime.App.Core.Abstraction.csproj | 5 + .../ViewModels/IElementViewModel.cs | 4 +- .../ViewModels/IFileViewModel.cs | 10 -- .../FileTime.App.Core.csproj | 1 + .../FileTime.App.Core/Helpers}/ColorHelper.cs | 2 +- .../Helpers/SizePreviewItemHelper.cs | 27 +++ .../NavigationUserCommandHandlerService.cs | 2 +- src/AppCommon/FileTime.App.Core/Startup.cs | 1 - .../ViewModels/ContainerViewModel.cs | 2 +- .../ViewModels/ElementViewModel.cs | 12 +- .../ViewModels/FileViewModel.cs | 20 --- .../ViewModels/TabViewModel.cs | 23 +-- .../Controls/ItemPreviews.cs | 151 ++++++++++++++-- .../FileTime.ConsoleUI.App.csproj | 1 + .../FileTime.ConsoleUI.App/MainWindow.cs | 82 ++++----- src/ConsoleApp/FileTime.ConsoleUI/Program.cs | 3 - src/ConsoleApp/FileTime.ConsoleUI/Startup.cs | 2 +- .../Models/Extensions/FileExtension.cs | 3 - .../Models/IElement.cs | 2 +- .../Copy/CalculateStrategy.cs | 3 +- src/Core/FileTime.Core.Models/Element.cs | 1 + src/Core/FileTime.Core.Services/Tab.cs | 7 +- .../Converters/ItemSizeToBrushConverter.cs | 20 +-- .../FileTime.GuiApp.App/Views/ItemView.axaml | 88 ++++----- .../Services/ItemPreview.cs | 1 + .../Avalonia/FileTime.GuiApp/App.axaml.cs | 1 - .../TerminalUI/Color/AnsiColorProvider.cs | 37 +--- .../TerminalUI/Color/ColorProviderBase.cs | 40 ++++- src/Library/TerminalUI/Color/ColorRGB.cs | 4 +- .../TerminalUI/Color/ConsoleColorProvider.cs | 167 ++++++++++++++---- .../TerminalUI/Color/IColorProvider.cs | 1 + src/Library/TerminalUI/Color/Rgb.cs | 33 ++++ .../TerminalUI/ConsoleDrivers/XTermDriver.cs | 1 + src/Library/TerminalUI/Controls/Grid.cs | 16 +- src/Library/TerminalUI/Controls/Rectangle.cs | 5 +- src/Library/TerminalUI/Controls/View.cs | 12 +- .../ExpressionTrackers/BinaryTracker.cs | 2 + .../ExpressionTrackers/TypeBinaryTracker.cs | 26 +++ src/Library/TerminalUI/PropertyTrackerBase.cs | 7 +- .../LocalContentProvider.cs | 9 +- 43 files changed, 567 insertions(+), 279 deletions(-) delete mode 100644 src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs rename src/{GuiApp/Avalonia/FileTime.GuiApp.App/Helper => AppCommon/FileTime.App.Core/Helpers}/ColorHelper.cs (96%) create mode 100644 src/AppCommon/FileTime.App.Core/Helpers/SizePreviewItemHelper.cs delete mode 100644 src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs delete mode 100644 src/Core/FileTime.Core.Abstraction/Models/Extensions/FileExtension.cs create mode 100644 src/Library/TerminalUI/Color/Rgb.cs create mode 100644 src/Library/TerminalUI/ExpressionTrackers/TypeBinaryTracker.cs diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/ChildElementPreview.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/ChildElementPreview.cs index 3be8d52..3f85267 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/ChildElementPreview.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/ChildElementPreview.cs @@ -1,4 +1,5 @@ using DeclarativeProperty; +using FileTime.Core.Models; namespace FileTime.App.ContainerSizeScanner; @@ -7,7 +8,7 @@ public class ChildElementPreview : ISizePreviewItem public ChildElementPreview(ISizeScanElement element) { Name = element.Name; - Size = element.Size; + Size = new DeclarativeProperty(((IElement) element).Size); } public string Name { get; } diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanElement.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanElement.cs index 7175f8f..b01eca3 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanElement.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanElement.cs @@ -18,6 +18,9 @@ public record SizeScanElement : ISizeScanElement public required DateTime? ModifiedAt { get; init;} public required IDeclarativeProperty Size { get; init; } + + long IElement.Size => Size.Value; + public bool IsHidden => false; public bool IsExists => true; public SupportsDelete CanDelete => SupportsDelete.False; diff --git a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs index 5252089..45c2538 100644 --- a/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs +++ b/src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs @@ -1,7 +1,6 @@ using DeclarativeProperty; using FileTime.Core.Enums; using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; using Microsoft.Extensions.Logging; @@ -104,10 +103,7 @@ public class SizeScanTask : ISizeScanTask { if (_cancelled) return; - var fileExtension = element.GetExtension(); - var size = fileExtension?.Size ?? 0; - - var sizeProperty = new DeclarativeProperty(size); + var sizeProperty = new DeclarativeProperty(element.Size); var childName = sizeScanContainer.FullName!.GetChild(element.Name).Path; var childElement = new SizeScanElement diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj b/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj index 0d64f1a..748c5cc 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj +++ b/src/AppCommon/FileTime.App.Core.Abstraction/FileTime.App.Core.Abstraction.csproj @@ -25,4 +25,9 @@ + + + + + diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs index 41735c5..fbe04e2 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs @@ -7,8 +7,8 @@ namespace FileTime.App.Core.ViewModels; public interface IElementViewModel : IItemViewModel, - ISizeProvider, - IInitable + IInitable, + ISizeProvider { IElement? Element { get; } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs deleted file mode 100644 index ccb6a5d..0000000 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs +++ /dev/null @@ -1,10 +0,0 @@ -using FileTime.App.Core.Models.Enums; -using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; -using InitableService; - -namespace FileTime.App.Core.ViewModels; - -public interface IFileViewModel : IElementViewModel, IInitable -{ -} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj index 8f3dcfc..cb16d26 100644 --- a/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj +++ b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj @@ -44,4 +44,5 @@ + diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Helper/ColorHelper.cs b/src/AppCommon/FileTime.App.Core/Helpers/ColorHelper.cs similarity index 96% rename from src/GuiApp/Avalonia/FileTime.GuiApp.App/Helper/ColorHelper.cs rename to src/AppCommon/FileTime.App.Core/Helpers/ColorHelper.cs index 437d116..7ca2024 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Helper/ColorHelper.cs +++ b/src/AppCommon/FileTime.App.Core/Helpers/ColorHelper.cs @@ -1,4 +1,4 @@ -namespace FileTime.GuiApp.App.Helper; +namespace FileTime.App.Core.Helpers; public static class ColorHelper { diff --git a/src/AppCommon/FileTime.App.Core/Helpers/SizePreviewItemHelper.cs b/src/AppCommon/FileTime.App.Core/Helpers/SizePreviewItemHelper.cs new file mode 100644 index 0000000..fd08081 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/Helpers/SizePreviewItemHelper.cs @@ -0,0 +1,27 @@ +using System.Collections.ObjectModel; +using FileTime.App.ContainerSizeScanner; + +namespace FileTime.App.Core.Helpers; + +public static class SizePreviewItemHelper +{ + public static (byte r, byte g, byte b) GetItemColor( + ObservableCollection items, + ISizePreviewItem currentItem, + double hueDiff = 0, + double lightness = 0.75 + ) + { + var i = 0; + for (; i < items.Count; i++) + { + if (items[i].Name == currentItem.Name) break; + } + + var hue = (360d * i / (items.Count < 1 ? 1 : items.Count)) + hueDiff; + if (hue > 360) hue -= 360; + if (hue < 0) hue += 360; + + return ColorHelper.HlsToRgb(hue, lightness, 1); + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs index df20a59..de7fdc2 100644 --- a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs +++ b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/NavigationUserCommandHandlerService.cs @@ -321,7 +321,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase { if (_selectedTab is null || _currentItems?.Value is null) return Task.CompletedTask; - var newSelectedItem = getNewSelected(_currentItems.Value); + var newSelectedItem = getNewSelected(_currentItems.Value.ToArray()); if (newSelectedItem == null) return Task.CompletedTask; if (_selectedTab.Tab is { } tab) diff --git a/src/AppCommon/FileTime.App.Core/Startup.cs b/src/AppCommon/FileTime.App.Core/Startup.cs index 5cf3382..5613fe8 100644 --- a/src/AppCommon/FileTime.App.Core/Startup.cs +++ b/src/AppCommon/FileTime.App.Core/Startup.cs @@ -18,7 +18,6 @@ public static class Startup serviceCollection.TryAddTransient(); serviceCollection.TryAddTransient(); serviceCollection.TryAddTransient(); - serviceCollection.TryAddTransient(); serviceCollection.TryAddTransient(); serviceCollection.TryAddTransient(); serviceCollection.TryAddSingleton(); diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs index ce00f89..f3557c6 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs @@ -4,7 +4,7 @@ using FileTime.Core.Models; namespace FileTime.App.Core.ViewModels; -public partial class ContainerViewModel : ItemViewModel, IContainerViewModel +public class ContainerViewModel : ItemViewModel, IContainerViewModel { public IContainer? Container => BaseItem as IContainer; diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs index 68c1868..53c13f9 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs @@ -5,16 +5,20 @@ using FileTime.Core.Models; namespace FileTime.App.Core.ViewModels; -public partial class ElementViewModel : ItemViewModel, IElementViewModel +public class ElementViewModel : ItemViewModel, IElementViewModel { + private readonly DeclarativeProperty _size = new(0); public IElement? Element => BaseItem as Element; public ElementViewModel(IItemNameConverterService itemNameConverterService, IAppState appState) : base(itemNameConverterService, appState) { } - public void Init(IElement item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) - => Init((IItem)item, parentTab, itemViewModelType); + public void Init(IElement item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) + { + Init((IItem) item, parentTab, itemViewModelType); + _size.SetValueSafe(item.Size); + } - public IDeclarativeProperty Size { get; protected set; } = new DeclarativeProperty(0); + public IDeclarativeProperty Size => _size; } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs deleted file mode 100644 index 5b13e55..0000000 --- a/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DeclarativeProperty; -using FileTime.App.Core.Models.Enums; -using FileTime.App.Core.Services; -using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; - -namespace FileTime.App.Core.ViewModels; - -public partial class FileViewModel : ElementViewModel, IFileViewModel -{ - public FileViewModel(IItemNameConverterService itemNameConverterService, IAppState appState) : base(itemNameConverterService, appState) - { - } - - public void Init(IElement item, FileExtension fileExtension, ITabViewModel parentTab, ItemViewModelType itemViewModelType) - { - Init(item, parentTab, itemViewModelType); - Size = new DeclarativeProperty(fileExtension.Size ?? 0); - } -} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs index 35a13b6..13060d1 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs @@ -7,7 +7,6 @@ using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Services; using FileTime.Core.Enums; using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; using FileTime.Core.Services; using FileTime.Core.Timeline; using InitableService; @@ -206,25 +205,11 @@ public partial class TabViewModel : ITabViewModel } else if (item is IElement element) { - var fileExtension = element.GetExtension(); + var elementViewModel = _serviceProvider + .GetInitableResolver(element, this, type) + .GetRequiredService(); - if (fileExtension is not null) - { - var fileViewModel = _serviceProvider - .GetInitableResolver( - element, fileExtension, this, type) - .GetRequiredService(); - - return fileViewModel; - } - else - { - var elementViewModel = _serviceProvider - .GetInitableResolver(element, this, type) - .GetRequiredService(); - - return elementViewModel; - } + return elementViewModel; } throw new ArgumentException($"{nameof(item)} is not {nameof(IContainer)} neither {nameof(IElement)}"); diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemPreviews.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemPreviews.cs index cac5643..b46e4dc 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemPreviews.cs +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemPreviews.cs @@ -1,7 +1,12 @@ -using FileTime.App.Core.Models; +using System.Collections.ObjectModel; +using FileTime.App.ContainerSizeScanner; +using FileTime.App.Core.Helpers; +using FileTime.App.Core.Models; using FileTime.App.Core.ViewModels.ItemPreview; using FileTime.ConsoleUI.App.Preview; using FileTime.ConsoleUI.App.Styling; +using Humanizer.Bytes; +using TerminalUI.Color; using TerminalUI.Controls; using TerminalUI.Extensions; using TerminalUI.Models; @@ -13,11 +18,18 @@ public class ItemPreviews { private readonly ITheme _theme; private readonly IConsoleAppState _appState; + private readonly IColorProvider _colorProvider; + private ItemsControl _sizePreviews; - public ItemPreviews(ITheme theme, IConsoleAppState appState) + public ItemPreviews( + ITheme theme, + IConsoleAppState appState, + IColorProvider colorProvider + ) { _theme = theme; _appState = appState; + _colorProvider = colorProvider; } public IView View() @@ -38,7 +50,11 @@ public class ItemPreviews fallbackValue: false)), ElementPreviews() .WithDataContextBinding( - dc => (IElementPreviewViewModel)dc.ItemPreviewService.ItemPreview.Value + dc => (IElementPreviewViewModel) dc.ItemPreviewService.ItemPreview.Value + ), + SizeContainerPreview() + .WithDataContextBinding( + dc => (ContainerPreview) dc.ItemPreviewService.ItemPreview.Value ) } }; @@ -46,6 +62,125 @@ public class ItemPreviews return view; } + private IView SizeContainerPreview() + { + var sizePreviews = new ItemsControl + { + Orientation = Orientation.Horizontal, + Margin = "0 0 0 1" + }; + sizePreviews.Setup(c => c.Bind( + c, + dc => dc.TopItems, + c => c.ItemsSource)); + + _sizePreviews = sizePreviews; + + sizePreviews.ItemTemplate = SizeContainerItem; + + var root = new Grid + { + RowDefinitionsObject = "Auto Auto", + ChildInitializer = + { + sizePreviews, + new ItemsControl + { + Extensions = {new GridPositionExtension(0, 1)}, + ItemTemplate = () => + { + var root = new Grid + { + ColumnDefinitionsObject = "5 11 *", + ChildInitializer = + { + new Rectangle + { + Height = 1, + Width = 3 + } + .Setup(r => r.Bind( + r, + dc => GenerateSizeBackground(_sizePreviews.DataContext.TopItems, dc), + r => r.Fill)), + new TextBlock + { + Extensions = {new GridPositionExtension(1, 0)}, + TextAlignment = TextAlignment.Right, + Margin = "0 0 1 0" + } + .Setup(t => t.Bind( + t, + dc => dc.Size.Value, + t => t.Text, + v => ByteSize.FromBytes(v).ToString())), + new TextBlock + { + Extensions = {new GridPositionExtension(2, 0)} + } + .Setup(t => t.Bind( + t, + dc => dc.Name, + t => t.Text)) + } + }; + + return root; + } + } + .Setup(c => c.Bind( + c, + dc => dc.TopItems, + c => c.ItemsSource)) + } + }; + + root.Bind( + root, + dc => dc.Name == ContainerPreview.PreviewName, + r => r.IsVisible); + + return root; + } + + private Grid SizeContainerItem() + { + var root = new Grid + { + ChildInitializer = + { + new Rectangle + { + Height = 1 + } + .Setup(r => r.Bind( + r, + dc => GenerateSizeBackground(_sizePreviews.DataContext.TopItems, dc), + r => r.Fill)) + } + }; + + root.Bind( + root, + dc => GetWidth(dc.Size.Value, _sizePreviews.DataContext.TopItems, _sizePreviews.ActualWidth), + r => r.Width); + + return root; + } + + private int? GetWidth(long sizeValue, ObservableCollection? dataContextTopItems, int rootActualWidth) + => dataContextTopItems is null + ? 0 + : (int) Math.Floor((double) rootActualWidth * sizeValue / dataContextTopItems.Select(i => i.Size.Value).Sum()); + + private IColor? GenerateSizeBackground(ObservableCollection topItems, ISizePreviewItem? dc) + { + if (dc is null) return null; + var (r, g, b) = SizePreviewItemHelper.GetItemColor(topItems, dc); + + return _colorProvider.FromRgb(new Rgb(r, g, b), ColorType.Background); + } + private IView ElementPreviews() { var view = new Grid @@ -60,7 +195,6 @@ public class ItemPreviews t, dc => dc.Mode == ItemPreviewMode.Unknown, t => t.IsVisible, - v => v, fallbackValue: false)), new TextBlock { @@ -70,7 +204,6 @@ public class ItemPreviews t, dc => dc.Mode == ItemPreviewMode.Empty, t => t.IsVisible, - v => v, fallbackValue: false)), new Grid { @@ -85,7 +218,7 @@ public class ItemPreviews dc => dc.TextContent, t => t.Text, fallbackValue: string.Empty); - + t.Bind( t, dc => _appState.PreviewType, @@ -99,7 +232,7 @@ public class ItemPreviews b, dc => dc.BinaryContent, b => b.Data); - + b.Bind( b, dc => _appState.PreviewType, @@ -120,7 +253,6 @@ public class ItemPreviews t, dc => dc.Mode == ItemPreviewMode.Text, t => t.IsVisible, - v => v, fallbackValue: false)), } }; @@ -128,8 +260,7 @@ public class ItemPreviews view.Bind( view, dc => dc.Name == ElementPreviewViewModel.PreviewName, - v => v.IsVisible, - v => v + v => v.IsVisible ); return view; diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj b/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj index cdb554c..d1fe886 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj @@ -20,6 +20,7 @@ + diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs index 3d545bb..5da278f 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs @@ -1,5 +1,6 @@ using System.Globalization; using FileTime.App.Core.Models.Enums; +using FileTime.App.Core.Models.Traits; using FileTime.App.Core.ViewModels; using FileTime.ConsoleUI.App.Configuration; using FileTime.ConsoleUI.App.Controls; @@ -479,7 +480,9 @@ public class MainWindow list.Bind( list, - dc => dc.AppState.SelectedTab.Value.SelectedsChildren.Value.Count > 0, + dc => + dc.AppState.SelectedTab.Value.SelectedsChildren.Value.Count > 0 + && dc.ItemPreviewService.ItemPreview.Value == null, l => l.IsVisible, fallbackValue: false); @@ -534,52 +537,43 @@ public class MainWindow ); }), new StackPanel + { + Extensions = {new GridPositionExtension(1, 0)}, + ChildInitializer = { - Extensions = {new GridPositionExtension(1, 0)}, - ChildInitializer = - { - new TextBlock() - .Setup(t => - { - if (!options.ShowAttributes) return; - t.Bind( - t, - dc => ((IContainer) dc.BaseItem).Items.Count, - tb => tb.Text, - t => $" {t}"); - }) - } - } - .Setup(s => s.Bind( - s, - dc => dc.BaseItem.Type == AbsolutePathType.Container, - s => s.IsVisible)), - new StackPanel - { - Extensions = {new GridPositionExtension(1, 0)}, - ChildInitializer = - { - new TextBlock() - .Setup(t => - { - if (!options.ShowAttributes) return; - t.Bind( - t, - dc => ((IElementViewModel) dc).Size.Value, - tb => tb.Text, - v => - { - var b = ByteSize.FromBytes(v); + new TextBlock() + .Setup(t => + { + if (!options.ShowAttributes) return; + t.Bind( + t, + dc => dc is ISizeProvider + ? ((ISizeProvider) dc).Size.Value + : ((ISizeProvider) dc.BaseItem).Size.Value, + tb => tb.Text, + v => + { + var b = ByteSize.FromBytes(v); - return $"{b.LargestWholeNumberValue:0.#} " + b.GetLargestWholeNumberSymbol(NumberFormatInfo.CurrentInfo).First(); - }); - }) - } + return $"{b.LargestWholeNumberValue:0.#} " + b.GetLargestWholeNumberSymbol(NumberFormatInfo.CurrentInfo).First(); + }); + }), + + /*new TextBlock() + .Setup(t => + { + if (!options.ShowAttributes) return; + t.Bind( + t, + dc => ((IContainer) dc.BaseItem).Items.Count, + tb => tb.Text, + t => $" {t,4}"); + }).Setup(s => s.Bind( + s, + dc => dc.BaseItem.Type == AbsolutePathType.Container, + s => s.IsVisible))*/ } - .Setup(s => s.Bind( - s, - dc => dc.BaseItem.Type == AbsolutePathType.Element, - s => s.IsVisible)) + }, } } } diff --git a/src/ConsoleApp/FileTime.ConsoleUI/Program.cs b/src/ConsoleApp/FileTime.ConsoleUI/Program.cs index 268c245..a936bba 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI/Program.cs +++ b/src/ConsoleApp/FileTime.ConsoleUI/Program.cs @@ -1,6 +1,4 @@ using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; using FileTime.App.Core; using FileTime.App.Core.Configuration; using FileTime.ConsoleUI; @@ -52,7 +50,6 @@ try } finally { - driver?.Clear(); driver?.SetCursorVisible(true); driver?.Dispose(); } diff --git a/src/ConsoleApp/FileTime.ConsoleUI/Startup.cs b/src/ConsoleApp/FileTime.ConsoleUI/Startup.cs index ca13476..5a5326a 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI/Startup.cs +++ b/src/ConsoleApp/FileTime.ConsoleUI/Startup.cs @@ -17,7 +17,7 @@ public static class Startup { public static readonly Dictionary> Drivers = new() { - ["windows"] = () => new XTermDriver(), + ["xterm"] = () => new XTermDriver(), ["dotnet"] = () => new DotnetDriver() }; public static IServiceCollection AddConsoleDriver(this IServiceCollection serviceCollection) diff --git a/src/Core/FileTime.Core.Abstraction/Models/Extensions/FileExtension.cs b/src/Core/FileTime.Core.Abstraction/Models/Extensions/FileExtension.cs deleted file mode 100644 index 912492f..0000000 --- a/src/Core/FileTime.Core.Abstraction/Models/Extensions/FileExtension.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace FileTime.Core.Models.Extensions; - -public record FileExtension(long? Size); \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/Models/IElement.cs b/src/Core/FileTime.Core.Abstraction/Models/IElement.cs index 2b48a74..7e31a6d 100644 --- a/src/Core/FileTime.Core.Abstraction/Models/IElement.cs +++ b/src/Core/FileTime.Core.Abstraction/Models/IElement.cs @@ -2,5 +2,5 @@ namespace FileTime.Core.Models; public interface IElement : IItem { - + long Size { get; } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Command/Copy/CalculateStrategy.cs b/src/Core/FileTime.Core.Command/Copy/CalculateStrategy.cs index de507f5..df7f049 100644 --- a/src/Core/FileTime.Core.Command/Copy/CalculateStrategy.cs +++ b/src/Core/FileTime.Core.Command/Copy/CalculateStrategy.cs @@ -1,5 +1,4 @@ using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; namespace FileTime.Core.Command.Copy; @@ -20,7 +19,7 @@ public class CalculateStrategy : ICopyStrategy public async Task CopyAsync(AbsolutePath from, AbsolutePath to, CopyCommandContext context) { var resolvedFrom = await from.ResolveAsync(); - _operationStatuses.Add(new OperationProgress(from.Path.Path, (resolvedFrom as IElement)?.GetExtension()?.Size ?? 0L)); + _operationStatuses.Add(new OperationProgress(from.Path.Path, (resolvedFrom as IElement)?.Size ?? 0L)); } public Task CreateContainerAsync(IContainer target, string name, PointInTime currentTime) => Task.CompletedTask; diff --git a/src/Core/FileTime.Core.Models/Element.cs b/src/Core/FileTime.Core.Models/Element.cs index af1dca0..a56d654 100644 --- a/src/Core/FileTime.Core.Models/Element.cs +++ b/src/Core/FileTime.Core.Models/Element.cs @@ -18,6 +18,7 @@ public record Element( SupportsDelete CanDelete, bool CanRename, string? Attributes, + long Size, IContentProvider Provider, PointInTime PointInTime, ObservableCollection Exceptions, diff --git a/src/Core/FileTime.Core.Services/Tab.cs b/src/Core/FileTime.Core.Services/Tab.cs index 7e9b5b4..abffbed 100644 --- a/src/Core/FileTime.Core.Services/Tab.cs +++ b/src/Core/FileTime.Core.Services/Tab.cs @@ -6,7 +6,6 @@ using DeclarativeProperty; using DynamicData; using FileTime.Core.Helper; using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; using ObservableComputations; using IContainer = FileTime.Core.Models.IContainer; @@ -178,12 +177,12 @@ public class Tab : ITab private static long GetSize(IItem item) { - if (item is IElement element && element.GetExtension() is { } fileExtension) + if (item is IElement element) { - return fileExtension.Size ?? -1; + return element.Size; } - return -2; + return -1; } private static IItem MapItem(AbsolutePath item) diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Converters/ItemSizeToBrushConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Converters/ItemSizeToBrushConverter.cs index e12f5a7..cbe65dd 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Converters/ItemSizeToBrushConverter.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Converters/ItemSizeToBrushConverter.cs @@ -3,7 +3,7 @@ using Avalonia.Data.Converters; using Avalonia.Media; using Avalonia.Threading; using FileTime.App.ContainerSizeScanner; -using FileTime.GuiApp.App.Helper; +using FileTime.App.Core.Helpers; namespace FileTime.GuiApp.App.Converters; @@ -16,18 +16,12 @@ public class ItemSizeToBrushConverter : IMultiValueConverter { if (values is [ISizePreviewItem previewItem, ContainerPreview sizeContainerViewModel]) { - var items = sizeContainerViewModel.TopItems; - var i = 0; - for (; i < items.Count; i++) - { - if (items[i].Name == previewItem.Name) break; - } - - var hue = (360d * i / (items.Count < 1 ? 1 : items.Count)) + HueDiff; - if (hue > 360) hue -= 360; - if (hue < 0) hue += 360; - - var (r, g, b) = ColorHelper.HlsToRgb(hue, Lightness, 1); + var (r, g, b) = SizePreviewItemHelper.GetItemColor( + sizeContainerViewModel.TopItems, + previewItem, + HueDiff, + Lightness + ); var task = Dispatcher.UIThread.InvokeAsync(() => new SolidColorBrush(Color.FromRgb(r, g, b))); task.Wait(); diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/ItemView.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/ItemView.axaml index d7d3382..1ffda4f 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/ItemView.axaml +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/ItemView.axaml @@ -1,48 +1,52 @@ + x:Name="ItemRoot" + HorizontalAlignment="Stretch" + HorizontalContentAlignment="Stretch" + d:DesignHeight="450" + d:DesignWidth="800" + x:CompileBindings="True" + x:DataType="appcore:IItemViewModel" + Background="{Binding ViewMode.Value, Converter={StaticResource ItemViewModeToBackgroundConverter}}" + mc:Ignorable="d"> + ColumnDefinitions="20,*,Auto"> + Source="{Binding Converter={StaticResource ItemToImageConverter}}" /> - - + + @@ -54,52 +58,50 @@ - + - - + + - + Text="{Binding BaseItem.DisplayName, Converter={StaticResource GetFileExtensionConverter}}" /> + - - - - + TextAlignment="Right" /> + TextAlignment="Right" /> + TextAlignment="Right" /> + TextAlignment="Right" /> diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.DesignPreview/Services/ItemPreview.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.DesignPreview/Services/ItemPreview.cs index a9489f2..975da3f 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.DesignPreview/Services/ItemPreview.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.DesignPreview/Services/ItemPreview.cs @@ -58,6 +58,7 @@ public class ItemPreview SupportsDelete.True, true, "attr", + 0, null!, PointInTime.Present, new ObservableCollection(), diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs index ba4f6d1..ea20738 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/App.axaml.cs @@ -10,7 +10,6 @@ using FileTime.GuiApp.App.Font; using FileTime.GuiApp.App.ViewModels; using FileTime.GuiApp.App.Views; using FileTime.Server; -using FileTime.Server.Common; using FileTime.Tools.Compression; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Library/TerminalUI/Color/AnsiColorProvider.cs b/src/Library/TerminalUI/Color/AnsiColorProvider.cs index f51e80a..7255218 100644 --- a/src/Library/TerminalUI/Color/AnsiColorProvider.cs +++ b/src/Library/TerminalUI/Color/AnsiColorProvider.cs @@ -6,49 +6,24 @@ public class AnsiColorProvider : ColorProviderBase { var finalColor = ParseInternal(color, type); - finalColor ??= ParseHexColor(color, type); + finalColor ??= FromRgb(color, type); if (finalColor is not null) return finalColor; throw new NotSupportedException($"Color can not be parsed. {color}"); } - private static IColor? ParseHexColor(string color, ColorType colorType) + private IColor? FromRgb(string color, ColorType type) { - if (!color.StartsWith("#")) return null; - if (color.Length == 4) + if (ParseHexColor(color) is var (r, g, b)) { - var r = ColorCharToColorByte(color[1]); - var g = ColorCharToColorByte(color[2]); - var b = ColorCharToColorByte(color[3]); - - r += (byte) (r << 4); - g += (byte) (g << 4); - b += (byte) (b << 4); - - return new ColorRgb(r, g, b, colorType); - } - - if (color.Length == 7) - { - var r = (byte) (ColorCharToColorByte(color[1]) << 4 | ColorCharToColorByte(color[2])); - var g = (byte) (ColorCharToColorByte(color[3]) << 4 | ColorCharToColorByte(color[4])); - var b = (byte) (ColorCharToColorByte(color[5]) << 4 | ColorCharToColorByte(color[6])); - - return new ColorRgb(r, g, b, colorType); + return new ColorRgb(r, g, b, type); } - throw new NotSupportedException($"Hex color can not be parsed. {color}"); + return null; } - private static byte ColorCharToColorByte(char color) => - color switch - { - >= '0' and <= '9' => (byte) (color - '0'), - >= 'A' and <= 'F' => (byte) (color - 'A' + 10), - >= 'a' and <= 'f' => (byte) (color - 'a' + 10), - _ => throw new NotSupportedException($"Hex color can not be parsed. {color}") - }; + public override IColor FromRgb(Rgb rgb, ColorType type) => new ColorRgb(rgb.R, rgb.G, rgb.B, type); public override IColor BlackForeground { get; } = new Color256(0, ColorType.Foreground); public override IColor BlueForeground { get; } = new Color256(12, ColorType.Foreground); diff --git a/src/Library/TerminalUI/Color/ColorProviderBase.cs b/src/Library/TerminalUI/Color/ColorProviderBase.cs index 44c5cec..073f4f5 100644 --- a/src/Library/TerminalUI/Color/ColorProviderBase.cs +++ b/src/Library/TerminalUI/Color/ColorProviderBase.cs @@ -3,8 +3,46 @@ public abstract class ColorProviderBase : IColorProvider { public abstract IColor Parse(string color, ColorType type); + public abstract IColor FromRgb(Rgb rgb, ColorType type); - protected IColor? ParseInternal(string color, ColorType type) + protected static Rgb? ParseHexColor(string color) + { + if (!color.StartsWith("#")) return null; + if (color.Length == 4) + { + var r = ColorCharToColorByte(color[1]); + var g = ColorCharToColorByte(color[2]); + var b = ColorCharToColorByte(color[3]); + + r += (byte) (r << 4); + g += (byte) (g << 4); + b += (byte) (b << 4); + + return new(r, g, b); + } + + if (color.Length == 7) + { + var r = (byte) (ColorCharToColorByte(color[1]) << 4 | ColorCharToColorByte(color[2])); + var g = (byte) (ColorCharToColorByte(color[3]) << 4 | ColorCharToColorByte(color[4])); + var b = (byte) (ColorCharToColorByte(color[5]) << 4 | ColorCharToColorByte(color[6])); + + return new(r, g, b); + } + + return null; + } + + private static byte ColorCharToColorByte(char color) => + color switch + { + >= '0' and <= '9' => (byte) (color - '0'), + >= 'A' and <= 'F' => (byte) (color - 'A' + 10), + >= 'a' and <= 'f' => (byte) (color - 'a' + 10), + _ => throw new NotSupportedException($"Hex color can not be parsed. {color}") + }; + + protected IColor? ParseInternal(string color, ColorType type) => (color.ToLower(), type) switch { ("black", ColorType.Foreground) => BlackForeground, diff --git a/src/Library/TerminalUI/Color/ColorRGB.cs b/src/Library/TerminalUI/Color/ColorRGB.cs index e9eec05..1e96189 100644 --- a/src/Library/TerminalUI/Color/ColorRGB.cs +++ b/src/Library/TerminalUI/Color/ColorRGB.cs @@ -7,8 +7,8 @@ public readonly record struct ColorRgb(byte R, byte G, byte B, ColorType Type) : public string ToConsoleColor() => Type switch { - ColorType.Foreground => $"\x1b[38;2;{R};{G};{B};m", - ColorType.Background => $"\x1b[48;2;{R};{G};{B};m", + ColorType.Foreground => $"\x1b[38;2;{R};{G};{B}m", + ColorType.Background => $"\x1b[48;2;{R};{G};{B}m", _ => throw new InvalidEnumArgumentException(nameof(Type), (int) Type, typeof(ColorType)) }; public IColor AsForeground() => this with {Type = ColorType.Foreground}; diff --git a/src/Library/TerminalUI/Color/ConsoleColorProvider.cs b/src/Library/TerminalUI/Color/ConsoleColorProvider.cs index 8a63373..43ae8ff 100644 --- a/src/Library/TerminalUI/Color/ConsoleColorProvider.cs +++ b/src/Library/TerminalUI/Color/ConsoleColorProvider.cs @@ -1,48 +1,143 @@ -namespace TerminalUI.Color; +// ReSharper disable InconsistentNaming +namespace TerminalUI.Color; public class ConsoleColorProvider : ColorProviderBase { + private static readonly List<(Rgb, IColor)> Foregrounds; + private static readonly List<(Rgb, IColor)> Backgrounds; + + static ConsoleColorProvider() + { + Foregrounds = new List<(Rgb, IColor)> + { + (new Rgb(0, 0, 0), _blackForeground), + (new Rgb(0, 0, 128), _darkBlueForeground), + (new Rgb(0, 128, 0), _darkGreenForeground), + (new Rgb(0, 128, 128), _darkCyanForeground), + (new Rgb(128, 0, 0), _darkRedForeground), + (new Rgb(128, 0, 128), _darkMagentaForeground), + (new Rgb(128, 128, 0), _darkYellowForeground), + (new Rgb(192, 192, 192), _grayForeground), + (new Rgb(128, 128, 128), _darkGrayForeground), + (new Rgb(0, 0, 255), _blueForeground), + (new Rgb(0, 255, 0), _greenForeground), + (new Rgb(0, 255, 255), _cyanForeground), + (new Rgb(255, 0, 0), _redForeground), + (new Rgb(255, 0, 255), _magentaForeground), + (new Rgb(255, 255, 0), _yellowForeground), + (new Rgb(255, 255, 255), _whiteForeground), + }; + + Backgrounds = new List<(Rgb, IColor)> + { + (new Rgb(0, 0, 0), _blackBackground), + (new Rgb(0, 0, 128), _darkBlueBackground), + (new Rgb(0, 128, 0), _darkGreenBackground), + (new Rgb(0, 128, 128), _darkCyanBackground), + (new Rgb(128, 0, 0), _darkRedBackground), + (new Rgb(128, 0, 128), _darkMagentaBackground), + (new Rgb(128, 128, 0), _darkYellowBackground), + (new Rgb(192, 192, 192), _grayBackground), + (new Rgb(128, 128, 128), _darkGrayBackground), + (new Rgb(0, 0, 255), _blueBackground), + (new Rgb(0, 255, 0), _greenBackground), + (new Rgb(0, 255, 255), _cyanBackground), + (new Rgb(255, 0, 0), _redBackground), + (new Rgb(255, 0, 255), _magentaBackground), + (new Rgb(255, 255, 0), _yellowBackground), + (new Rgb(255, 255, 255), _whiteBackground), + }; + } + public override IColor Parse(string color, ColorType type) { var finalColor = ParseInternal(color, type); if (finalColor is not null) return finalColor; - - //TODO get closest color - throw new NotSupportedException($"Color can not be parsed. {color}"); + //TODO get closest color + var rgb = ParseHexColor(color); + + if (rgb is null) + { + throw new NotSupportedException($"Color can not be parsed. {color}"); + } + + return FromRgb(rgb.Value, type); } - public override IColor BlackForeground { get; } = new ConsoleColor(System.ConsoleColor.Black, ColorType.Foreground); - public override IColor BlueForeground { get; } = new ConsoleColor(System.ConsoleColor.Blue, ColorType.Foreground); - public override IColor CyanForeground { get; } = new ConsoleColor(System.ConsoleColor.Cyan, ColorType.Foreground); - public override IColor DarkBlueForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkBlue, ColorType.Foreground); - public override IColor DarkCyanForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkCyan, ColorType.Foreground); - public override IColor DarkGrayForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkGray, ColorType.Foreground); - public override IColor DarkGreenForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkGreen, ColorType.Foreground); - public override IColor DarkMagentaForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkMagenta, ColorType.Foreground); - public override IColor DarkRedForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkRed, ColorType.Foreground); - public override IColor DarkYellowForeground { get; } = new ConsoleColor(System.ConsoleColor.DarkYellow, ColorType.Foreground); - public override IColor GrayForeground { get; } = new ConsoleColor(System.ConsoleColor.Gray, ColorType.Foreground); - public override IColor GreenForeground { get; } = new ConsoleColor(System.ConsoleColor.Green, ColorType.Foreground); - public override IColor MagentaForeground { get; } = new ConsoleColor(System.ConsoleColor.Magenta, ColorType.Foreground); - public override IColor RedForeground { get; } = new ConsoleColor(System.ConsoleColor.Red, ColorType.Foreground); - public override IColor WhiteForeground { get; } = new ConsoleColor(System.ConsoleColor.White, ColorType.Foreground); - public override IColor YellowForeground { get; } = new ConsoleColor(System.ConsoleColor.Yellow, ColorType.Foreground); + public override IColor FromRgb(Rgb rgb, ColorType type) + => type == ColorType.Background + ? ApproximateColor(rgb, Backgrounds) + : ApproximateColor(rgb, Foregrounds); - public override IColor BlackBackground => new ConsoleColor(System.ConsoleColor.Black, ColorType.Background); - public override IColor BlueBackground => new ConsoleColor(System.ConsoleColor.Blue, ColorType.Background); - public override IColor CyanBackground => new ConsoleColor(System.ConsoleColor.Cyan, ColorType.Background); - public override IColor DarkBlueBackground => new ConsoleColor(System.ConsoleColor.DarkBlue, ColorType.Background); - public override IColor DarkCyanBackground => new ConsoleColor(System.ConsoleColor.DarkCyan, ColorType.Background); - public override IColor DarkGrayBackground => new ConsoleColor(System.ConsoleColor.DarkGray, ColorType.Background); - public override IColor DarkGreenBackground => new ConsoleColor(System.ConsoleColor.DarkGreen, ColorType.Background); - public override IColor DarkMagentaBackground => new ConsoleColor(System.ConsoleColor.DarkMagenta, ColorType.Background); - public override IColor DarkRedBackground => new ConsoleColor(System.ConsoleColor.DarkRed, ColorType.Background); - public override IColor DarkYellowBackground => new ConsoleColor(System.ConsoleColor.DarkYellow, ColorType.Background); - public override IColor GrayBackground => new ConsoleColor(System.ConsoleColor.Gray, ColorType.Background); - public override IColor GreenBackground => new ConsoleColor(System.ConsoleColor.Green, ColorType.Background); - public override IColor MagentaBackground => new ConsoleColor(System.ConsoleColor.Magenta, ColorType.Background); - public override IColor RedBackground => new ConsoleColor(System.ConsoleColor.Red, ColorType.Background); - public override IColor WhiteBackground => new ConsoleColor(System.ConsoleColor.White, ColorType.Background); - public override IColor YellowBackground => new ConsoleColor(System.ConsoleColor.Yellow, ColorType.Background); + protected IColor ApproximateColor(Rgb rgb, IEnumerable<(Rgb, IColor)> colors) + => colors.MinBy(c => c.Item1 - rgb).Item2; + + public override IColor BlackForeground => _blackForeground; + public override IColor BlueForeground => _blueForeground; + public override IColor CyanForeground => _cyanForeground; + public override IColor DarkBlueForeground => _darkBlueForeground; + public override IColor DarkCyanForeground => _darkCyanForeground; + public override IColor DarkGrayForeground => _darkGrayForeground; + public override IColor DarkGreenForeground => _darkGreenForeground; + public override IColor DarkMagentaForeground => _darkMagentaForeground; + public override IColor DarkRedForeground => _darkRedForeground; + public override IColor DarkYellowForeground => _darkYellowForeground; + public override IColor GrayForeground => _grayForeground; + public override IColor GreenForeground => _greenForeground; + public override IColor MagentaForeground => _magentaForeground; + public override IColor RedForeground => _redForeground; + public override IColor WhiteForeground => _whiteForeground; + public override IColor YellowForeground => _yellowForeground; + + public override IColor BlackBackground => _blackBackground; + public override IColor BlueBackground => _blueBackground; + public override IColor CyanBackground => _cyanBackground; + public override IColor DarkBlueBackground => _darkBlueBackground; + public override IColor DarkCyanBackground => _darkCyanBackground; + public override IColor DarkGrayBackground => _darkGrayBackground; + public override IColor DarkGreenBackground => _darkGreenBackground; + public override IColor DarkMagentaBackground => _darkMagentaBackground; + public override IColor DarkRedBackground => _darkRedBackground; + public override IColor DarkYellowBackground => _darkYellowBackground; + public override IColor GrayBackground => _grayBackground; + public override IColor GreenBackground => _greenBackground; + public override IColor MagentaBackground => _magentaBackground; + public override IColor RedBackground => _redBackground; + public override IColor WhiteBackground => _whiteBackground; + public override IColor YellowBackground => _yellowBackground; + + private static readonly IColor _blackForeground = new ConsoleColor(System.ConsoleColor.Black, ColorType.Foreground); + private static readonly IColor _blueForeground = new ConsoleColor(System.ConsoleColor.Blue, ColorType.Foreground); + private static readonly IColor _cyanForeground = new ConsoleColor(System.ConsoleColor.Cyan, ColorType.Foreground); + private static readonly IColor _darkBlueForeground = new ConsoleColor(System.ConsoleColor.DarkBlue, ColorType.Foreground); + private static readonly IColor _darkCyanForeground = new ConsoleColor(System.ConsoleColor.DarkCyan, ColorType.Foreground); + private static readonly IColor _darkGrayForeground = new ConsoleColor(System.ConsoleColor.DarkGray, ColorType.Foreground); + private static readonly IColor _darkGreenForeground = new ConsoleColor(System.ConsoleColor.DarkGreen, ColorType.Foreground); + private static readonly IColor _darkMagentaForeground = new ConsoleColor(System.ConsoleColor.DarkMagenta, ColorType.Foreground); + private static readonly IColor _darkRedForeground = new ConsoleColor(System.ConsoleColor.DarkRed, ColorType.Foreground); + private static readonly IColor _darkYellowForeground = new ConsoleColor(System.ConsoleColor.DarkYellow, ColorType.Foreground); + private static readonly IColor _grayForeground = new ConsoleColor(System.ConsoleColor.Gray, ColorType.Foreground); + private static readonly IColor _greenForeground = new ConsoleColor(System.ConsoleColor.Green, ColorType.Foreground); + private static readonly IColor _magentaForeground = new ConsoleColor(System.ConsoleColor.Magenta, ColorType.Foreground); + private static readonly IColor _redForeground = new ConsoleColor(System.ConsoleColor.Red, ColorType.Foreground); + private static readonly IColor _whiteForeground = new ConsoleColor(System.ConsoleColor.White, ColorType.Foreground); + private static readonly IColor _yellowForeground = new ConsoleColor(System.ConsoleColor.Yellow, ColorType.Foreground); + + private static readonly IColor _blackBackground = new ConsoleColor(System.ConsoleColor.Black, ColorType.Background); + private static readonly IColor _blueBackground = new ConsoleColor(System.ConsoleColor.Blue, ColorType.Background); + private static readonly IColor _cyanBackground = new ConsoleColor(System.ConsoleColor.Cyan, ColorType.Background); + private static readonly IColor _darkBlueBackground = new ConsoleColor(System.ConsoleColor.DarkBlue, ColorType.Background); + private static readonly IColor _darkCyanBackground = new ConsoleColor(System.ConsoleColor.DarkCyan, ColorType.Background); + private static readonly IColor _darkGrayBackground = new ConsoleColor(System.ConsoleColor.DarkGray, ColorType.Background); + private static readonly IColor _darkGreenBackground = new ConsoleColor(System.ConsoleColor.DarkGreen, ColorType.Background); + private static readonly IColor _darkMagentaBackground = new ConsoleColor(System.ConsoleColor.DarkMagenta, ColorType.Background); + private static readonly IColor _darkRedBackground = new ConsoleColor(System.ConsoleColor.DarkRed, ColorType.Background); + private static readonly IColor _darkYellowBackground = new ConsoleColor(System.ConsoleColor.DarkYellow, ColorType.Background); + private static readonly IColor _grayBackground = new ConsoleColor(System.ConsoleColor.Gray, ColorType.Background); + private static readonly IColor _greenBackground = new ConsoleColor(System.ConsoleColor.Green, ColorType.Background); + private static readonly IColor _magentaBackground = new ConsoleColor(System.ConsoleColor.Magenta, ColorType.Background); + private static readonly IColor _redBackground = new ConsoleColor(System.ConsoleColor.Red, ColorType.Background); + private static readonly IColor _whiteBackground = new ConsoleColor(System.ConsoleColor.White, ColorType.Background); + private static readonly IColor _yellowBackground = new ConsoleColor(System.ConsoleColor.Yellow, ColorType.Background); } \ No newline at end of file diff --git a/src/Library/TerminalUI/Color/IColorProvider.cs b/src/Library/TerminalUI/Color/IColorProvider.cs index dc314d9..ed11819 100644 --- a/src/Library/TerminalUI/Color/IColorProvider.cs +++ b/src/Library/TerminalUI/Color/IColorProvider.cs @@ -3,6 +3,7 @@ public interface IColorProvider { IColor Parse(string color, ColorType type); + IColor FromRgb(Rgb rgb, ColorType type); IColor BlackForeground { get; } IColor BlueForeground { get; } diff --git a/src/Library/TerminalUI/Color/Rgb.cs b/src/Library/TerminalUI/Color/Rgb.cs new file mode 100644 index 0000000..6bda748 --- /dev/null +++ b/src/Library/TerminalUI/Color/Rgb.cs @@ -0,0 +1,33 @@ +using System.Diagnostics; + +namespace TerminalUI.Color; + +[DebuggerDisplay("R = {R}, G = {G}, B = {B}")] +public readonly struct Rgb +{ + public readonly byte R; + public readonly byte G; + public readonly byte B; + + public Rgb(byte r, byte g, byte b) + { + R = r; + G = g; + B = b; + } + + public static double operator -(Rgb left, Rgb right) + { + var r = Math.Abs(left.R - right.R); + var g = Math.Abs(left.G - right.G); + var b = Math.Abs(left.B - right.B); + return (double)(r + g + b) / 3; + } + + public void Deconstruct(out byte r, out byte g, out byte b) + { + r = R; + g = G; + b = B; + } +} \ No newline at end of file diff --git a/src/Library/TerminalUI/ConsoleDrivers/XTermDriver.cs b/src/Library/TerminalUI/ConsoleDrivers/XTermDriver.cs index 6697cea..9a07888 100644 --- a/src/Library/TerminalUI/ConsoleDrivers/XTermDriver.cs +++ b/src/Library/TerminalUI/ConsoleDrivers/XTermDriver.cs @@ -36,6 +36,7 @@ public sealed class XTermDriver : DotnetDriver public override void ResetStyle() { Write("\x1b[0m"); + base.ResetStyle(); } public override void SetBackgroundColor(IColor background) diff --git a/src/Library/TerminalUI/Controls/Grid.cs b/src/Library/TerminalUI/Controls/Grid.cs index 008063f..7922371 100644 --- a/src/Library/TerminalUI/Controls/Grid.cs +++ b/src/Library/TerminalUI/Controls/Grid.cs @@ -127,11 +127,18 @@ public sealed class Grid : ChildCollectionView, T>, IVisibilityChange protected override Size CalculateSize() { - return WithCalculatedSize( + if (Width.HasValue && Height.HasValue) + { + return new Size(Width.Value, Height.Value); + } + + var size = WithCalculatedSize( RenderContext.Empty, new Option(new Size(0, 0), false), CalculateSizeInternal); + return new Size(Width ?? size.Width, Height ?? size.Height); + Size CalculateSizeInternal(in RenderContext _, ReadOnlySpan columnWidths, ReadOnlySpan rowHeights) { var width = 0; @@ -153,11 +160,14 @@ public sealed class Grid : ChildCollectionView, T>, IVisibilityChange protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size) { - if (size.Width == 0 || size.Height == 0) return false; + var width = Width ?? size.Width; + var height = Height ?? size.Height; + + if (width == 0 || height == 0) return false; return WithCalculatedSize( renderContext, - new Option(size, true), + new Option(new Size(width, height), true), DefaultRendererInternal ); diff --git a/src/Library/TerminalUI/Controls/Rectangle.cs b/src/Library/TerminalUI/Controls/Rectangle.cs index 4bfdf27..6c8e7fa 100644 --- a/src/Library/TerminalUI/Controls/Rectangle.cs +++ b/src/Library/TerminalUI/Controls/Rectangle.cs @@ -26,7 +26,8 @@ public sealed partial class Rectangle : View, T>, IDisplayView protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size) { var fillColor = Fill ?? Background ?? renderContext.Background; - var renderState = new RenderState(position, size, fillColor); + var renderSize = new Size(Width ?? size.Width, Height ?? size.Height); + var renderState = new RenderState(position, renderSize, fillColor); var skipRender = !renderContext.ForceRerender && !NeedsRerender(renderState); _lastRenderState = renderState; @@ -41,7 +42,7 @@ public sealed partial class Rectangle : View, T>, IDisplayView RenderEmpty( renderContext, position, - size, + renderSize, skipRender, false ); diff --git a/src/Library/TerminalUI/Controls/View.cs b/src/Library/TerminalUI/Controls/View.cs index a6fa3a6..c7d6216 100644 --- a/src/Library/TerminalUI/Controls/View.cs +++ b/src/Library/TerminalUI/Controls/View.cs @@ -146,8 +146,8 @@ public abstract partial class View : IView where TConcrete : Vi if (!IsVisible) return false; - ActualWidth = size.Width; - ActualHeight = size.Height; + ActualWidth = Width ?? size.Width; + ActualHeight = Height ?? size.Height; if (RenderMethod is null) { @@ -167,10 +167,14 @@ public abstract partial class View : IView where TConcrete : Vi ); size = new Size( - size.Width - Margin.Left - Margin.Right, - size.Height - Margin.Top - Margin.Bottom + ActualWidth - Margin.Left - Margin.Right, + ActualHeight - Margin.Top - Margin.Bottom ); } + else if (Width.HasValue || Height.HasValue) + { + size = new Size(ActualWidth, ActualHeight); + } bool renderResult; if (Background != null || Foreground != null) diff --git a/src/Library/TerminalUI/ExpressionTrackers/BinaryTracker.cs b/src/Library/TerminalUI/ExpressionTrackers/BinaryTracker.cs index 4dbc623..0bcb0c3 100644 --- a/src/Library/TerminalUI/ExpressionTrackers/BinaryTracker.cs +++ b/src/Library/TerminalUI/ExpressionTrackers/BinaryTracker.cs @@ -31,6 +31,8 @@ public class BinaryTracker : ExpressionTrackerBase ExpressionType.GreaterThanOrEqual => (v1, v2) => Comparer.Default.Compare(v1, v2) >= 0, ExpressionType.LessThan => (v1, v2) => Comparer.Default.Compare(v1, v2) < 0, ExpressionType.LessThanOrEqual => (v1, v2) => Comparer.Default.Compare(v1, v2) <= 0, + ExpressionType.AndAlso => (v1, v2) => v1 is true && v2 is true, + ExpressionType.OrElse => (v1, v2) => v1 is true || v2 is true, _ => throw new NotImplementedException() }; diff --git a/src/Library/TerminalUI/ExpressionTrackers/TypeBinaryTracker.cs b/src/Library/TerminalUI/ExpressionTrackers/TypeBinaryTracker.cs new file mode 100644 index 0000000..1d56cd2 --- /dev/null +++ b/src/Library/TerminalUI/ExpressionTrackers/TypeBinaryTracker.cs @@ -0,0 +1,26 @@ +using System.Linq.Expressions; + +namespace TerminalUI.ExpressionTrackers; + +public class TypeBinaryTracker : ExpressionTrackerBase +{ + private readonly IExpressionTracker _childExpressionTracker; + private readonly Func _computer; + + public TypeBinaryTracker(TypeBinaryExpression typeBinaryExpression, IExpressionTracker childExpressionTracker) + { + _childExpressionTracker = childExpressionTracker; + ArgumentNullException.ThrowIfNull(childExpressionTracker); + + SubscribeToValueChanges = false; + SubscribeToTracker(childExpressionTracker); + + _computer = typeBinaryExpression.NodeType switch + { + ExpressionType.TypeIs => o => o is not null && typeBinaryExpression.TypeOperand.IsInstanceOfType(o), + _ => throw new NotImplementedException() + }; + } + protected override object? ComputeValue() + => _computer(_childExpressionTracker.GetValue()); +} \ No newline at end of file diff --git a/src/Library/TerminalUI/PropertyTrackerBase.cs b/src/Library/TerminalUI/PropertyTrackerBase.cs index eb20281..745b586 100644 --- a/src/Library/TerminalUI/PropertyTrackerBase.cs +++ b/src/Library/TerminalUI/PropertyTrackerBase.cs @@ -80,10 +80,11 @@ public abstract class PropertyTrackerBase { return new ConstantTracker(constantExpression.Value); } - /*else if (expression is not ConstantExpression) + else if (expression is TypeBinaryExpression typeBinaryExpression) { - Debug.Assert(false, "Unknown expression type " + expression.GetType()); - }*/ + var childExpression = FindReactiveProperties(typeBinaryExpression.Expression, parameters); + return new TypeBinaryTracker(typeBinaryExpression, childExpression); + } throw new NotSupportedException(); } diff --git a/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs b/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs index 090e87c..8647497 100644 --- a/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs +++ b/src/Providers/FileTime.Providers.Local/LocalContentProvider.cs @@ -4,7 +4,6 @@ using DynamicData; using FileTime.Core.ContentAccess; using FileTime.Core.Enums; using FileTime.Core.Models; -using FileTime.Core.Models.Extensions; using FileTime.Core.Timeline; using Microsoft.Extensions.DependencyInjection; @@ -356,11 +355,6 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo var parent = new AbsolutePath(_timelessContentProvider, pointInTime, parentFullName, AbsolutePathType.Container); - var extensions = new ExtensionCollection() - { - new FileExtension(fileInfo.Length) - }; - return new Element( fileInfo.Name, fileInfo.Name, @@ -374,10 +368,11 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo SupportsDelete.True, true, GetFileAttributes(fileInfo), + fileInfo.Length, this, pointInTime, new ObservableCollection(), - extensions.AsReadOnly() + new ExtensionCollection().AsReadOnly() ); }