UI improvements

This commit is contained in:
2022-01-24 00:08:22 +01:00
parent 031d07613b
commit aacbaa3a02
33 changed files with 729 additions and 152 deletions

View File

@@ -23,5 +23,7 @@ namespace FileTime.App.Core.Command
GoToRoot, GoToRoot,
GoToProvider, GoToProvider,
GoToHome, GoToHome,
EnterRapidTravel,
OpenOrRun,
} }
} }

View File

@@ -1,5 +1,6 @@
using FileTime.ConsoleUI.App.UI.Color; using FileTime.ConsoleUI.App.UI.Color;
using FileTime.Core.Command; using FileTime.Core.Command;
using FileTime.Core.Extensions;
using FileTime.Core.Models; using FileTime.Core.Models;
namespace FileTime.ConsoleUI.App namespace FileTime.ConsoleUI.App
@@ -38,7 +39,7 @@ namespace FileTime.ConsoleUI.App
var currentLocation = await _selectedTab!.GetCurrentLocation(); var currentLocation = await _selectedTab!.GetCurrentLocation();
IContainer containerToOpen = currentLocation; /*IContainer containerToOpen = currentLocation;
if (currentLocation is VirtualContainer oldVirtualContainer) if (currentLocation is VirtualContainer oldVirtualContainer)
{ {
@@ -49,13 +50,15 @@ namespace FileTime.ConsoleUI.App
else else
{ {
containerToOpen = GenerateHiddenFilterVirtualContainer(currentLocation); containerToOpen = GenerateHiddenFilterVirtualContainer(currentLocation);
} } */
var containerToOpen = await currentLocation.ToggleVirtualContainerInChain(hiddenFilterName, GenerateHiddenFilterVirtualContainer);
await _selectedTab.OpenContainer(containerToOpen); await _selectedTab.OpenContainer(containerToOpen);
static VirtualContainer GenerateHiddenFilterVirtualContainer(IContainer container) static async Task<VirtualContainer> GenerateHiddenFilterVirtualContainer(IContainer container)
{ {
return new VirtualContainer( var newContainer = new VirtualContainer(
container, container,
new List<Func<IEnumerable<IContainer>, IEnumerable<IContainer>>>() new List<Func<IEnumerable<IContainer>, IEnumerable<IContainer>>>()
{ {
@@ -69,6 +72,10 @@ namespace FileTime.ConsoleUI.App
true, true,
hiddenFilterName hiddenFilterName
); );
await newContainer.Init();
return newContainer;
} }
} }

View File

@@ -43,7 +43,7 @@ namespace FileTime.ConsoleUI.App.UI
if (paneState == null) throw new Exception($"{nameof(paneState)} can not be null"); if (paneState == null) throw new Exception($"{nameof(paneState)} can not be null");
Tab = pane; Tab = pane;
Tab.CurrentLocationChanged += (o, e) => _currentDisplayStartY = 0; Tab.CurrentLocationChanged.Add((_, _) => { _currentDisplayStartY = 0; return Task.CompletedTask; });
TabState = paneState; TabState = paneState;
} }

View File

@@ -8,38 +8,6 @@ namespace FileTime.Core.Components
private IItem? _currentSelectedItem; private IItem? _currentSelectedItem;
private IContainer _currentLocation; private IContainer _currentLocation;
/* public IContainer CurrentLocation
{
get => _currentLocation;
private set
{
if (_currentLocation != value)
{
if (_currentLocation != null)
{
_currentLocation.Refreshed -= HandleCurrentLocationRefresh;
}
_currentLocation = value;
CurrentLocationChanged?.Invoke(this, EventArgs.Empty);
CurrentSelectedItem = CurrentLocation.Items.Count > 0 ? CurrentLocation.Items[0] : null;
_currentLocation.Refreshed += HandleCurrentLocationRefresh;
}
}
}
public IItem? CurrentSelectedItem
{
get => _currentSelectedItem;
set
{
if (_currentSelectedItem != value && (_currentLocation.Items.Contains(value) || value == null))
{
_currentSelectedItem = value;
CurrentSelectedIndex = GetItemIndex(value);
CurrentSelectedItemChanged?.Invoke(this, EventArgs.Empty);
}
}
} */
public int CurrentSelectedIndex { get; private set; } public int CurrentSelectedIndex { get; private set; }
public AsyncEventHandler CurrentLocationChanged = new(); public AsyncEventHandler CurrentLocationChanged = new();

View File

@@ -0,0 +1,25 @@
using FileTime.Core.Models;
namespace FileTime.Core.Extensions
{
public static class ContainerExtensions
{
public static async Task<IContainer> ToggleVirtualContainerInChain(this IContainer container, string filterName, Func<IContainer, Task<VirtualContainer>> generator)
{
if (container is VirtualContainer oldVirtualContainer)
{
return oldVirtualContainer.HasWithName(filterName)
? await oldVirtualContainer.ExceptWithName(filterName)
: await generator(container);
}
else
{
return await generator(container);
}
}
public static async Task<IContainer> WithoutVirtualContainer(this IContainer container, string filterName) =>
container is VirtualContainer oldVirtualContainer
? await oldVirtualContainer.ExceptWithName(filterName)
: container;
}
}

View File

@@ -16,6 +16,8 @@ namespace FileTime.Core.Models
Task<bool> IsExists(string name); Task<bool> IsExists(string name);
Task<IContainer> Clone();
AsyncEventHandler Refreshed { get; } AsyncEventHandler Refreshed { get; }
} }
} }

View File

@@ -90,17 +90,20 @@ namespace FileTime.Core.Models
|| (BaseContainer is VirtualContainer virtualContainer || (BaseContainer is VirtualContainer virtualContainer
&& virtualContainer.HasWithName(name)); && virtualContainer.HasWithName(name));
public IContainer ExceptWithName(string name) public async Task<IContainer> ExceptWithName(string name)
{ {
if (BaseContainer is VirtualContainer virtualBaseContainer && virtualBaseContainer.VirtualContainerName == name) if (BaseContainer is VirtualContainer virtualBaseContainer && virtualBaseContainer.VirtualContainerName == name)
{ {
return new VirtualContainer( var newContainer = new VirtualContainer(
virtualBaseContainer.ExceptWithName(name), await virtualBaseContainer.ExceptWithName(name),
_containerTransformators, _containerTransformators,
_elementTransformators, _elementTransformators,
IsPermanent, IsPermanent,
IsTransitive, IsTransitive,
VirtualContainerName); VirtualContainerName);
await newContainer.Init();
return newContainer;
} }
else if (VirtualContainerName == name) else if (VirtualContainerName == name)
{ {
@@ -145,5 +148,16 @@ namespace FileTime.Core.Models
} }
public async Task Delete() => await BaseContainer.Delete(); public async Task Delete() => await BaseContainer.Delete();
public async Task<IContainer> Clone()
{
return new VirtualContainer(
await BaseContainer.Clone(),
_containerTransformators,
_elementTransformators,
IsPermanent,
IsTransitive,
VirtualContainerName
);
}
} }
} }

