Order in Tab instead TabViewModel, Utf8 char handling
This commit is contained in:
@@ -20,7 +20,6 @@ public interface ITabViewModel : IInitable<ITab, int>, IDisposable
|
|||||||
IDeclarativeProperty<ObservableCollection<FullName>> MarkedItems { get; }
|
IDeclarativeProperty<ObservableCollection<FullName>> MarkedItems { get; }
|
||||||
IDeclarativeProperty<ObservableCollection<IItemViewModel>> SelectedsChildren { get; }
|
IDeclarativeProperty<ObservableCollection<IItemViewModel>> SelectedsChildren { get; }
|
||||||
IDeclarativeProperty<ObservableCollection<IItemViewModel>> ParentsChildren { get; }
|
IDeclarativeProperty<ObservableCollection<IItemViewModel>> ParentsChildren { get; }
|
||||||
DeclarativeProperty<ItemOrdering?> Ordering { get; }
|
|
||||||
|
|
||||||
void ClearMarkedItems();
|
void ClearMarkedItems();
|
||||||
void RemoveMarkedItem(FullName fullName);
|
void RemoveMarkedItem(FullName fullName);
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
{
|
{
|
||||||
if (_currentSelectedTab is null) return;
|
if (_currentSelectedTab is null) return;
|
||||||
|
|
||||||
await _currentSelectedTab.Ordering.SetValue(sortItemsCommand.Ordering);
|
await _currentSelectedTab.Tab.Ordering.SetValue(sortItemsCommand.Ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CopyBase64()
|
private async Task CopyBase64()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Reactive.Linq;
|
|
||||||
using DeclarativeProperty;
|
using DeclarativeProperty;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
@@ -47,7 +46,6 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
public IDeclarativeProperty<ObservableCollection<FullName>> MarkedItems { get; }
|
public IDeclarativeProperty<ObservableCollection<FullName>> MarkedItems { get; }
|
||||||
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> SelectedsChildren { get; private set; }
|
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> SelectedsChildren { get; private set; }
|
||||||
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> ParentsChildren { get; private set; }
|
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> ParentsChildren { get; private set; }
|
||||||
public DeclarativeProperty<ItemOrdering?> Ordering { get; } = new(ItemOrdering.Name);
|
|
||||||
|
|
||||||
|
|
||||||
public TabViewModel(
|
public TabViewModel(
|
||||||
@@ -82,39 +80,6 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
i => MapItemToViewModel(i, ItemViewModelType.Main)
|
i => MapItemToViewModel(i, ItemViewModelType.Main)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).CombineLatest(
|
|
||||||
Ordering,
|
|
||||||
(items, ordering) =>
|
|
||||||
{
|
|
||||||
if (items is null) return Task.FromResult<ObservableCollection<IItemViewModel>?>(null);
|
|
||||||
|
|
||||||
ObservableCollection<IItemViewModel>? orderedItems = ordering switch
|
|
||||||
{
|
|
||||||
ItemOrdering.Name =>
|
|
||||||
items
|
|
||||||
.Ordering(i => i.BaseItem!.Type)
|
|
||||||
.ThenOrdering(i => i.DisplayNameText),
|
|
||||||
ItemOrdering.NameDesc =>
|
|
||||||
items
|
|
||||||
.Ordering(i => i.BaseItem!.Type)
|
|
||||||
.ThenOrdering(i => i.DisplayNameText, ListSortDirection.Descending),
|
|
||||||
ItemOrdering.CreationDate =>
|
|
||||||
items
|
|
||||||
.Ordering(i => i.CreatedAt),
|
|
||||||
ItemOrdering.CreationDateDesc =>
|
|
||||||
items
|
|
||||||
.Ordering(i => i.CreatedAt, ListSortDirection.Descending),
|
|
||||||
ItemOrdering.LastModifyDate =>
|
|
||||||
items
|
|
||||||
.Ordering(i => i.ModifiedAt),
|
|
||||||
ItemOrdering.LastModifyDateDesc =>
|
|
||||||
items
|
|
||||||
.Ordering(i => i.ModifiedAt, ListSortDirection.Descending),
|
|
||||||
_ => throw new NotImplementedException()
|
|
||||||
};
|
|
||||||
|
|
||||||
return Task.FromResult(orderedItems);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
using var _ = Defer(
|
using var _ = Defer(
|
||||||
@@ -135,6 +100,12 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CurrentSelectedItem.Subscribe((v) =>
|
||||||
|
{
|
||||||
|
_refreshSmoothnessCalculator.RegisterChange();
|
||||||
|
_refreshSmoothnessCalculator.RecalculateSmoothness();
|
||||||
|
});
|
||||||
|
|
||||||
CurrentSelectedItemAsContainer = CurrentSelectedItem.Map(i => i as IContainerViewModel);
|
CurrentSelectedItemAsContainer = CurrentSelectedItem.Map(i => i as IContainerViewModel);
|
||||||
|
|
||||||
SelectedsChildren = CurrentSelectedItem
|
SelectedsChildren = CurrentSelectedItem
|
||||||
|
|||||||
@@ -62,16 +62,16 @@ public class Timeline
|
|||||||
{
|
{
|
||||||
ForegroundColor = _progressBarTheme?.ForegroundColor,
|
ForegroundColor = _progressBarTheme?.ForegroundColor,
|
||||||
UnfilledForeground = _progressBarTheme?.UnfilledForeground,
|
UnfilledForeground = _progressBarTheme?.UnfilledForeground,
|
||||||
FilledCharacter = '\u2594',
|
FilledCharacter = new('\u2594', '█'),
|
||||||
UnfilledCharacter = '\u2594',
|
UnfilledCharacter = new('\u2594', '█'),
|
||||||
Fraction1Per8Character = '\u2594',
|
Fraction1Per8Character = new('\u2594', ' '),
|
||||||
Fraction2Per8Character = '\u2594',
|
Fraction2Per8Character = new('\u2594', ' '),
|
||||||
Fraction3Per8Character = '\u2594',
|
Fraction3Per8Character = new('\u2594', ' '),
|
||||||
Fraction4Per8Character = '\u2594',
|
Fraction4Per8Character = new('\u2594', ' '),
|
||||||
Fraction5Per8Character = '\u2594',
|
Fraction5Per8Character = new('\u2594', '█'),
|
||||||
Fraction6Per8Character = '\u2594',
|
Fraction6Per8Character = new('\u2594', '█'),
|
||||||
Fraction7Per8Character = '\u2594',
|
Fraction7Per8Character = new('\u2594', '█'),
|
||||||
FractionFull = '\u2594',
|
FractionFull = new('\u2594', '█'),
|
||||||
},
|
},
|
||||||
Extensions =
|
Extensions =
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
using FileTime.App.Core.Models.Enums;
|
using System.Globalization;
|
||||||
|
using FileTime.App.Core.Models.Enums;
|
||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.ConsoleUI.App.Controls;
|
using FileTime.ConsoleUI.App.Controls;
|
||||||
using FileTime.ConsoleUI.App.Styling;
|
using FileTime.ConsoleUI.App.Styling;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using Humanizer.Bytes;
|
||||||
using TerminalUI;
|
using TerminalUI;
|
||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
using TerminalUI.Controls;
|
using TerminalUI.Controls;
|
||||||
@@ -14,6 +17,16 @@ namespace FileTime.ConsoleUI.App;
|
|||||||
|
|
||||||
public class MainWindow
|
public class MainWindow
|
||||||
{
|
{
|
||||||
|
private readonly struct ItemViewRenderOptions
|
||||||
|
{
|
||||||
|
public readonly bool ShowAttributes;
|
||||||
|
|
||||||
|
public ItemViewRenderOptions(bool showAttributes = false)
|
||||||
|
{
|
||||||
|
ShowAttributes = showAttributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private readonly IRootViewModel _rootViewModel;
|
private readonly IRootViewModel _rootViewModel;
|
||||||
private readonly IApplicationContext _applicationContext;
|
private readonly IApplicationContext _applicationContext;
|
||||||
private readonly ITheme _theme;
|
private readonly ITheme _theme;
|
||||||
@@ -251,30 +264,11 @@ public class MainWindow
|
|||||||
{
|
{
|
||||||
var list = new ListView<IRootViewModel, IItemViewModel>
|
var list = new ListView<IRootViewModel, IItemViewModel>
|
||||||
{
|
{
|
||||||
ListPadding = 8
|
ListPadding = 8,
|
||||||
|
Margin = "1 0 1 0"
|
||||||
};
|
};
|
||||||
|
|
||||||
list.ItemTemplate = item =>
|
list.ItemTemplate = item => ItemItemTemplate(item, new ItemViewRenderOptions(true));
|
||||||
{
|
|
||||||
var textBlock = item.CreateChild<TextBlock<IItemViewModel>>();
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? string.Empty : dc.DisplayNameText,
|
|
||||||
tb => tb.Text
|
|
||||||
);
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? _theme.DefaultForegroundColor : ToForegroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
|
||||||
tb => tb.Foreground
|
|
||||||
);
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? _theme.DefaultBackgroundColor : ToBackgroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
|
||||||
tb => tb.Background
|
|
||||||
);
|
|
||||||
|
|
||||||
return textBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
list.Bind(
|
list.Bind(
|
||||||
list,
|
list,
|
||||||
@@ -296,27 +290,7 @@ public class MainWindow
|
|||||||
ListPadding = 8
|
ListPadding = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
list.ItemTemplate = item =>
|
list.ItemTemplate = item => ItemItemTemplate(item, new ItemViewRenderOptions());
|
||||||
{
|
|
||||||
var textBlock = item.CreateChild<TextBlock<IItemViewModel>>();
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? string.Empty : dc.DisplayNameText,
|
|
||||||
tb => tb.Text
|
|
||||||
);
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? _theme.DefaultForegroundColor : ToForegroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
|
||||||
tb => tb.Foreground
|
|
||||||
);
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? _theme.DefaultBackgroundColor : ToBackgroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
|
||||||
tb => tb.Background
|
|
||||||
);
|
|
||||||
|
|
||||||
return textBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
list.Bind(
|
list.Bind(
|
||||||
list,
|
list,
|
||||||
@@ -333,28 +307,7 @@ public class MainWindow
|
|||||||
ListPadding = 8
|
ListPadding = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
list.ItemTemplate = item =>
|
list.ItemTemplate = item => ItemItemTemplate(item, new ItemViewRenderOptions());
|
||||||
{
|
|
||||||
var textBlock = item.CreateChild<TextBlock<IItemViewModel>>();
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? string.Empty : dc.DisplayNameText,
|
|
||||||
tb => tb.Text
|
|
||||||
);
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? _theme.DefaultForegroundColor : ToForegroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
|
||||||
tb => tb.Foreground,
|
|
||||||
v => v
|
|
||||||
);
|
|
||||||
textBlock.Bind(
|
|
||||||
textBlock,
|
|
||||||
dc => dc == null ? _theme.DefaultBackgroundColor : ToBackgroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
|
||||||
tb => tb.Background
|
|
||||||
);
|
|
||||||
|
|
||||||
return textBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
list.Bind(
|
list.Bind(
|
||||||
list,
|
list,
|
||||||
@@ -364,6 +317,98 @@ public class MainWindow
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IView<IItemViewModel> ItemItemTemplate(
|
||||||
|
ListViewItem<IItemViewModel, IRootViewModel> item,
|
||||||
|
ItemViewRenderOptions options
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var root = new Grid<IItemViewModel>
|
||||||
|
{
|
||||||
|
ChildInitializer =
|
||||||
|
{
|
||||||
|
new Rectangle<IItemViewModel>(),
|
||||||
|
new Grid<IItemViewModel>
|
||||||
|
{
|
||||||
|
Margin = "1 0 1 0",
|
||||||
|
ColumnDefinitionsObject = "* Auto",
|
||||||
|
ChildInitializer =
|
||||||
|
{
|
||||||
|
new TextBlock<IItemViewModel>()
|
||||||
|
.Setup(t =>
|
||||||
|
{
|
||||||
|
t.Bind(
|
||||||
|
t,
|
||||||
|
dc => dc == null ? string.Empty : dc.DisplayNameText,
|
||||||
|
tb => tb.Text
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
new StackPanel<IItemViewModel>
|
||||||
|
{
|
||||||
|
Extensions = {new GridPositionExtension(1, 0)},
|
||||||
|
ChildInitializer =
|
||||||
|
{
|
||||||
|
new TextBlock<IItemViewModel>()
|
||||||
|
.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<IItemViewModel>
|
||||||
|
{
|
||||||
|
Extensions = {new GridPositionExtension(1, 0)},
|
||||||
|
ChildInitializer =
|
||||||
|
{
|
||||||
|
new TextBlock<IItemViewModel>()
|
||||||
|
.Setup(t =>
|
||||||
|
{
|
||||||
|
if (!options.ShowAttributes) return;
|
||||||
|
t.Bind(
|
||||||
|
t,
|
||||||
|
dc => ((IElementViewModel) dc).Size.Value,
|
||||||
|
tb => tb.Text,
|
||||||
|
v =>
|
||||||
|
{
|
||||||
|
var b = ByteSize.FromBytes(v);
|
||||||
|
|
||||||
|
return $"{b.LargestWholeNumberValue:0.#} " + b.GetLargestWholeNumberSymbol(NumberFormatInfo.CurrentInfo).First();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.Setup(s => s.Bind(
|
||||||
|
s,
|
||||||
|
dc => dc.BaseItem.Type == AbsolutePathType.Element,
|
||||||
|
s => s.IsVisible))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
root.Bind(
|
||||||
|
root,
|
||||||
|
dc => dc == null ? _theme.DefaultForegroundColor : ToForegroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
||||||
|
tb => tb.Foreground
|
||||||
|
);
|
||||||
|
|
||||||
|
root.Bind(
|
||||||
|
root,
|
||||||
|
dc => dc == null ? _theme.DefaultBackgroundColor : ToBackgroundColor(dc.ViewMode.Value, dc.BaseItem.Type),
|
||||||
|
tb => tb.Background
|
||||||
|
);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
private IColor? ToForegroundColor(ItemViewMode viewMode, AbsolutePathType absolutePathType) =>
|
private IColor? ToForegroundColor(ItemViewMode viewMode, AbsolutePathType absolutePathType) =>
|
||||||
(viewMode, absolutePathType) switch
|
(viewMode, absolutePathType) switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using DeclarativeProperty;
|
using DeclarativeProperty;
|
||||||
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
@@ -7,10 +8,11 @@ namespace FileTime.Core.Services;
|
|||||||
|
|
||||||
public interface ITab : IAsyncInitable<IContainer>, IDisposable
|
public interface ITab : IAsyncInitable<IContainer>, IDisposable
|
||||||
{
|
{
|
||||||
public IDeclarativeProperty<IContainer?> CurrentLocation { get; }
|
IDeclarativeProperty<IContainer?> CurrentLocation { get; }
|
||||||
public IDeclarativeProperty<ObservableCollection<IItem>?> CurrentItems { get; }
|
IDeclarativeProperty<ObservableCollection<IItem>?> CurrentItems { get; }
|
||||||
public IDeclarativeProperty<AbsolutePath?> CurrentSelectedItem { get; }
|
IDeclarativeProperty<AbsolutePath?> CurrentSelectedItem { get; }
|
||||||
FullName? LastDeepestSelectedPath { get; }
|
FullName? LastDeepestSelectedPath { get; }
|
||||||
|
DeclarativeProperty<ItemOrdering?> Ordering { get; }
|
||||||
|
|
||||||
Task SetCurrentLocation(IContainer newLocation);
|
Task SetCurrentLocation(IContainer newLocation);
|
||||||
void AddItemFilter(ItemFilter filter);
|
void AddItemFilter(ItemFilter filter);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
using System.Reactive.Linq;
|
|
||||||
using System.Reactive.Subjects;
|
|
||||||
using ByteSizeLib;
|
|
||||||
using DeclarativeProperty;
|
using DeclarativeProperty;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
|
using Humanizer.Bytes;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.Core.Command.Copy;
|
namespace FileTime.Core.Command.Copy;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ByteSize" Version="2.1.1" />
|
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
|
||||||
<ProjectReference Include="..\..\Library\CircularBuffer\CircularBuffer.csproj" />
|
<ProjectReference Include="..\..\Library\CircularBuffer\CircularBuffer.csproj" />
|
||||||
<ProjectReference Include="..\..\Library\Defer\Defer.csproj" />
|
<ProjectReference Include="..\..\Library\Defer\Defer.csproj" />
|
||||||
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
|
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
using CircularBuffer;
|
using CircularBuffer;
|
||||||
using DeclarativeProperty;
|
using DeclarativeProperty;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.Core.Helper;
|
using FileTime.Core.Helper;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
using ObservableComputations;
|
using ObservableComputations;
|
||||||
|
using IContainer = FileTime.Core.Models.IContainer;
|
||||||
|
|
||||||
namespace FileTime.Core.Services;
|
namespace FileTime.Core.Services;
|
||||||
|
|
||||||
@@ -14,9 +16,9 @@ public class Tab : ITab
|
|||||||
{
|
{
|
||||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
private readonly ITabEvents _tabEvents;
|
private readonly ITabEvents _tabEvents;
|
||||||
private readonly DeclarativeProperty<IContainer?> _currentLocation = new(null);
|
private readonly DeclarativeProperty<IContainer?> _currentLocation = new();
|
||||||
private readonly DeclarativeProperty<IContainer?> _currentLocationForced = new(null);
|
private readonly DeclarativeProperty<IContainer?> _currentLocationForced = new();
|
||||||
private readonly DeclarativeProperty<AbsolutePath?> _currentRequestItem = new(null);
|
private readonly DeclarativeProperty<AbsolutePath?> _currentRequestItem = new();
|
||||||
private readonly ObservableCollection<ItemFilter> _itemFilters = new();
|
private readonly ObservableCollection<ItemFilter> _itemFilters = new();
|
||||||
private readonly CircularBuffer<FullName> _history = new(20);
|
private readonly CircularBuffer<FullName> _history = new(20);
|
||||||
private readonly CircularBuffer<FullName> _future = new(20);
|
private readonly CircularBuffer<FullName> _future = new(20);
|
||||||
@@ -28,11 +30,11 @@ public class Tab : ITab
|
|||||||
public IDeclarativeProperty<ObservableCollection<IItem>?> CurrentItems { get; }
|
public IDeclarativeProperty<ObservableCollection<IItem>?> CurrentItems { get; }
|
||||||
public IDeclarativeProperty<AbsolutePath?> CurrentSelectedItem { get; }
|
public IDeclarativeProperty<AbsolutePath?> CurrentSelectedItem { get; }
|
||||||
public FullName? LastDeepestSelectedPath { get; private set; }
|
public FullName? LastDeepestSelectedPath { get; private set; }
|
||||||
|
public DeclarativeProperty<ItemOrdering?> Ordering { get; } = new(ItemOrdering.Name);
|
||||||
|
|
||||||
public Tab(
|
public Tab(
|
||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
ITabEvents tabEvents,
|
ITabEvents tabEvents)
|
||||||
IRefreshSmoothnessCalculator refreshSmoothnessCalculator)
|
|
||||||
{
|
{
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_tabEvents = tabEvents;
|
_tabEvents = tabEvents;
|
||||||
@@ -47,7 +49,7 @@ public class Tab : ITab
|
|||||||
_currentLocationForced
|
_currentLocationForced
|
||||||
);
|
);
|
||||||
|
|
||||||
CurrentLocation.Subscribe((c, _) =>
|
CurrentLocation.Subscribe((_, _) =>
|
||||||
{
|
{
|
||||||
if (_currentSelectedItemCached is not null)
|
if (_currentSelectedItemCached is not null)
|
||||||
{
|
{
|
||||||
@@ -78,6 +80,39 @@ public class Tab : ITab
|
|||||||
|
|
||||||
return Task.FromResult(items);
|
return Task.FromResult(items);
|
||||||
}
|
}
|
||||||
|
).CombineLatest(
|
||||||
|
Ordering,
|
||||||
|
(items, ordering) =>
|
||||||
|
{
|
||||||
|
if (items is null) return Task.FromResult<ObservableCollection<IItem>?>(null);
|
||||||
|
|
||||||
|
ObservableCollection<IItem>? orderedItems = ordering switch
|
||||||
|
{
|
||||||
|
ItemOrdering.Name =>
|
||||||
|
items
|
||||||
|
.Ordering(i => i.Type)
|
||||||
|
.ThenOrdering(i => i.DisplayName),
|
||||||
|
ItemOrdering.NameDesc =>
|
||||||
|
items
|
||||||
|
.Ordering(i => i.Type)
|
||||||
|
.ThenOrdering(i => i.DisplayName, ListSortDirection.Descending),
|
||||||
|
ItemOrdering.CreationDate =>
|
||||||
|
items
|
||||||
|
.Ordering(i => i.CreatedAt),
|
||||||
|
ItemOrdering.CreationDateDesc =>
|
||||||
|
items
|
||||||
|
.Ordering(i => i.CreatedAt, ListSortDirection.Descending),
|
||||||
|
ItemOrdering.LastModifyDate =>
|
||||||
|
items
|
||||||
|
.Ordering(i => i.ModifiedAt),
|
||||||
|
ItemOrdering.LastModifyDateDesc =>
|
||||||
|
items
|
||||||
|
.Ordering(i => i.ModifiedAt, ListSortDirection.Descending),
|
||||||
|
_ => throw new NotImplementedException()
|
||||||
|
};
|
||||||
|
|
||||||
|
return Task.FromResult(orderedItems);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@@ -92,12 +127,6 @@ public class Tab : ITab
|
|||||||
return Task.FromResult(GetSelectedItemByItems(items));
|
return Task.FromResult(GetSelectedItemByItems(items));
|
||||||
}).DistinctUntilChanged();
|
}).DistinctUntilChanged();
|
||||||
|
|
||||||
CurrentSelectedItem.Subscribe((v) =>
|
|
||||||
{
|
|
||||||
refreshSmoothnessCalculator.RegisterChange();
|
|
||||||
refreshSmoothnessCalculator.RecalculateSmoothness();
|
|
||||||
});
|
|
||||||
|
|
||||||
CurrentSelectedItem.Subscribe(async (s, _) =>
|
CurrentSelectedItem.Subscribe(async (s, _) =>
|
||||||
{
|
{
|
||||||
_currentSelectedItemCached = s;
|
_currentSelectedItemCached = s;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Avalonia.Data.Converters;
|
using Avalonia.Data.Converters;
|
||||||
using ByteSizeLib;
|
using Humanizer.Bytes;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.App.Converters;
|
namespace FileTime.GuiApp.App.Converters;
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public static class DeclarativePropertyExtensions
|
|||||||
public static IDeclarativeProperty<TResult?> CombineLatest<T1, T2, TResult>(
|
public static IDeclarativeProperty<TResult?> CombineLatest<T1, T2, TResult>(
|
||||||
this IDeclarativeProperty<T1> prop1,
|
this IDeclarativeProperty<T1> prop1,
|
||||||
IDeclarativeProperty<T2> prop2,
|
IDeclarativeProperty<T2> prop2,
|
||||||
Func<T1, T2, Task<TResult>> func,
|
Func<T1, T2, Task<TResult?>> func,
|
||||||
Action<TResult?>? setValueHook = null)
|
Action<TResult?>? setValueHook = null)
|
||||||
=> new CombineLatestProperty<T1,T2,TResult?>(prop1, prop2, func, setValueHook);
|
=> new CombineLatestProperty<T1,T2,TResult?>(prop1, prop2, func, setValueHook);
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ public static class DeclarativePropertyExtensions
|
|||||||
|
|
||||||
public static IDeclarativeProperty<TResult?> CombineAll<T, TResult>(
|
public static IDeclarativeProperty<TResult?> CombineAll<T, TResult>(
|
||||||
this IEnumerable<IDeclarativeProperty<T>> sources,
|
this IEnumerable<IDeclarativeProperty<T>> sources,
|
||||||
Func<IEnumerable<T>, Task<TResult>> combiner,
|
Func<IEnumerable<T>, Task<TResult?>> combiner,
|
||||||
Action<TResult?>? setValueHook = null)
|
Action<TResult?>? setValueHook = null)
|
||||||
=> new CombineAllProperty<T,TResult?>(sources, combiner, setValueHook);
|
=> new CombineAllProperty<T,TResult?>(sources, combiner, setValueHook);
|
||||||
}
|
}
|
||||||
14
src/Library/TerminalUI/Color/SpecialColors.cs
Normal file
14
src/Library/TerminalUI/Color/SpecialColors.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
namespace TerminalUI.Color;
|
||||||
|
|
||||||
|
public class SpecialColor : IColor
|
||||||
|
{
|
||||||
|
private SpecialColor(){}
|
||||||
|
public ColorType Type => ColorType.Unknown;
|
||||||
|
public string ToConsoleColor() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public IColor AsForeground() => this;
|
||||||
|
|
||||||
|
public IColor AsBackground() => this;
|
||||||
|
|
||||||
|
public static SpecialColor None { get; } = new();
|
||||||
|
}
|
||||||
@@ -36,12 +36,16 @@ public class DotnetDriver : IConsoleDriver
|
|||||||
|
|
||||||
public virtual void SetForegroundColor(IColor foreground)
|
public virtual void SetForegroundColor(IColor foreground)
|
||||||
{
|
{
|
||||||
|
if (foreground == SpecialColor.None) return;
|
||||||
|
|
||||||
if (foreground is not ConsoleColor consoleColor) throw new NotSupportedException();
|
if (foreground is not ConsoleColor consoleColor) throw new NotSupportedException();
|
||||||
Console.ForegroundColor = consoleColor.Color;
|
Console.ForegroundColor = consoleColor.Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetBackgroundColor(IColor background)
|
public virtual void SetBackgroundColor(IColor background)
|
||||||
{
|
{
|
||||||
|
if (background == SpecialColor.None) return;
|
||||||
|
|
||||||
if (background is not ConsoleColor consoleColor) throw new NotSupportedException();
|
if (background is not ConsoleColor consoleColor) throw new NotSupportedException();
|
||||||
Console.BackgroundColor = consoleColor.Color;
|
Console.BackgroundColor = consoleColor.Color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ public sealed class XTermDriver : DotnetDriver
|
|||||||
|
|
||||||
public override void SetBackgroundColor(IColor background)
|
public override void SetBackgroundColor(IColor background)
|
||||||
{
|
{
|
||||||
|
if (background == SpecialColor.None) return;
|
||||||
|
|
||||||
if (background is ConsoleColor consoleColor)
|
if (background is ConsoleColor consoleColor)
|
||||||
{
|
{
|
||||||
Console.BackgroundColor = consoleColor.Color;
|
Console.BackgroundColor = consoleColor.Color;
|
||||||
@@ -41,6 +43,8 @@ public sealed class XTermDriver : DotnetDriver
|
|||||||
|
|
||||||
public override void SetForegroundColor(IColor foreground)
|
public override void SetForegroundColor(IColor foreground)
|
||||||
{
|
{
|
||||||
|
if (foreground == SpecialColor.None) return;
|
||||||
|
|
||||||
if (foreground is ConsoleColor consoleColor)
|
if (foreground is ConsoleColor consoleColor)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = consoleColor.Color;
|
Console.ForegroundColor = consoleColor.Color;
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
int Minimum,
|
int Minimum,
|
||||||
int Maximum,
|
int Maximum,
|
||||||
int Value,
|
int Value,
|
||||||
char? LeftCap,
|
SelectiveChar? LeftCap,
|
||||||
char? RightCap,
|
SelectiveChar? RightCap,
|
||||||
char? Fill,
|
SelectiveChar? Fill,
|
||||||
char? Unfilled,
|
SelectiveChar? Unfilled,
|
||||||
IColor? UnfilledForeground,
|
IColor? UnfilledForeground,
|
||||||
IColor? UnfilledBackground);
|
IColor? UnfilledBackground);
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
var background = Background ?? (_theme ?? theme)?.BackgroundColor ?? renderContext.Background;
|
var background = Background ?? (_theme ?? theme)?.BackgroundColor ?? renderContext.Background;
|
||||||
var unfilledForeground = (_theme ?? theme)?.UnfilledForeground ?? renderContext.Foreground;
|
var unfilledForeground = (_theme ?? theme)?.UnfilledForeground ?? renderContext.Foreground;
|
||||||
var unfilledBackground = (_theme ?? theme)?.UnfilledBackground ?? renderContext.Background;
|
var unfilledBackground = (_theme ?? theme)?.UnfilledBackground ?? renderContext.Background;
|
||||||
var unfilledCharacter = (_theme ?? theme)?.UnfilledCharacter ?? ApplicationContext?.EmptyCharacter ?? ' ';
|
var unfilledCharacterS = (_theme ?? theme)?.UnfilledCharacter ?? new SelectiveChar(ApplicationContext?.EmptyCharacter ?? ' ');
|
||||||
var fillCharacter = (_theme ?? theme)?.FilledCharacter ?? '█';
|
var fillCharacterS = (_theme ?? theme)?.FilledCharacter ?? new SelectiveChar('█');
|
||||||
var leftCap = (_theme ?? theme)?.LeftCap;
|
var leftCapS = (_theme ?? theme)?.LeftCap;
|
||||||
var rightCap = (_theme ?? theme)?.RightCap;
|
var rightCapS = (_theme ?? theme)?.RightCap;
|
||||||
|
|
||||||
var renderState = new RenderState(
|
var renderState = new RenderState(
|
||||||
position,
|
position,
|
||||||
@@ -60,15 +60,21 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
Minimum,
|
Minimum,
|
||||||
Maximum,
|
Maximum,
|
||||||
Value,
|
Value,
|
||||||
leftCap,
|
leftCapS,
|
||||||
rightCap,
|
rightCapS,
|
||||||
fillCharacter,
|
fillCharacterS,
|
||||||
unfilledCharacter,
|
unfilledCharacterS,
|
||||||
unfilledForeground,
|
unfilledForeground,
|
||||||
unfilledBackground);
|
unfilledBackground);
|
||||||
|
|
||||||
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
|
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
|
||||||
|
|
||||||
|
var utf8Support = ApplicationContext!.SupportUtf8Output;
|
||||||
|
var unfilledCharacter = unfilledCharacterS.GetChar(utf8Support);
|
||||||
|
var fillCharacter = fillCharacterS.GetChar(utf8Support);
|
||||||
|
var leftCap = leftCapS?.GetChar(utf8Support);
|
||||||
|
var rightCap = rightCapS?.GetChar(utf8Support);
|
||||||
|
|
||||||
_lastRenderState = renderState;
|
_lastRenderState = renderState;
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
|
|
||||||
@@ -90,17 +96,18 @@ public partial class ProgressBar<T> : View<ProgressBar<T>, T>
|
|||||||
if (ApplicationContext!.SupportUtf8Output)
|
if (ApplicationContext!.SupportUtf8Output)
|
||||||
{
|
{
|
||||||
var remained = progressWidth - progressQuotientWidth;
|
var remained = progressWidth - progressQuotientWidth;
|
||||||
|
var t = _theme ?? theme;
|
||||||
transientChar = remained switch
|
transientChar = remained switch
|
||||||
{
|
{
|
||||||
< 0.125 => unfilledCharacter,
|
< 0.125 => unfilledCharacter,
|
||||||
< 0.250 => (_theme ?? theme)?.Fraction1Per8Character ?? '\u258F',
|
< 0.250 => (t?.Fraction1Per8Character ?? new SelectiveChar('\u258F', ' ')).GetChar(utf8Support),
|
||||||
< 0.375 => (_theme ?? theme)?.Fraction2Per8Character ?? '\u258E',
|
< 0.375 => (t?.Fraction2Per8Character ?? new SelectiveChar('\u258E', ' ')).GetChar(utf8Support),
|
||||||
< 0.500 => (_theme ?? theme)?.Fraction3Per8Character ?? '\u258D',
|
< 0.500 => (t?.Fraction3Per8Character ?? new SelectiveChar('\u258D', ' ')).GetChar(utf8Support),
|
||||||
< 0.675 => (_theme ?? theme)?.Fraction4Per8Character ?? '\u258C',
|
< 0.675 => (t?.Fraction4Per8Character ?? new SelectiveChar('\u258C', ' ')).GetChar(utf8Support),
|
||||||
< 0.750 => (_theme ?? theme)?.Fraction5Per8Character ?? '\u258B',
|
< 0.750 => (t?.Fraction5Per8Character ?? new SelectiveChar('\u258B', ' ')).GetChar(utf8Support),
|
||||||
< 0.875 => (_theme ?? theme)?.Fraction6Per8Character ?? '\u258A',
|
< 0.875 => (t?.Fraction6Per8Character ?? new SelectiveChar('\u258A', ' ')).GetChar(utf8Support),
|
||||||
< 0_001 => (_theme ?? theme)?.Fraction7Per8Character ?? '\u2589',
|
< 0_001 => (t?.Fraction7Per8Character ?? new SelectiveChar('\u2589', ' ')).GetChar(utf8Support),
|
||||||
_ => (_theme ?? theme)?.FractionFull ?? '\u2588',
|
_ => (t?.FractionFull ?? new SelectiveChar('\u2588', ' ')).GetChar(utf8Support),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,24 +10,26 @@ public sealed partial class Rectangle<T> : View<Rectangle<T>, T>, IDisplayView
|
|||||||
private record RenderState(
|
private record RenderState(
|
||||||
Position Position,
|
Position Position,
|
||||||
Size Size,
|
Size Size,
|
||||||
IColor? Fill);
|
IColor? Color);
|
||||||
|
|
||||||
private RenderState? _lastRenderState;
|
private RenderState? _lastRenderState;
|
||||||
|
|
||||||
[Notify] private IColor? _fill;
|
|
||||||
protected override Size CalculateSize() => new(Width ?? 0, Height ?? 0);
|
protected override Size CalculateSize() => new(Width ?? 0, Height ?? 0);
|
||||||
|
|
||||||
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
protected override bool DefaultRenderer(in RenderContext renderContext, Position position, Size size)
|
||||||
{
|
{
|
||||||
var renderState = new RenderState(position, size, Fill);
|
var color = Background ?? renderContext.Background;
|
||||||
if ((!renderContext.ForceRerender && !NeedsRerender(renderState)) || Fill is null) return false;
|
var renderState = new RenderState(position, size, color);
|
||||||
|
if (!renderContext.ForceRerender && !NeedsRerender(renderState)) return false;
|
||||||
_lastRenderState = renderState;
|
_lastRenderState = renderState;
|
||||||
|
|
||||||
var driver = renderContext.ConsoleDriver;
|
var driver = renderContext.ConsoleDriver;
|
||||||
|
|
||||||
var s = new string('█', size.Width);
|
var s = new string(' ', size.Width);
|
||||||
driver.SetBackgroundColor(Fill);
|
driver.ResetColor();
|
||||||
driver.SetForegroundColor(Fill);
|
if (color is not null)
|
||||||
|
{
|
||||||
|
driver.SetForegroundColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
var height = size.Height;
|
var height = size.Height;
|
||||||
for (var i = 0; i < height; i++)
|
for (var i = 0; i < height; i++)
|
||||||
|
|||||||
21
src/Library/TerminalUI/Models/SelectiveChar.cs
Normal file
21
src/Library/TerminalUI/Models/SelectiveChar.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace TerminalUI.Models;
|
||||||
|
|
||||||
|
public readonly struct SelectiveChar
|
||||||
|
{
|
||||||
|
public readonly char Utf8Char;
|
||||||
|
public readonly char AsciiChar;
|
||||||
|
|
||||||
|
public SelectiveChar(char c)
|
||||||
|
{
|
||||||
|
Utf8Char = c;
|
||||||
|
AsciiChar = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelectiveChar(char utf8Char, char asciiChar)
|
||||||
|
{
|
||||||
|
Utf8Char = utf8Char;
|
||||||
|
AsciiChar = asciiChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char GetChar(bool enableUtf8) => enableUtf8 ? Utf8Char : AsciiChar;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
|
using TerminalUI.Models;
|
||||||
|
|
||||||
namespace TerminalUI.Styling.Controls;
|
namespace TerminalUI.Styling.Controls;
|
||||||
|
|
||||||
@@ -8,16 +9,16 @@ public interface IProgressBarTheme
|
|||||||
IColor? BackgroundColor { get; init; }
|
IColor? BackgroundColor { get; init; }
|
||||||
IColor? UnfilledForeground { get; init; }
|
IColor? UnfilledForeground { get; init; }
|
||||||
IColor? UnfilledBackground { get; init; }
|
IColor? UnfilledBackground { get; init; }
|
||||||
char? FilledCharacter { get; init; }
|
SelectiveChar? FilledCharacter { get; init; }
|
||||||
char? UnfilledCharacter { get; init; }
|
SelectiveChar? UnfilledCharacter { get; init; }
|
||||||
char? Fraction1Per8Character { get; init; }
|
SelectiveChar? Fraction1Per8Character { get; init; }
|
||||||
char? Fraction2Per8Character { get; init; }
|
SelectiveChar? Fraction2Per8Character { get; init; }
|
||||||
char? Fraction3Per8Character { get; init; }
|
SelectiveChar? Fraction3Per8Character { get; init; }
|
||||||
char? Fraction4Per8Character { get; init; }
|
SelectiveChar? Fraction4Per8Character { get; init; }
|
||||||
char? Fraction5Per8Character { get; init; }
|
SelectiveChar? Fraction5Per8Character { get; init; }
|
||||||
char? Fraction6Per8Character { get; init; }
|
SelectiveChar? Fraction6Per8Character { get; init; }
|
||||||
char? Fraction7Per8Character { get; init; }
|
SelectiveChar? Fraction7Per8Character { get; init; }
|
||||||
char? FractionFull { get; init; }
|
SelectiveChar? FractionFull { get; init; }
|
||||||
char? LeftCap { get; init; }
|
SelectiveChar? LeftCap { get; init; }
|
||||||
char? RightCap { get; init; }
|
SelectiveChar? RightCap { get; init; }
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using TerminalUI.Color;
|
using TerminalUI.Color;
|
||||||
|
using TerminalUI.Models;
|
||||||
|
|
||||||
namespace TerminalUI.Styling.Controls;
|
namespace TerminalUI.Styling.Controls;
|
||||||
|
|
||||||
@@ -28,16 +29,16 @@ public class ProgressBarTheme : IProgressBarTheme
|
|||||||
public IColor? BackgroundColor { get; init; }
|
public IColor? BackgroundColor { get; init; }
|
||||||
public IColor? UnfilledForeground { get; init; }
|
public IColor? UnfilledForeground { get; init; }
|
||||||
public IColor? UnfilledBackground { get; init; }
|
public IColor? UnfilledBackground { get; init; }
|
||||||
public char? FilledCharacter { get; init; }
|
public SelectiveChar? FilledCharacter { get; init; }
|
||||||
public char? UnfilledCharacter { get; init; }
|
public SelectiveChar? UnfilledCharacter { get; init; }
|
||||||
public char? Fraction1Per8Character { get; init; }
|
public SelectiveChar? Fraction1Per8Character { get; init; }
|
||||||
public char? Fraction2Per8Character { get; init; }
|
public SelectiveChar? Fraction2Per8Character { get; init; }
|
||||||
public char? Fraction3Per8Character { get; init; }
|
public SelectiveChar? Fraction3Per8Character { get; init; }
|
||||||
public char? Fraction4Per8Character { get; init; }
|
public SelectiveChar? Fraction4Per8Character { get; init; }
|
||||||
public char? Fraction5Per8Character { get; init; }
|
public SelectiveChar? Fraction5Per8Character { get; init; }
|
||||||
public char? Fraction6Per8Character { get; init; }
|
public SelectiveChar? Fraction6Per8Character { get; init; }
|
||||||
public char? Fraction7Per8Character { get; init; }
|
public SelectiveChar? Fraction7Per8Character { get; init; }
|
||||||
public char? FractionFull { get; init; }
|
public SelectiveChar? FractionFull { get; init; }
|
||||||
public char? LeftCap { get; init; }
|
public SelectiveChar? LeftCap { get; init; }
|
||||||
public char? RightCap { get; init; }
|
public SelectiveChar? RightCap { get; init; }
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user