View File

@@ -50,5 +50,7 @@ namespace FileTime.Core.Providers
public Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default) => Task.FromResult(_items); public Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default) => Task.FromResult(_items);
public Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default) => Task.FromResult(_containers); public Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default) => Task.FromResult(_containers);
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements); public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements);
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
} }
} }

View File

@@ -32,6 +32,7 @@ namespace FileTime.Uno
ServiceProvider ??= DependencyInjection ServiceProvider ??= DependencyInjection
.RegisterDefaultServices() .RegisterDefaultServices()
.AddViewModels() .AddViewModels()
.AddServices()
.BuildServiceProvider(); .BuildServiceProvider();
#if HAS_UNO || NETFX_CORE #if HAS_UNO || NETFX_CORE

View File

@@ -15,6 +15,13 @@ namespace FileTime.Uno.Application
[Property] [Property]
private TabContainer _selectedTab; private TabContainer _selectedTab;
[Property]
private ViewMode _viewMode;
[Property]
private string _rapidTravelText = "";
private void TabsChanged() private void TabsChanged()
{ {
SelectedTab ??= Tabs[0]; SelectedTab ??= Tabs[0];

View File

@@ -2,6 +2,7 @@
using FileTime.Core.Components; using FileTime.Core.Components;
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Providers.Local; using FileTime.Providers.Local;
using FileTime.Uno.Services;
using FileTime.Uno.ViewModels; using FileTime.Uno.ViewModels;
using MvvmGen; using MvvmGen;
using System; using System;
@@ -14,6 +15,7 @@ using System.Threading.Tasks;
namespace FileTime.Uno.Application namespace FileTime.Uno.Application
{ {
[ViewModel] [ViewModel]
[Inject(typeof(ItemNameConverterService))]
[Inject(typeof(LocalContentProvider))] [Inject(typeof(LocalContentProvider))]
[Inject(typeof(Tab))] [Inject(typeof(Tab))]
public partial class TabContainer public partial class TabContainer
@@ -27,22 +29,36 @@ namespace FileTime.Uno.Application
[Property] [Property]
private ContainerViewModel _childContainer; private ContainerViewModel _childContainer;
[Property] //[Property]
[PropertyCallMethod(nameof(SelectedItemChanged))] //[PropertyCallMethod(nameof(SelectedItemChanged))]
private IItemViewModel _selectedItem; private IItemViewModel _selectedItem;
public IItemViewModel SelectedItem
{
get => _selectedItem;
set
{
if (_selectedItem != value && value != null)
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
SelectedItemChanged();
}
}
}
public async Task Init() public async Task Init()
{ {
Tab.CurrentLocationChanged.Add(Tab_CurrentLocationChanged); Tab.CurrentLocationChanged.Add(Tab_CurrentLocationChanged);
Tab.CurrentSelectedItemChanged.Add(Tab_CurrentSelectedItemChanged); Tab.CurrentSelectedItemChanged.Add(Tab_CurrentSelectedItemChanged);
CurrentLocation = new ContainerViewModel(await Tab.GetCurrentLocation()); CurrentLocation = new ContainerViewModel(await Tab.GetCurrentLocation(), ItemNameConverterService);
await CurrentLocation.Init(); await CurrentLocation.Init();
var parent = (await Tab.GetCurrentLocation()).GetParent(); var parent = (await Tab.GetCurrentLocation()).GetParent();
if (parent != null) if (parent != null)
{ {
Parent = new ContainerViewModel(parent); Parent = new ContainerViewModel(parent, ItemNameConverterService);
await Parent.Init(); await Parent.Init();
} }
else else
@@ -56,13 +72,13 @@ namespace FileTime.Uno.Application
private async Task Tab_CurrentLocationChanged(object sender, AsyncEventArgs e) private async Task Tab_CurrentLocationChanged(object sender, AsyncEventArgs e)
{ {
var currentLocation = await Tab.GetCurrentLocation(); var currentLocation = await Tab.GetCurrentLocation();
CurrentLocation = new ContainerViewModel(currentLocation); CurrentLocation = new ContainerViewModel(currentLocation, ItemNameConverterService);
await CurrentLocation.Init(); await CurrentLocation.Init();
var parent = currentLocation.GetParent(); var parent = currentLocation.GetParent();
if (parent != null) if (parent != null)
{ {
Parent = new ContainerViewModel(parent); Parent = new ContainerViewModel(parent, ItemNameConverterService);
await Parent.Init(); await Parent.Init();
} }
else else
@@ -174,7 +190,7 @@ namespace FileTime.Uno.Application
public async Task GotToHome() public async Task GotToHome()
{ {
var path = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile).Replace(Path.DirectorySeparatorChar, Constants.SeparatorChar); var path = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile).Replace(Path.DirectorySeparatorChar, Constants.SeparatorChar);
var resolvedPath = LocalContentProvider.GetByPath(path); var resolvedPath = await LocalContentProvider.GetByPath(path);
if (resolvedPath is IContainer homeFolder) if (resolvedPath is IContainer homeFolder)
{ {
await Tab.OpenContainer(homeFolder); await Tab.OpenContainer(homeFolder);
@@ -185,5 +201,10 @@ namespace FileTime.Uno.Application
{ {
(await Tab.GetCurrentLocation())?.CreateContainer(name); (await Tab.GetCurrentLocation())?.CreateContainer(name);
} }
public async Task OpenContainer(IContainer container)
{
await Tab.OpenContainer(container);
}
} }
} }

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FileTime.Uno.Application
{
public enum ViewMode
{
Default,
RapidTravel
}
}

View File

@@ -45,6 +45,7 @@ namespace FileTime.Uno.Converters
{ {
if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt == parameterInt; if (value is int valueInt && (parameter is int parameterInt || int.TryParse(parameter?.ToString(), out parameterInt))) return valueInt == parameterInt;
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble == parameterDouble; else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble == parameterDouble;
else if (value.GetType().IsEnum && Enum.TryParse(value.GetType(), parameter.ToString(), out var _)) return value.ToString() == parameter.ToString();
} }
return value == parameter; return value == parameter;

View File

@@ -0,0 +1,38 @@
using FileTime.Uno.Application;
using FileTime.Uno.ViewModels;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Media;
using System;
using System.Collections.Generic;
using System.Text;
namespace FileTime.Uno.Converters
{
public class ItemViewModeToBrushConverter : IValueConverter
{
public string DefaultBrush { get; set; }
public string SelectedBrush { get; set; }
public string AlternativeBrush { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is ItemViewMode viewMode)
{
return viewMode switch
{
ItemViewMode.Default => Microsoft.UI.Xaml.Application.Current.Resources[DefaultBrush],
ItemViewMode.Selected => Microsoft.UI.Xaml.Application.Current.Resources[SelectedBrush],
ItemViewMode.Alternative => Microsoft.UI.Xaml.Application.Current.Resources[AlternativeBrush],
_ => throw new NotSupportedException(),
};
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}

View File

@@ -20,6 +20,7 @@
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)Application\AppState.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Application\AppState.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Application\TabContainer.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Application\TabContainer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Application\ViewMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Command\CommandBinding.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Command\CommandBinding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Command\CommandHandler.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Command\CommandHandler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Converters\BoolToVisibilityConverter.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Converters\BoolToVisibilityConverter.cs" />
@@ -29,6 +30,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Converters\FormatSizeConverter.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Converters\FormatSizeConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Converters\ItemToImageConverter.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Converters\ItemToImageConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Converters\NullToVisibilityConverter.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Converters\NullToVisibilityConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Converters\ItemViewModeToBrushConverter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IconProviders\AwesomeIconProvider.cs" /> <Compile Include="$(MSBuildThisFileDirectory)IconProviders\AwesomeIconProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IconProviders\IIconProvider.cs" /> <Compile Include="$(MSBuildThisFileDirectory)IconProviders\IIconProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IconProviders\MaterialIconProvider.cs" /> <Compile Include="$(MSBuildThisFileDirectory)IconProviders\MaterialIconProvider.cs" />
@@ -38,13 +40,16 @@
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)Misc\InputElementWrapper.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Misc\InputElementWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Misc\KeyWithModifiers.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Misc\KeyWithModifiers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\ItemNamePart.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Models\RootDriveInfo.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Models\RootDriveInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Services\ItemNameConverterService.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Startup.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Startup.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ContainerViewModel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModels\ContainerViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ElementViewModel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModels\ElementViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\IItemViewModel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModels\IItemViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ItemViewMode.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModels\ItemViewMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\MainPageViewModel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModels\MainPageViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\TabControlViewModel.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Include="$(MSBuildThisFileDirectory)Converters\Converters.xaml"> <Page Include="$(MSBuildThisFileDirectory)Converters\Converters.xaml">

View File

@@ -13,6 +13,7 @@
<ItemGroup> <ItemGroup>
<_Globbed_Compile Remove="Application\AppState.cs" /> <_Globbed_Compile Remove="Application\AppState.cs" />
<_Globbed_Compile Remove="Application\TabContainer.cs" /> <_Globbed_Compile Remove="Application\TabContainer.cs" />
<_Globbed_Compile Remove="Application\ViewMode.cs" />
<_Globbed_Compile Remove="Command\CommandBinding.cs" /> <_Globbed_Compile Remove="Command\CommandBinding.cs" />
<_Globbed_Compile Remove="Converters\BoolToVisibilityConverter.cs" /> <_Globbed_Compile Remove="Converters\BoolToVisibilityConverter.cs" />
<_Globbed_Compile Remove="Converters\DebugConverter.cs" /> <_Globbed_Compile Remove="Converters\DebugConverter.cs" />
@@ -27,7 +28,9 @@
<_Globbed_Compile Remove="IconProviders\SystemIconProvider.cs" /> <_Globbed_Compile Remove="IconProviders\SystemIconProvider.cs" />
<_Globbed_Compile Remove="Misc\InputElementWrapper.cs" /> <_Globbed_Compile Remove="Misc\InputElementWrapper.cs" />
<_Globbed_Compile Remove="Misc\KeyWithModifiers.cs" /> <_Globbed_Compile Remove="Misc\KeyWithModifiers.cs" />
<_Globbed_Compile Remove="Models\ItemNamePart.cs" />
<_Globbed_Compile Remove="Models\RootDriveInfo.cs" /> <_Globbed_Compile Remove="Models\RootDriveInfo.cs" />
<_Globbed_Compile Remove="Services\ItemNameConverterService.cs" />
<_Globbed_Compile Remove="Startup.cs" /> <_Globbed_Compile Remove="Startup.cs" />
<_Globbed_Compile Remove="StyleSelectors\ContentItemStyleSelector.cs" /> <_Globbed_Compile Remove="StyleSelectors\ContentItemStyleSelector.cs" />
<_Globbed_Compile Remove="ViewModels\ContainerViewModel.cs" /> <_Globbed_Compile Remove="ViewModels\ContainerViewModel.cs" />
@@ -35,6 +38,7 @@
<_Globbed_Compile Remove="ViewModels\IItemViewModel.cs" /> <_Globbed_Compile Remove="ViewModels\IItemViewModel.cs" />
<_Globbed_Compile Remove="ViewModels\ItemViewMode.cs" /> <_Globbed_Compile Remove="ViewModels\ItemViewMode.cs" />
<_Globbed_Compile Remove="ViewModels\MainPageViewModel.cs" /> <_Globbed_Compile Remove="ViewModels\MainPageViewModel.cs" />
<_Globbed_Compile Remove="ViewModels\TabControlViewModel.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<_Globbed_Content Remove="Assets\Fonts\Font Awesome 5 Brands-Regular-400.otf" /> <_Globbed_Content Remove="Assets\Fonts\Font Awesome 5 Brands-Regular-400.otf" />

View File

@@ -105,11 +105,78 @@
<Grid Grid.Column="1"> <Grid Grid.Column="1">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid Margin="20"> <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid>
<TextBlock
Margin="10,5"
Foreground="{ThemeResource ForegroundBrush}"
Text="{Binding AppState.SelectedTab.CurrentLocation.Container.FullName}" />
</Grid>
<ItemsControl
Grid.Column="1"
HorizontalAlignment="Right"
ItemsSource="{Binding Tabs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid
Margin="10,0,0,0"
Padding="5">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior
Binding="{Binding IsSelected}"
Value="True">
<ic:ChangePropertyAction
PropertyName="Background"
Value="{ThemeResource ForegroundBrush}" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=Text}"
Value="{ThemeResource ContainerBackgroundBrush}" />
</ic:DataTriggerBehavior>
<ic:DataTriggerBehavior
Binding="{Binding IsSelected}"
Value="False">
<ic:ChangePropertyAction
PropertyName="Background"
Value="{ThemeResource ContainerBackgroundBrush}" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=Text}"
Value="{ThemeResource ForegroundBrush}" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
<TextBlock
x:Name="Text"
VerticalAlignment="Center">
<Run Text="{Binding TabNumber}" />
<Run Text="{Binding Tab.CurrentLocation.Container.FullName}" />
</TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<Grid
Grid.Row="1"
Margin="20">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="15*" /> <ColumnDefinition Width="15*" />
@@ -235,7 +302,37 @@
</Grid> </Grid>
</Grid> </Grid>
<Grid Grid.Row="1"> <Grid Grid.Row="2">
<Grid Visibility="{Binding AppState.ViewMode, Converter={StaticResource EqualityToVisibilityConverter}, ConverterParameter=RapidTravel}">
<Grid.RowDefinitions>
<RowDefinition Height="1" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle
Height="1"
Margin="10,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Fill="{ThemeResource ContentSeparatorBrush}" />
<StackPanel
Grid.Row="1"
Margin="30,10,10,10"
Orientation="Horizontal">
<TextBlock
Margin="0,0,30,0"
Foreground="{ThemeResource ForegroundBrush}"
Text="Rapid travel mode" />
<TextBlock Foreground="{ThemeResource ForegroundBrush}">
<Run Text="Filter" />
<Run Text="{Binding AppState.RapidTravelText}" />
</TextBlock>
</StackPanel>
</Grid>
<Grid Visibility="{Binding NoCommandFound, Converter={StaticResource BoolToVisibilityConverter}}"> <Grid Visibility="{Binding NoCommandFound, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="1" /> <RowDefinition Height="1" />

View File

@@ -32,9 +32,9 @@ namespace FileTime.Uno
ViewModel.FocusDefaultElement = () => (FindName(nameof(CurrentItems)) as FrameworkElement)?.Focus(FocusState.Programmatic); ViewModel.FocusDefaultElement = () => (FindName(nameof(CurrentItems)) as FrameworkElement)?.Focus(FocusState.Programmatic);
foreach (var asd in Microsoft.UI.Xaml.Application.Current.Resources.MergedDictionaries) foreach (var resourceDictionary in Microsoft.UI.Xaml.Application.Current.Resources.MergedDictionaries)
{ {
if (asd is ResourceDictionary resourceDictionary && resourceDictionary.Source != null) if (resourceDictionary.Source != null)
{ {
if (resourceDictionary.Source.LocalPath == "/Files/Themes/DefaultLight.xaml") if (resourceDictionary.Source.LocalPath == "/Files/Themes/DefaultLight.xaml")
{ {
@@ -57,9 +57,9 @@ namespace FileTime.Uno
CurrentItems.Focus(FocusState.Programmatic); CurrentItems.Focus(FocusState.Programmatic);
} }
private void CurrentItems_KeyDown(object sender, KeyRoutedEventArgs e) private async void CurrentItems_KeyDown(object sender, KeyRoutedEventArgs e)
{ {
e.Handled = ViewModel.ProcessKeyDown(e.Key) || e.Handled; e.Handled = await ViewModel.ProcessKeyDown(e.Key) || e.Handled;
} }
private async void CurrentItems_KeyUp(object sender, KeyRoutedEventArgs e) private async void CurrentItems_KeyUp(object sender, KeyRoutedEventArgs e)

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
using Windows.UI.Text;
namespace FileTime.Uno.Models
{
public class ItemNamePart
{
public string Text { get; set; }
public TextDecorations TextDecorations { get; set; }
public ItemNamePart(string text)
{
Text = text;
}
}
}

View File

@@ -0,0 +1,52 @@
using FileTime.Uno.Application;
using FileTime.Uno.Models;
using FileTime.Uno.ViewModels;
using MvvmGen;
using System;
using System.Collections.Generic;
using System.Text;
using Windows.UI.Text;
namespace FileTime.Uno.Services
{
[ViewModel]
[Inject(typeof(AppState))]
public partial class ItemNameConverterService
{
public List<ItemNamePart> GetDisplayName(IItemViewModel itemViewModel)
{
var nameParts = new List<ItemNamePart>();
var rapidTravelText = AppState.RapidTravelText.ToLower();
if (AppState.ViewMode == ViewMode.RapidTravel && rapidTravelText.Length > 0)
{
var nameLeft = itemViewModel.Item.Name;
while (nameLeft.ToLower().Contains(rapidTravelText))
{
var rapidTextStart = nameLeft.ToLower().IndexOf(rapidTravelText);
var before = rapidTextStart > 0 ? nameLeft.Substring(0, rapidTextStart) : null;
var rapidTravel = nameLeft.Substring(rapidTextStart, rapidTravelText.Length);
nameLeft = nameLeft.Substring(rapidTextStart + rapidTravelText.Length);
if (before != null)
{
nameParts.Add(new ItemNamePart(before));
}
nameParts.Add(new ItemNamePart(rapidTravel) { TextDecorations = TextDecorations.Underline });
}
if (nameLeft.Length > 0)
{
nameParts.Add(new ItemNamePart(nameLeft));
}
}
else
{
nameParts.Add(new ItemNamePart(itemViewModel.Item.Name));
}
return nameParts;
}
}
}

View File

@@ -1,4 +1,5 @@
using FileTime.Uno.Application; using FileTime.Uno.Application;
using FileTime.Uno.Services;
using FileTime.Uno.ViewModels; using FileTime.Uno.ViewModels;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System; using System;
@@ -12,9 +13,14 @@ namespace FileTime.Uno
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection) internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
{ {
return serviceCollection return serviceCollection
.AddLogging() .AddSingleton<AppState>()
.AddTransient<AppState>()
.AddTransient<MainPageViewModel>(); .AddTransient<MainPageViewModel>();
} }
internal static IServiceCollection AddServices(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddLogging()
.AddSingleton<ItemNameConverterService>();
}
} }
} }

View File

@@ -1,14 +1,23 @@
<ResourceDictionary <ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:FileTime.Uno.Converters"
xmlns:i="using:Microsoft.Xaml.Interactivity" xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"> xmlns:ic="using:Microsoft.Xaml.Interactions.Core">
<DataTemplate x:Key="ContainerItemTemplate"> <DataTemplate x:Key="ContainerItemTemplate">
<Grid <Grid
x:Name="ContainerItemTemplateRoot"
Margin="0" Margin="0"
Padding="0" Padding="0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"> VerticalAlignment="Stretch">
<Grid.Resources>
<converters:ItemViewModeToBrushConverter
x:Key="TextForegroundConverter"
AlternativeBrush="AlternativeForegroundBrush"
DefaultBrush="ForegroundBrush"
SelectedBrush="SelectedItemForegroundBrush" />
</Grid.Resources>
<i:Interaction.Behaviors> <i:Interaction.Behaviors>
<ic:DataTriggerBehavior <ic:DataTriggerBehavior
Binding="{Binding ViewMode, Converter={StaticResource EnumToStringConverter}}" Binding="{Binding ViewMode, Converter={StaticResource EnumToStringConverter}}"
@@ -16,10 +25,6 @@
<ic:ChangePropertyAction <ic:ChangePropertyAction
PropertyName="Background" PropertyName="Background"
Value="{ThemeResource ItemBackgroundBrush}" /> Value="{ThemeResource ItemBackgroundBrush}" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=DispalyText}"
Value="{ThemeResource ForegroundBrush}" />
</ic:DataTriggerBehavior> </ic:DataTriggerBehavior>
<ic:DataTriggerBehavior <ic:DataTriggerBehavior
Binding="{Binding ViewMode, Converter={StaticResource EnumToStringConverter}}" Binding="{Binding ViewMode, Converter={StaticResource EnumToStringConverter}}"
@@ -27,10 +32,6 @@
<ic:ChangePropertyAction <ic:ChangePropertyAction
PropertyName="Background" PropertyName="Background"
Value="{ThemeResource AlternativeItemBackgroundBrush}" /> Value="{ThemeResource AlternativeItemBackgroundBrush}" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=DispalyText}"
Value="{ThemeResource AlternativeForegroundBrush}" />
</ic:DataTriggerBehavior> </ic:DataTriggerBehavior>
<ic:DataTriggerBehavior <ic:DataTriggerBehavior
Binding="{Binding ViewMode, Converter={StaticResource EnumToStringConverter}}" Binding="{Binding ViewMode, Converter={StaticResource EnumToStringConverter}}"
@@ -38,10 +39,6 @@
<ic:ChangePropertyAction <ic:ChangePropertyAction
PropertyName="Background" PropertyName="Background"
Value="{ThemeResource SelectedItemBackgroundBrush}" /> Value="{ThemeResource SelectedItemBackgroundBrush}" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=DispalyText}"
Value="{ThemeResource SelectedItemForegroundBrush}" />
</ic:DataTriggerBehavior> </ic:DataTriggerBehavior>
</i:Interaction.Behaviors> </i:Interaction.Behaviors>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -54,11 +51,28 @@
Height="32" Height="32"
Margin="10,0" Margin="10,0"
Source="{Binding Converter={StaticResource ItemToImageConverter}}" /> Source="{Binding Converter={StaticResource ItemToImageConverter}}" />
<TextBlock
x:Name="DispalyText" <ItemsControl
Grid.Column="1" Grid.Column="1"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Item.Name}" /> ItemsSource="{Binding DisplayName}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock
x:Name="DispalyText"
Foreground="{Binding DataContext.ViewMode, ElementName=ContainerItemTemplateRoot, Converter={StaticResource TextForegroundConverter}}"
Text="{Binding Text}"
TextDecorations="{Binding TextDecorations}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid> </Grid>
</DataTemplate> </DataTemplate>

View File

@@ -1,5 +1,7 @@
using AsyncEvent; using AsyncEvent;
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Uno.Models;
using FileTime.Uno.Services;
using MvvmGen; using MvvmGen;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -11,6 +13,7 @@ using System.Threading.Tasks;
namespace FileTime.Uno.ViewModels namespace FileTime.Uno.ViewModels
{ {
[ViewModel] [ViewModel]
[Inject(typeof(ItemNameConverterService))]
public partial class ContainerViewModel : IItemViewModel public partial class ContainerViewModel : IItemViewModel
{ {
private bool isRefreshing; private bool isRefreshing;
@@ -45,6 +48,8 @@ namespace FileTime.Uno.ViewModels
? ItemViewMode.Alternative ? ItemViewMode.Alternative
: ItemViewMode.Default; : ItemViewMode.Default;
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(this);
public ObservableCollection<ContainerViewModel> Containers public ObservableCollection<ContainerViewModel> Containers
{ {
get get
@@ -70,12 +75,14 @@ namespace FileTime.Uno.ViewModels
} }
} }
public ContainerViewModel(IContainer container) : this() public ContainerViewModel(IContainer container, ItemNameConverterService itemNameConverterService) : this(itemNameConverterService)
{ {
Container = container; Container = container;
Container.Refreshed.Add(Container_Refreshed); Container.Refreshed.Add(Container_Refreshed);
} }
public void InvalidateDisplayName() => OnPropertyChanged(nameof(DisplayName));
public async Task Init(bool initializeChildren = true) public async Task Init(bool initializeChildren = true)
{ {
await Refresh(initializeChildren); await Refresh(initializeChildren);
@@ -98,8 +105,8 @@ namespace FileTime.Uno.ViewModels
{ {
isRefreshing = true; isRefreshing = true;
var containers = (await _container.GetContainers()).Select(c => new ContainerViewModel(c)).ToList(); var containers = (await _container.GetContainers()).Select(c => new ContainerViewModel(c, ItemNameConverterService)).ToList();
var elements = (await _container.GetElements()).Select(e => new ElementViewModel(e)).ToList(); var elements = (await _container.GetElements()).Select(e => new ElementViewModel(e, ItemNameConverterService)).ToList();
_containers.Clear(); _containers.Clear();
_elements.Clear(); _elements.Clear();

View File

@@ -1,12 +1,13 @@
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Uno.Models;
using FileTime.Uno.Services;
using MvvmGen; using MvvmGen;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
namespace FileTime.Uno.ViewModels namespace FileTime.Uno.ViewModels
{ {
[ViewModel] [ViewModel]
[Inject(typeof(ItemNameConverterService))]
public partial class ElementViewModel : IItemViewModel public partial class ElementViewModel : IItemViewModel
{ {
public IItem Item => _element; public IItem Item => _element;
@@ -29,9 +30,13 @@ namespace FileTime.Uno.ViewModels
? ItemViewMode.Alternative ? ItemViewMode.Alternative
: ItemViewMode.Default; : ItemViewMode.Default;
public ElementViewModel(IElement element) public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(this);
public ElementViewModel(IElement element, ItemNameConverterService itemNameConverterService) : this(itemNameConverterService)
{ {
Element = element; Element = element;
} }
public void InvalidateDisplayName() => OnPropertyChanged(nameof(DisplayName));
} }
} }

View File

@@ -1,4 +1,5 @@
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Uno.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@@ -13,5 +14,9 @@ namespace FileTime.Uno.ViewModels
bool IsAlternative { get; set; } bool IsAlternative { get; set; }
ItemViewMode ViewMode { get; } ItemViewMode ViewMode { get; }
List<ItemNamePart> DisplayName { get; }
void InvalidateDisplayName();
} }
} }

View File

@@ -1,13 +1,18 @@
using FileTime.Core.Components; using FileTime.Core.Components;
using FileTime.Core.Extensions;
using FileTime.Core.Interactions; using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Providers.Local; using FileTime.Providers.Local;
using FileTime.Uno.Application; using FileTime.Uno.Application;
using FileTime.Uno.Command; using FileTime.Uno.Command;
using FileTime.Uno.Misc; using FileTime.Uno.Misc;
using FileTime.Uno.Models; using FileTime.Uno.Models;
using FileTime.Uno.Services;
using MvvmGen; using MvvmGen;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -18,22 +23,24 @@ namespace FileTime.Uno.ViewModels
[ViewModel] [ViewModel]
[Inject(typeof(LocalContentProvider))] [Inject(typeof(LocalContentProvider))]
[Inject(typeof(AppState), PropertyAccessModifier = AccessModifier.Public)] [Inject(typeof(AppState), PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(ItemNameConverterService))]
public partial class MainPageViewModel public partial class MainPageViewModel
{ {
const string RAPIDTRAVEL = "rapidTravel";
private readonly List<KeyWithModifiers> _previousKeys = new List<KeyWithModifiers>(); private readonly List<KeyWithModifiers> _previousKeys = new List<KeyWithModifiers>();
private readonly List<KeyWithModifiers[]> _keysToSkip = new List<KeyWithModifiers[]>(); private readonly List<KeyWithModifiers[]> _keysToSkip = new List<KeyWithModifiers[]>();
private bool _isAltPressed = false; private bool _isAltPressed = false;
private bool _isShiftPressed = false; private bool _isShiftPressed = false;
private bool _isCtrlPressed = false; private bool _isCtrlPressed = false;
private List<CommandBinding> _commandBindings = new();
private List<CommandBinding> _universalCommandBindings = new();
private Action _inputHandler; private Action _inputHandler;
[Property] [Property]
private string _text; private string _text;
[Property]
private List<CommandBinding> _commandBindings = new();
[Property] [Property]
private bool _noCommandFound; private bool _noCommandFound;
@@ -46,6 +53,9 @@ namespace FileTime.Uno.ViewModels
[Property] [Property]
private List<RootDriveInfo> _rootDriveInfos; private List<RootDriveInfo> _rootDriveInfos;
[Property]
private ObservableCollection<TabControlViewModel> _tabs = new ObservableCollection<TabControlViewModel>();
public Action FocusDefaultElement { get; set; } public Action FocusDefaultElement { get; set; }
async partial void OnInitialize() async partial void OnInitialize()
@@ -55,17 +65,21 @@ namespace FileTime.Uno.ViewModels
_keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.Up) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.Up) });
_keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.Down) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.Down) });
_keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.Tab) }); _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.Tab) });
_keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.PageDown) });
_keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(VirtualKey.PageUp) });
var tab = new Tab(); var tab = new Tab();
await tab.Init(LocalContentProvider); await tab.Init(LocalContentProvider);
var tabContainer = new TabContainer(tab, LocalContentProvider); var tabContainer = new TabContainer(tab, LocalContentProvider, ItemNameConverterService);
await tabContainer.Init(); await tabContainer.Init();
AppState.Tabs = new List<TabContainer>() AppState.Tabs = new List<TabContainer>()
{ {
tabContainer tabContainer
}; };
_tabs.Add(new TabControlViewModel(1, tabContainer));
var driveInfos = new List<RootDriveInfo>(); var driveInfos = new List<RootDriveInfo>();
foreach (var drive in DriveInfo.GetDrives()) foreach (var drive in DriveInfo.GetDrives())
{ {
@@ -82,9 +96,27 @@ namespace FileTime.Uno.ViewModels
public async Task OpenContainer() public async Task OpenContainer()
{ {
AppState.RapidTravelText = "";
await AppState.SelectedTab.Open(); await AppState.SelectedTab.Open();
} }
public async Task OpenOrRun()
{
if (AppState.SelectedTab.SelectedItem is ContainerViewModel)
{
await OpenContainer();
}
else if (AppState.SelectedTab.SelectedItem is ElementViewModel elementViewModel && elementViewModel.Element is LocalFile localFile)
{
Process.Start(new ProcessStartInfo(localFile.File.FullName) { UseShellExecute = true });
if (AppState.ViewMode == ViewMode.RapidTravel)
{
await ExitRapidTravelMode();
}
}
}
public async Task GoUp() public async Task GoUp()
{ {
await AppState.SelectedTab.GoUp(); await AppState.SelectedTab.GoUp();
@@ -135,6 +167,90 @@ namespace FileTime.Uno.ViewModels
await AppState.SelectedTab.GotToHome(); await AppState.SelectedTab.GotToHome();
} }
public Task EnterRapidTravelMode()
{
AppState.ViewMode = ViewMode.RapidTravel;
_previousKeys.Clear();
PossibleCommands = new();
FocusDefaultElement?.Invoke();
return Task.CompletedTask;
}
public async Task ExitRapidTravelMode()
{
AppState.ViewMode = ViewMode.Default;
_previousKeys.Clear();
PossibleCommands = new();
AppState.RapidTravelText = "";
await AppState.SelectedTab.OpenContainer(await AppState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(RAPIDTRAVEL));
FocusDefaultElement?.Invoke();
}
public async Task SwitchToTab(int number)
{
var tab = _tabs.FirstOrDefault(t => t.TabNumber == number);
if (number == -1)
{
var greatestNumber = _tabs.Select(t => t.TabNumber).Max();
tab = _tabs.FirstOrDefault(t => t.TabNumber == greatestNumber);
}
else if (tab == null)
{
var newContainer = await AppState.SelectedTab.CurrentLocation.Container.Clone();
var newTab = new Tab();
await newTab.Init(newContainer);
var tabContainer = new TabContainer(newTab, LocalContentProvider, ItemNameConverterService);
await tabContainer.Init();
tab = new TabControlViewModel(number, tabContainer);
var i = 0;
for (i = 0; i < Tabs.Count; i++)
{
if (Tabs[i].TabNumber > number) break;
}
Tabs.Insert(i, tab);
}
if (AppState.ViewMode == ViewMode.RapidTravel)
{
await ExitRapidTravelMode();
}
AppState.SelectedTab = tab.Tab;
foreach (var tab2 in Tabs)
{
tab2.IsSelected = tab2.TabNumber == tab.TabNumber;
}
}
public async Task CloseTab()
{
if (_tabs.Count > 1)
{
var currentTab = _tabs.FirstOrDefault(t => t.Tab == AppState.SelectedTab);
if (currentTab != null)
{
_tabs.Remove(currentTab);
var tabNumber = _tabs[0].TabNumber;
for (var i = 0; i < Tabs.Count; i++)
{
if (Tabs[i].TabNumber > currentTab.TabNumber) break;
tabNumber = _tabs[i].TabNumber;
}
await SwitchToTab(tabNumber);
}
}
}
public Task CreateContainer() public Task CreateContainer()
{ {
var handler = () => var handler = () =>
@@ -167,7 +283,7 @@ namespace FileTime.Uno.ViewModels
_inputHandler = null; _inputHandler = null;
} }
public bool ProcessKeyDown(VirtualKey key) public async Task<bool> ProcessKeyDown(VirtualKey key)
{ {
NoCommandFound = false; NoCommandFound = false;
if (key == VirtualKey.Menu) if (key == VirtualKey.Menu)
@@ -182,10 +298,126 @@ namespace FileTime.Uno.ViewModels
{ {
_isCtrlPressed = true; _isCtrlPressed = true;
} }
else
{
if (AppState.ViewMode == ViewMode.Default)
{
var keyWithModifiers = new KeyWithModifiers(key, _isAltPressed, _isShiftPressed, _isCtrlPressed);
_previousKeys.Add(keyWithModifiers);
var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys));
selectedCommandBinding ??= _commandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys));
if (key == VirtualKey.Escape)
{
_previousKeys.Clear();
PossibleCommands = new();
}
else if (selectedCommandBinding != null)
{
await selectedCommandBinding.InvokeAsync();
_previousKeys.Clear();
PossibleCommands = new();
FocusDefaultElement?.Invoke();
}
else if (_keysToSkip.Any(k => AreKeysEqual(k, _previousKeys)))
{
_previousKeys.Clear();
PossibleCommands = new();
}
else if (_previousKeys.Count == 2)
{
NoCommandFound = true;
_previousKeys.Clear();
PossibleCommands = new();
}
else
{
var possibleCommands = _universalCommandBindings.Concat(_commandBindings).Where(c => AreKeysEqual(c.Keys[0], keyWithModifiers)).ToList();
if (possibleCommands.Count == 0)
{
NoCommandFound = true;
_previousKeys.Clear();
}
else
{
PossibleCommands = possibleCommands;
}
}
return true;
}
else
{
var keyString = key.ToString();
var updateRapidTravelFilter = false;
if (key == VirtualKey.Escape)
{
await ExitRapidTravelMode();
}
else if (key == VirtualKey.Back)
{
if (AppState.RapidTravelText.Length > 0)
{
AppState.RapidTravelText = AppState.RapidTravelText.Substring(0, AppState.RapidTravelText.Length - 1);
updateRapidTravelFilter = true;
}
}
else if (keyString.Length == 1)
{
AppState.RapidTravelText += keyString.ToString().ToLower();
updateRapidTravelFilter = true;
}
else
{
var currentKeyAsList = new List<KeyWithModifiers>() { new KeyWithModifiers(key) };
var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, currentKeyAsList));
if (selectedCommandBinding != null)
{
await selectedCommandBinding.InvokeAsync();
FocusDefaultElement?.Invoke();
}
}
if (updateRapidTravelFilter)
{
var currentLocation = await AppState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(RAPIDTRAVEL);
var newLocation = new VirtualContainer(
currentLocation,
new List<Func<IEnumerable<IContainer>, IEnumerable<IContainer>>>()
{
container => container.Where(c => c.Name.ToLower().Contains(AppState.RapidTravelText))
},
new List<Func<IEnumerable<IElement>, IEnumerable<IElement>>>()
{
element => element.Where(e => e.Name.ToLower().Contains(AppState.RapidTravelText))
},
virtualContainerName: RAPIDTRAVEL
);
await newLocation.Init();
await AppState.SelectedTab.OpenContainer(newLocation);
var selectedItemName = AppState.SelectedTab.SelectedItem.Item.Name;
if (!AppState.SelectedTab.CurrentLocation.Items.Select(i => i.Item.Name).Any(n => n == selectedItemName))
{
await AppState.SelectedTab.MoveCursorToFirst();
}
FocusDefaultElement?.Invoke();
}
return true;
}
}
return false; return false;
} }
public async Task<bool> ProcessKeyUp(VirtualKey key) public Task<bool> ProcessKeyUp(VirtualKey key)
{ {
if (key == VirtualKey.Menu) if (key == VirtualKey.Menu)
{ {
@@ -199,57 +431,8 @@ namespace FileTime.Uno.ViewModels
{ {
_isCtrlPressed = false; _isCtrlPressed = false;
} }
else
{
var keyWithModifiers = new KeyWithModifiers(key, _isAltPressed, _isShiftPressed, _isCtrlPressed);
_previousKeys.Add(keyWithModifiers);
var selectedCommandBinding = _commandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys)); return Task.FromResult(false);
if (key == VirtualKey.Escape)
{
_previousKeys.Clear();
PossibleCommands = new();
}
else if (selectedCommandBinding != null)
{
await selectedCommandBinding.InvokeAsync();
_previousKeys.Clear();
PossibleCommands = new();
if (selectedCommandBinding.Name != "")
{
FocusDefaultElement?.Invoke();
}
}
else if (_keysToSkip.Any(k => AreKeysEqual(k, _previousKeys)))
{
_previousKeys.Clear();
PossibleCommands = new();
}
else if (_previousKeys.Count == 2)
{
NoCommandFound = true;
_previousKeys.Clear();
PossibleCommands = new();
}
else
{
var possibleCommands = _commandBindings.Where(c => AreKeysEqual(c.Keys[0], keyWithModifiers)).ToList();
if (possibleCommands.Count == 0)
{
NoCommandFound = true;
_previousKeys.Clear();
}
else
{
PossibleCommands = possibleCommands;
}
}
return true;
}
return false;
} }
public void ResetSpecialKeys() public void ResetSpecialKeys()
@@ -287,17 +470,11 @@ namespace FileTime.Uno.ViewModels
{ {
var commandBindings = new List<CommandBinding>() var commandBindings = new List<CommandBinding>()
{ {
new CommandBinding("go up", FileTime.App.Core.Command.Commands.GoUp, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Left)}, GoUp), new CommandBinding(
new CommandBinding("open", FileTime.App.Core.Command.Commands.Open, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Right)}, OpenContainer), "enter rapid travel mode",
/*new CommandBinding("cursor up", FileTime.App.Core.Command.Commands.MoveCursorUp, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Up)}, MoveCursorUp), FileTime.App.Core.Command.Commands.EnterRapidTravel,
new CommandBinding("cursor down", FileTime.App.Core.Command.Commands.MoveCursorDown, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Down)}, MoveCursorDown), new KeyWithModifiers[]{new KeyWithModifiers((VirtualKey)188, shift: true)},
new CommandBinding("cursor page up", FileTime.App.Core.Command.Commands.MoveCursorUpPage, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageUp)}, MoveCursorUpPage), EnterRapidTravelMode),
new CommandBinding("cursor page down", FileTime.App.Core.Command.Commands.MoveCursorDownPage, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageDown)}, MoveCursorDownPage),*/
/*new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Up)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Down)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageUp)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageDown)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Tab)}, () =>{ }),*/
new CommandBinding( new CommandBinding(
"create container", "create container",
FileTime.App.Core.Command.Commands.CreateContainer, FileTime.App.Core.Command.Commands.CreateContainer,
@@ -328,9 +505,75 @@ namespace FileTime.Uno.ViewModels
FileTime.App.Core.Command.Commands.GoToHome, FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.G),new KeyWithModifiers(VirtualKey.H)}, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.G),new KeyWithModifiers(VirtualKey.H)},
GotToHome), GotToHome),
new CommandBinding(
"switch to tab 1",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number1)},
async() => await SwitchToTab(1)),
new CommandBinding(
"switch to tab 2",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number2)},
async() => await SwitchToTab(2)),
new CommandBinding(
"switch to tab 3",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number3)},
async() => await SwitchToTab(3)),
new CommandBinding(
"switch to tab 4",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number4)},
async() => await SwitchToTab(4)),
new CommandBinding(
"switch to tab 5",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number5)},
async() => await SwitchToTab(5)),
new CommandBinding(
"switch to tab 6",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number6)},
async() => await SwitchToTab(6)),
new CommandBinding(
"switch to tab 7",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number7)},
async() => await SwitchToTab(7)),
new CommandBinding(
"switch to tab 8",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number8)},
async() => await SwitchToTab(8)),
new CommandBinding(
"switch to last tab",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Number9)},
async() => await SwitchToTab(-1)),
new CommandBinding(
"close tab",
FileTime.App.Core.Command.Commands.GoToHome,
new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Q)},
CloseTab),
};
var universalCommandBindings = new List<CommandBinding>()
{
new CommandBinding("go up", FileTime.App.Core.Command.Commands.GoUp, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Left)}, GoUp),
new CommandBinding("open", FileTime.App.Core.Command.Commands.Open, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Right)}, OpenContainer),
new CommandBinding("open or run", FileTime.App.Core.Command.Commands.OpenOrRun, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Enter)}, OpenOrRun),
/*new CommandBinding("cursor up", FileTime.App.Core.Command.Commands.MoveCursorUp, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Up)}, MoveCursorUp),
new CommandBinding("cursor down", FileTime.App.Core.Command.Commands.MoveCursorDown, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Down)}, MoveCursorDown),
new CommandBinding("cursor page up", FileTime.App.Core.Command.Commands.MoveCursorUpPage, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageUp)}, MoveCursorUpPage),
new CommandBinding("cursor page down", FileTime.App.Core.Command.Commands.MoveCursorDownPage, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageDown)}, MoveCursorDownPage),*/
/*new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Up)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Down)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageUp)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.PageDown)}, () =>{ }),
new CommandBinding("", null, new KeyWithModifiers[]{new KeyWithModifiers(VirtualKey.Tab)}, () =>{ }),*/
}; };
_commandBindings.AddRange(commandBindings); _commandBindings.AddRange(commandBindings);
_universalCommandBindings.AddRange(universalCommandBindings);
} }
} }
} }

View File

@@ -0,0 +1,17 @@
using FileTime.Uno.Application;
using MvvmGen;
using System;
using System.Collections.Generic;
using System.Text;
namespace FileTime.Uno.ViewModels
{
[ViewModel]
[Inject(typeof(TabContainer), "Tab", PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(int), "TabNumber", PropertyAccessModifier = AccessModifier.Public)]
public partial class TabControlViewModel
{
[Property]
private bool _isSelected;
}
}

View File

@@ -15,14 +15,6 @@ namespace FileTime.Providers.Local
private readonly IReadOnlyList<IItem>? _items; private readonly IReadOnlyList<IItem>? _items;
private readonly IReadOnlyList<IElement>? _elements = new List<IElement>().AsReadOnly(); private readonly IReadOnlyList<IElement>? _elements = new List<IElement>().AsReadOnly();
/* public IReadOnlyList<IContainer> RootContainers { get; }
public IReadOnlyList<IItem> Items => RootContainers;
public IReadOnlyList<IContainer> Containers => RootContainers;
public IReadOnlyList<IElement> Elements { get; } = new List<IElement>(); */
public string Name { get; } = "local"; public string Name { get; } = "local";
public string? FullName { get; } public string? FullName { get; }
@@ -66,6 +58,8 @@ namespace FileTime.Providers.Local
public async Task Refresh() => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty); public async Task Refresh() => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty);
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
public IContainer? GetParent() => _parent; public IContainer? GetParent() => _parent;
public Task<IContainer> CreateContainer(string name) => throw new NotSupportedException(); public Task<IContainer> CreateContainer(string name) => throw new NotSupportedException();
public Task<IElement> CreateElement(string name) => throw new NotSupportedException(); public Task<IElement> CreateElement(string name) => throw new NotSupportedException();

View File

@@ -34,6 +34,8 @@ namespace FileTime.Providers.Local
public IContainer? GetParent() => _parent; public IContainer? GetParent() => _parent;
public Task<IContainer> Clone() => Task.FromResult((IContainer)new LocalFolder(Directory, Provider, _parent));
public Task Refresh() public Task Refresh()
{ {
_containers = new List<IContainer>(); _containers = new List<IContainer>();

View File

@@ -64,6 +64,8 @@ namespace FileTime.Providers.Smb
public IContainer? GetParent() => _parent; public IContainer? GetParent() => _parent;
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
public async Task<bool> IsExists(string name) => (await GetItems())?.Any(i => i.Name == name) ?? false; public async Task<bool> IsExists(string name) => (await GetItems())?.Any(i => i.Name == name) ?? false;
public async Task Refresh() => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty); public async Task Refresh() => await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty);

View File

@@ -45,6 +45,8 @@ namespace FileTime.Providers.Smb
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
public async Task<IItem?> GetByPath(string path) public async Task<IItem?> GetByPath(string path)
{ {
var paths = path.Split(Constants.SeparatorChar); var paths = path.Split(Constants.SeparatorChar);

View File

@@ -92,6 +92,8 @@ namespace FileTime.Providers.Smb
await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty); await Refreshed.InvokeAsync(this, AsyncEventArgs.Empty);
} }
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
private async Task<ISMBClient> GetSmbClient() private async Task<ISMBClient> GetSmbClient()
{ {
if (_client == null) if (_client == null)

View File

@@ -88,6 +88,8 @@ namespace FileTime.Providers.Smb
public IContainer? GetParent() => _parent; public IContainer? GetParent() => _parent;
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
public Task<bool> IsExists(string name) public Task<bool> IsExists(string name)
{ {
throw new NotImplementedException(); throw new NotImplementedException();