Optimization, UI improvements, Run command

This commit is contained in:
2022-02-05 00:04:27 +01:00
parent bca940372a
commit c061f658aa
31 changed files with 579 additions and 212 deletions

View File

@@ -12,6 +12,7 @@
<Color x:Key="AppBackgroundColor">#E7073642</Color>
<Color x:Key="ContainerBackgroundColor">#083e4c</Color>
<Color x:Key="TransparentContainerBackgroundColor">#D0083e4c</Color>
<Color x:Key="BarelyTransparentBackgroundColor">#80083e4c</Color>
<Color x:Key="ItemBackgroundColor">#00000000</Color>
<Color x:Key="AlternativeItemBackgroundColor">#10000000</Color>
@@ -128,6 +129,7 @@
<converters:IsEmptyConverter x:Key="IsNotEmptyConverter" Inverse="true"/>
<converters:ExceptionToStringConverter x:Key="ExceptionToStringConverter"/>
<converters:BoolInverter x:Key="BoolInverter"/>
<converters:IsElementConverter x:Key="IsElementConverter"/>
</ResourceDictionary>
</Application.Resources>
@@ -145,6 +147,10 @@
<Style Selector="TextBlock.ExtraSmallText">
<Setter Property="FontSize" Value="11"/>
</Style>
<Style Selector="TextBox">
<Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}"/>
<Setter Property="Background" Value="{DynamicResource ContainerBackgroundBrush}"/>
</Style>
<Style Selector="ListBox.ContentListView">
<Setter Property="Background" Value="Transparent"/>
</Style>

View File

@@ -20,6 +20,7 @@ namespace FileTime.Avalonia.Application
[Inject(typeof(Tab))]
public partial class TabContainer : INewItemProcessor
{
private bool _updateFromCode;
[Property]
private TabState _tabState;
@@ -46,28 +47,44 @@ namespace FileTime.Avalonia.Application
get => _selectedItem;
set
{
if (value != null)
if (!_updateFromCode && value != null)
{
try
{
SetSelectedItemAsync(value, true).Wait();
/*var task = SetSelectedItemAsync(value, true);
Task.WaitAll(new Task[] { task }, 100);*/
SetSelectedItemAsync(value, true);
}
catch
{
catch
{
//TODO: Debug, linux start after restore 3 tabs
}
}
}
}
[Property]
private ElementPreviewViewModel? _elementPreview;
public async Task SetSelectedItemAsync(IItemViewModel? value, bool fromDataBinding = false)
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged(nameof(SelectedItem));
if (value is ElementViewModel elementViewModel)
{
var elementPreview = new ElementPreviewViewModel();
await elementPreview.Init(elementViewModel.Element);
ElementPreview = elementPreview;
}
else
{
ElementPreview = null;
}
await Tab.SetCurrentSelectedItem(SelectedItem?.Item, fromDataBinding);
OnPropertyChanged(nameof(SelectedItem));
}
}
@@ -174,7 +191,7 @@ namespace FileTime.Avalonia.Application
if (token.IsCancellationRequested) return;
var items = await _currentLocation.GetItems();
var items = await _currentLocation.GetItems(token);
if (items?.Count > 0)
{
foreach (var item in items)
@@ -198,7 +215,7 @@ namespace FileTime.Avalonia.Application
{
if (token.IsCancellationRequested) return;
var activeChildItem = await Tab.GetItemByLastPath(containerViewModel.Container);
child = (await containerViewModel.GetItems()).FirstOrDefault(i => i.Item == activeChildItem);
child = (await containerViewModel.GetItems(token)).FirstOrDefault(i => i.Item == activeChildItem);
if (child != null)
{
child.IsSelected = true;
@@ -239,59 +256,71 @@ namespace FileTime.Avalonia.Application
catch { }
}
private async Task RunFromCode(Func<Task> task)
{
_updateFromCode = true;
try
{
await task();
}
catch
{
_updateFromCode = false;
throw;
}
}
public async Task Open()
{
if (ChildContainer != null)
{
await Tab.Open();
await UpdateCurrentSelectedItem();
await RunFromCode(Tab.Open);
}
}
public async Task GoUp()
{
await Tab.GoUp();
await UpdateCurrentSelectedItem();
await RunFromCode(Tab.GoUp);
}
public async Task MoveCursorDown()
{
await Tab.SelectNextItem();
await RunFromCode(async () => await Tab.SelectNextItem());
}
public async Task MoveCursorDownPage()
{
await Tab.SelectNextItem(10);
await RunFromCode(async () => await Tab.SelectNextItem(10));
}
public async Task MoveCursorUp()
{
await Tab.SelectPreviousItem();
await RunFromCode(async () => await Tab.SelectPreviousItem());
}
public async Task MoveCursorUpPage()
{
await Tab.SelectPreviousItem(10);
await RunFromCode(async () => await Tab.SelectPreviousItem(10));
}
public async Task MoveCursorToFirst()
{
await Tab.SelectFirstItem();
await RunFromCode(Tab.SelectFirstItem);
}
public async Task MoveCursorToLast()
{
await Tab.SelectLastItem();
await RunFromCode(Tab.SelectLastItem);
}
public async Task GotToProvider()
{
await Tab.GoToProvider();
await RunFromCode(Tab.GoToProvider);
}
public async Task GotToRoot()
{
await Tab.GoToRoot();
await RunFromCode(Tab.GoToRoot);
}
public async Task GotToHome()
@@ -300,28 +329,42 @@ namespace FileTime.Avalonia.Application
var resolvedPath = await LocalContentProvider.GetByPath(path);
if (resolvedPath is IContainer homeFolder)
{
await Tab.OpenContainer(homeFolder);
await OpenContainer(homeFolder);
}
}
public async Task CreateContainer(string name)
{
(await Tab.GetCurrentLocation())?.CreateContainer(name);
await RunFromCode(async () =>
{
var currentLocation = await Tab.GetCurrentLocation();
if (currentLocation != null)
{
await currentLocation.CreateContainer(name);
}
});
}
public async Task CreateElement(string name)
{
(await Tab.GetCurrentLocation())?.CreateElement(name);
await RunFromCode(async () =>
{
var currentLocation = await Tab.GetCurrentLocation();
if (currentLocation != null)
{
await currentLocation.CreateElement(name);
}
});
}
public async Task OpenContainer(IContainer container)
{
await Tab.OpenContainer(container);
await RunFromCode(async () => await Tab.OpenContainer(container));
}
public async Task MarkCurrentItem()
{
await _tabState.MakrCurrentItem();
await _tabState.MarkCurrentItem();
}
public async Task UpdateMarkedItems(ContainerViewModel containerViewModel, CancellationToken token = default)

View File

@@ -42,11 +42,16 @@ namespace FileTime.Avalonia.Converters
else if (value is double valueDouble && (parameter is double parameterDouble || double.TryParse(parameter?.ToString(), out parameterDouble))) return valueDouble != parameterDouble;
return value != parameter;
}
if (ComparisonCondition == ComparisonCondition.Equal)
else if (ComparisonCondition == ComparisonCondition.Equal)
{
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?.GetType().IsEnum ?? false && Enum.TryParse(value.GetType(), parameter?.ToString(), out var _)) return value.ToString() == parameter?.ToString();
else if (value?.GetType().IsEnum ?? false && Enum.TryParse(value.GetType(), parameter?.ToString(), out var _))
{
var s1 = value.ToString();
var s2 = parameter?.ToString();
return s1 == s2;
}
}
return value == parameter;

View File

@@ -0,0 +1,17 @@
using System;
using System.Globalization;
using Avalonia.Data.Converters;
using FileTime.Core.Models;
namespace FileTime.Avalonia.Converters
{
public class IsElementConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) => value is IElement;
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,21 +1,20 @@
using FileTime.Core.Interactions;
using System;
using System.Collections.Generic;
using System.Text;
namespace FileTime.Avalonia.Misc
{
public class InputElementWrapper
{
public InputElement InputElement { get; }
public string Value { get; set; }
public char? PasswordChar { get; set; }
public InputElementWrapper(InputElement inputElement, string? defaultValue = null)
{
InputElement = inputElement;
Value = defaultValue ?? "";
PasswordChar = inputElement.InputType == InputType.Password ? '*' : null;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace FileTime.Avalonia.Models
{
public enum ElementPreviewMode
{
Unknown,
Text,
Empty
}
}

View File

@@ -60,6 +60,12 @@ namespace FileTime.Avalonia
{
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
#if DEBUG
catch
{
throw;
}
#else
catch (Exception e)
{
var message = $"Ciritcal error cought in {nameof(Program)}";
@@ -79,6 +85,7 @@ namespace FileTime.Avalonia
using var streamWriter = new StreamWriter(fileWriter);
streamWriter.WriteLine(DateTime.Now.ToString() + ": " + message + "\n" + e.ToString() + "\n\n");
}
#endif
}
// Avalonia configuration, don't remove; also used by visual designer.

View File

@@ -133,12 +133,13 @@ namespace FileTime.Avalonia.ViewModels
public async Task Init(bool initializeChildren = true, CancellationToken token = default)
{
await Refresh(initializeChildren, token);
if (_isInitialized) return;
await Refresh(initializeChildren, token: token);
}
private async Task Container_Refreshed(object? sender, AsyncEventArgs e, CancellationToken token = default)
{
await Refresh(false, token);
await Refresh(false, false, token);
}
[Obsolete($"Use the parametrizable version of {nameof(Refresh)}.")]
@@ -146,7 +147,7 @@ namespace FileTime.Avalonia.ViewModels
{
await Refresh(true);
}
private async Task Refresh(bool initializeChildren, CancellationToken token = default)
private async Task Refresh(bool initializeChildren, bool alloweReuse = true, CancellationToken token = default)
{
if (_isRefreshing) return;
@@ -157,18 +158,13 @@ namespace FileTime.Avalonia.ViewModels
{
_isRefreshing = true;
var containers = (await _container.GetContainers())!.Select(c => AdoptOrReuseOrCreateItem(c, (c2) => new ContainerViewModel(_newItemProcessor, this, c2, ItemNameConverterService))).ToList();
var elements = (await _container.GetElements())!.Select(e => AdoptOrReuseOrCreateItem(e, (e2) => new ElementViewModel(e2, this, ItemNameConverterService))).ToList();
var containers = (await _container.GetContainers())!.Select(c => AdoptOrReuseOrCreateItem(c, alloweReuse , (c2) => new ContainerViewModel(_newItemProcessor, this, c2, ItemNameConverterService))).ToList();
var elements = (await _container.GetElements())!.Select(e => AdoptOrReuseOrCreateItem(e, alloweReuse , (e2) => new ElementViewModel(e2, this, ItemNameConverterService))).ToList();
if (token.IsCancellationRequested) return;
Exceptions = new List<Exception>(_container.Exceptions);
foreach (var containerToRemove in _containers.Except(containers))
{
containerToRemove?.Dispose();
}
if (initializeChildren)
{
foreach (var container in containers)
@@ -178,14 +174,53 @@ namespace FileTime.Avalonia.ViewModels
}
}
for (var i = 0; i < _items.Count; i++)
/*var containersToAdd = containers.Except(_containers).ToList();
var containersToRemove = _containers.Except(containers).ToList();
var elementsToAdd = elements.Except(_elements).ToList();
var elementsToRemove = _elements.Except(elements).ToList();
foreach (var containerToRemove in containersToRemove)
{
_items[i].IsAlternative = i % 2 == 1;
Containers.Remove(containerToRemove);
Items.Remove(containerToRemove);
containerToRemove?.Dispose();
}
foreach (var elementToRemove in elementsToRemove)
{
Elements.Remove(elementToRemove);
Items.Remove(elementToRemove);
}
foreach (var containerToAdd in containersToAdd)
{
Containers.Insert(GetNewItemPosition(containerToAdd, Containers), containerToAdd);
Items.Insert(GetNewItemPosition(containerToAdd, Items), containerToAdd);
}
foreach (var elementToAdd in elementsToAdd)
{
Elements.Insert(GetNewItemPosition(elementToAdd, Elements), elementToAdd);
Items.Insert(GetNewItemPosition(elementToAdd, Items), elementToAdd);
}*/
var containersToRemove = _containers.Except(containers).ToList();
foreach (var containerToRemove in containersToRemove)
{
containerToRemove?.Dispose();
}
Containers = new ObservableCollection<ContainerViewModel>(containers);
Elements = new ObservableCollection<ElementViewModel>(elements);
Items = new ObservableCollection<IItemViewModel>(containers.Cast<IItemViewModel>().Concat(elements));
for (var i = 0; i < Items.Count; i++)
{
Items[i].IsAlternative = i % 2 == 1;
}
}
catch (Exception e)
{
@@ -197,13 +232,31 @@ namespace FileTime.Avalonia.ViewModels
_isRefreshing = false;
}
private TResult AdoptOrReuseOrCreateItem<T, TResult>(T item, Func<T, TResult> generator) where T : class, IItem
private int GetNewItemPosition<TItem, T>(TItem itemToAdd, IList<T> items) where TItem : IItemViewModel where T : IItemViewModel
{
var i = 0;
for (; i < items.Count; i++)
{
var item = items[i];
if (item is TItem && itemToAdd.Item.Name.CompareTo(item.Item.Name) < 0)
{
return i - 1;
}
}
return i;
}
private TResult AdoptOrReuseOrCreateItem<T, TResult>(T item, bool allowResuse, Func<T, TResult> generator) where T : class, IItem
{
var itemToAdopt = ChildrenToAdopt.Find(i => i.Item == item);
if (itemToAdopt is TResult itemViewModel) return itemViewModel;
if (allowResuse)
{
var existingViewModel = _items?.FirstOrDefault(i => i.Item == item);
if (existingViewModel is TResult itemViewModelToReuse) return itemViewModelToReuse;
}
return generator(item);
}
@@ -221,26 +274,26 @@ namespace FileTime.Avalonia.ViewModels
}
}
_containers = new ObservableCollection<ContainerViewModel>();
_elements = new ObservableCollection<ElementViewModel>();
_items = new ObservableCollection<IItemViewModel>();
_containers.Clear();
_elements.Clear();
_items.Clear();
}
public async Task<ObservableCollection<ContainerViewModel>> GetContainers(CancellationToken token = default)
{
if (!_isInitialized) await Task.Run(async () => await Refresh(false, token), token);
if (!_isInitialized) await Task.Run(async () => await Refresh(false, token: token), token);
return _containers;
}
public async Task<ObservableCollection<ElementViewModel>> GetElements(CancellationToken token = default)
{
if (!_isInitialized) await Task.Run(async () => await Refresh(false, token), token);
if (!_isInitialized) await Task.Run(async () => await Refresh(false, token: token), token);
return _elements;
}
public async Task<ObservableCollection<IItemViewModel>> GetItems(CancellationToken token = default)
{
if (!_isInitialized) await Task.Run(async () => await Refresh(false, token), token);
if (!_isInitialized) await Task.Run(async () => await Refresh(false, token: token), token);
return _items;
}

View File

@@ -0,0 +1,46 @@
using FileTime.Avalonia.Models;
using FileTime.Core.Models;
using MvvmGen;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace FileTime.Avalonia.ViewModels
{
[ViewModel]
public partial class ElementPreviewViewModel
{
private const int MAXTEXTPREVIEWSIZE = 1024 * 1024;
[Property]
private IElement? _element;
[Property]
private string? _textContent;
[Property]
private ElementPreviewMode? _mode;
public async Task Init(IElement element, CancellationToken token = default)
{
Element = element;
var elementSize = await element.GetElementSize(token);
if (elementSize == 0)
{
Mode = ElementPreviewMode.Empty;
}
else if (elementSize < MAXTEXTPREVIEWSIZE)
{
TextContent = await element.GetContent();
Mode = ElementPreviewMode.Text;
}
else
{
Mode = ElementPreviewMode.Unknown;
}
}
}
}

View File

@@ -74,10 +74,10 @@ namespace FileTime.Avalonia.ViewModels
private string _messageBoxText;
[Property]
private ObservableCollection<string> _popupTexts = new ObservableCollection<string>();
private ObservableCollection<string> _popupTexts = new();
[Property]
private bool _showAllShortcut;
private bool _isAllShortcutVisible;
[Property]
private List<CommandBinding> _allShortcut;
@@ -127,7 +127,7 @@ namespace FileTime.Avalonia.ViewModels
var driveInfos = new List<RootDriveInfo>();
var drives = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Fixed)
: DriveInfo.GetDrives().Where(d =>
: DriveInfo.GetDrives().Where(d =>
d.DriveType == DriveType.Fixed
&& d.DriveFormat != "pstorefs"
&& d.DriveFormat != "bpf_fs"
@@ -716,9 +716,58 @@ namespace FileTime.Avalonia.ViewModels
}
}
private Task ShowAllShortcut2()
private Task ShowAllShortcut()
{
ShowAllShortcut = true;
IsAllShortcutVisible = true;
return Task.CompletedTask;
}
private Task RunCommandInContainer()
{
var handler = () =>
{
if (Inputs != null)
{
var input = Inputs[0].Value;
string? path = null;
string? arguments = null;
if (input.StartsWith("\""))
{
var pathEnd = input.IndexOf('\"', 1);
path = input.Substring(1, pathEnd);
arguments = input.Substring(pathEnd + 1).Trim();
}
else
{
var inputParts = input.Split(' ');
path = inputParts[0];
arguments = inputParts.Length > 1 ? string.Join(' ', inputParts[1..]).Trim() : null;
}
if (!string.IsNullOrWhiteSpace(path))
{
var process = new Process();
process.StartInfo.FileName = path;
if (!string.IsNullOrWhiteSpace(arguments))
{
process.StartInfo.Arguments = arguments;
}
if (AppState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
{
process.StartInfo.WorkingDirectory = localFolder.Directory.FullName;
}
process.Start();
}
}
return Task.CompletedTask;
};
ReadInputs(new List<Core.Interactions.InputElement>() { new Core.Interactions.InputElement("Command", InputType.Text) }, handler);
return Task.CompletedTask;
}
@@ -757,14 +806,14 @@ namespace FileTime.Avalonia.ViewModels
_inputHandler = null;
}
public async Task<bool> ProcessKeyDown(Key key, KeyModifiers keyModifiers)
public async void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled)
{
if (key == Key.LeftAlt
|| key == Key.RightAlt
|| key == Key.LeftShift
|| key == Key.RightShift
|| key == Key.LeftCtrl
|| key == Key.RightCtrl) return false;
|| key == Key.RightCtrl) return;
NoCommandFound = false;
@@ -782,12 +831,14 @@ namespace FileTime.Avalonia.ViewModels
if (key == Key.Escape)
{
ShowAllShortcut = false;
IsAllShortcutVisible = false;
_previousKeys.Clear();
PossibleCommands = new();
setHandled(true);
}
else if (selectedCommandBinding != null)
{
setHandled(true);
await selectedCommandBinding.InvokeAsync();
_previousKeys.Clear();
PossibleCommands = new();
@@ -796,10 +847,11 @@ namespace FileTime.Avalonia.ViewModels
{
_previousKeys.Clear();
PossibleCommands = new();
return false;
return;
}
else if (_previousKeys.Count == 2)
{
setHandled(true);
NoCommandFound = true;
_previousKeys.Clear();
PossibleCommands = new();
@@ -817,6 +869,7 @@ namespace FileTime.Avalonia.ViewModels
{
PossibleCommands = possibleCommands;
}
setHandled(true);
}
}
else
@@ -826,9 +879,10 @@ namespace FileTime.Avalonia.ViewModels
if (key == Key.Escape)
{
if (ShowAllShortcut)
setHandled(true);
if (IsAllShortcutVisible)
{
ShowAllShortcut = false;
IsAllShortcutVisible = false;
}
else
{
@@ -839,12 +893,14 @@ namespace FileTime.Avalonia.ViewModels
{
if (AppState.RapidTravelText.Length > 0)
{
setHandled(true);
AppState.RapidTravelText = AppState.RapidTravelText.Substring(0, AppState.RapidTravelText.Length - 1);
updateRapidTravelFilter = true;
}
}
else if (keyString.Length == 1)
{
setHandled(true);
AppState.RapidTravelText += keyString.ToString().ToLower();
updateRapidTravelFilter = true;
}
@@ -854,12 +910,8 @@ namespace FileTime.Avalonia.ViewModels
var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, currentKeyAsList));
if (selectedCommandBinding != null)
{
setHandled(true);
await selectedCommandBinding.InvokeAsync();
return true;
}
else
{
return false;
}
}
@@ -895,13 +947,6 @@ namespace FileTime.Avalonia.ViewModels
}
}
}
return true;
}
public Task<bool> ProcessKeyUp(Key key, KeyModifiers keyModifiers)
{
return Task.FromResult(false);
}
private void ReadInputs(List<Core.Interactions.InputElement> inputs, Action inputHandler)
@@ -1144,7 +1189,12 @@ namespace FileTime.Avalonia.ViewModels
"show all shortcut",
FileTime.App.Core.Command.Commands.Dummy,
new KeyWithModifiers[] { new KeyWithModifiers(Key.F1) },
ShowAllShortcut2),
ShowAllShortcut),
new CommandBinding(
"run command",
FileTime.App.Core.Command.Commands.Dummy,
new KeyWithModifiers[] { new KeyWithModifiers(Key.D4, shift: true) },
RunCommandInContainer),
//TODO REMOVE
new CommandBinding(
"open in default file browser",

View File

@@ -6,12 +6,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:FileTime.Avalonia.ViewModels"
xmlns:local="using:FileTime.Avalonia.Views"
xmlns:models="using:FileTime.Avalonia.Models"
Title="FileTime"
d:DesignHeight="450"
d:DesignWidth="800"
Icon="/Assets/filetime.ico"
InputElement.KeyDown="OnKeyDown"
InputElement.KeyUp="OnKeyUp"
TransparencyLevelHint="Blur"
Background="Transparent"
ExtendClientAreaToDecorationsHint="True"
@@ -100,7 +100,7 @@
Margin="5,0,0,0"
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="1"
Grid.Row="1"
MinWidth="100"
HorizontalAlignment="Stretch"
Maximum="100"
@@ -269,123 +269,65 @@
VerticalAlignment="Stretch"
Fill="{DynamicResource ContentSeparatorBrush}" />
<Grid Grid.Column="4" IsVisible="{Binding AppState.SelectedTab.ChildContainer,Converter={StaticResource IsNotNullConverter}}">
<ListBox
Classes="ContentListView"
IsEnabled="False"
x:Name="ChildItems"
Items="{Binding AppState.SelectedTab.ChildContainer.Items}"
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Items.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:ItemView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Column="4">
<Grid IsVisible="{Binding AppState.SelectedTab.ChildContainer,Converter={StaticResource IsNotNullConverter}}">
<ListBox
Classes="ContentListView"
IsEnabled="False"
x:Name="ChildItems"
Items="{Binding AppState.SelectedTab.ChildContainer.Items}"
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Items.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:ItemView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Items.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
<TextBlock
x:Name="ChildEmpty"
Margin="10"
HorizontalAlignment="Center"
FontWeight="Bold"
Foreground="{DynamicResource ErrorBrush}"
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
Empty
</TextBlock>
<Grid
RowDefinitions="Auto, Auto"
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
<Grid IsVisible="{Binding AppState.SelectedTab.ChildContainer.Items.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
<TextBlock
Margin="0,0,0,10"
x:Name="ChildEmpty"
Margin="10"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Text="There were some errors while opening container."
Foreground="{DynamicResource ErrorBrush}" />
FontWeight="Bold"
Foreground="{DynamicResource ErrorBrush}"
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
Empty
</TextBlock>
<ItemsRepeater Grid.Row="1" Items="{Binding AppState.SelectedTab.ChildContainer.Exceptions}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding, Converter={StaticResource ExceptionToStringConverter}}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsVisible="{Binding Inputs, Converter={StaticResource IsNotNullConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl
x:Name="InputList"
Items="{Binding Inputs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid MinWidth="400">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid
RowDefinitions="Auto, Auto"
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding InputElement.Text}" />
<TextBox
AttachedToVisualTree="InputText_AttachedToVisualTree"
Grid.Column="1"
GotFocus="InputText_GotFocus"
LostFocus="InputText_LostFocus"
KeyDown="InputText_KeyDown"
Text="{Binding Value, Mode=TwoWay}" />
Margin="0,0,0,10"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Text="There were some errors while opening container."
Foreground="{DynamicResource ErrorBrush}" />
<ItemsRepeater Grid.Row="1" Items="{Binding AppState.SelectedTab.ChildContainer.Exceptions}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding, Converter={StaticResource ExceptionToStringConverter}}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel
Grid.Row="1"
Orientation="Horizontal">
<Button
Command="{Binding ProcessInputsCommand}"
Content="Ok" />
<Button
Command="{Binding CancelInputsCommand}"
Content="Cancel" />
</StackPanel>
</Grid>
</Grid>
</Grid>
<Grid
HorizontalAlignment="Center"
VerticalAlignment="Center"
IsVisible="{Binding MessageBoxText, Converter={StaticResource IsNotNullConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding MessageBoxText}"/>
<StackPanel
Grid.Row="1"
Orientation="Horizontal">
<Button
Command="{Binding ProcessMessageBoxCommand}"
Content="Yes" />
<Button
Command="{Binding CancelMessageBoxCommand}"
Content="No" />
</StackPanel>
<Grid IsVisible="{Binding AppState.SelectedTab.ElementPreview, Converter={StaticResource IsNotNullConverter}}">
<TextBlock HorizontalAlignment="Center" Text="Don't know how to preview this file" IsVisible="{Binding AppState.SelectedTab.ElementPreview.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static models:ElementPreviewMode.Unknown}}"/>
<TextBlock HorizontalAlignment="Center" Text="Empty" IsVisible="{Binding AppState.SelectedTab.ElementPreview.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static models:ElementPreviewMode.Empty}}"/>
<ScrollViewer IsVisible="{Binding AppState.SelectedTab.ElementPreview.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static models:ElementPreviewMode.Text}}">
<TextBox
IsReadOnly="True"
Text="{Binding AppState.SelectedTab.ElementPreview.TextContent}" />
</ScrollViewer>
</Grid>
</Grid>
</Grid>
<ItemsRepeater Items="{Binding PopupTexts}" Margin="0,0,0,20" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsVisible="{Binding PopupTexts.Count,Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
@@ -496,7 +438,99 @@
</Grid>
</Grid>
<Border Background="{DynamicResource TransparentContainerBackgroundBrush}" Margin="20" HorizontalAlignment="Center" IsVisible="{Binding ShowAllShortcut}">
<Border
Background="{DynamicResource BarelyTransparentBackgroundColor}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsVisible="{Binding Inputs, Converter={StaticResource IsNotNullConverter}}">
<Border
Background="{DynamicResource ContainerBackgroundBrush}"
Padding="20"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid RowDefinitions="Auto,Auto">
<ItemsControl
x:Name="InputList"
Items="{Binding Inputs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid MinWidth="500" ColumnDefinitions="250,*" Margin="10,5">
<TextBlock
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding InputElement.Text}" />
<TextBox
PasswordChar="{Binding PasswordChar}"
AttachedToVisualTree="InputText_AttachedToVisualTree"
IsTabStop="True"
Grid.Column="1"
GotFocus="InputText_GotFocus"
LostFocus="InputText_LostFocus"
KeyDown="InputText_KeyDown"
Text="{Binding Value, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel
Grid.Row="1"
Orientation="Horizontal"
Margin="0,10,0,0">
<Button
HorizontalContentAlignment="Center"
Width="80"
Command="{Binding ProcessInputsCommand}"
Content="Ok" />
<Button
HorizontalContentAlignment="Center"
Width="80"
Margin="10,0,0,0"
Command="{Binding CancelInputsCommand}"
Content="Cancel" />
</StackPanel>
</Grid>
</Border>
</Border>
<Border
Background="{DynamicResource BarelyTransparentBackgroundColor}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
IsVisible="{Binding MessageBoxText, Converter={StaticResource IsNotNullConverter}}">
<Border
Background="{DynamicResource ContainerBackgroundBrush}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Padding="20">
<Grid RowDefinitions="Auto,Auto">
<TextBlock Text="{Binding MessageBoxText}"/>
<StackPanel
Grid.Row="1"
Orientation="Horizontal"
Margin="0,10,0,0">
<Button
HorizontalContentAlignment="Center"
Width="80"
Command="{Binding ProcessMessageBoxCommand}"
Content="Yes" />
<Button
HorizontalContentAlignment="Center"
Width="80"
Margin="10,0,0,0"
Command="{Binding CancelMessageBoxCommand}"
Content="No" />
</StackPanel>
</Grid>
</Border>
</Border>
<Border
Background="{DynamicResource TransparentContainerBackgroundBrush}"
Margin="20"
HorizontalAlignment="Center"
IsVisible="{Binding IsAllShortcutVisible}">
<Grid RowDefinitions="Auto, *" Margin="30,10">
<TextBlock Text="Shortcuts" Margin="0,0,0,20"/>
<ScrollViewer

View File

@@ -45,19 +45,11 @@ namespace FileTime.Avalonia.Views
AvaloniaXamlLoader.Load(this);
}
public async void OnKeyDown(object sender, KeyEventArgs e)
public void OnKeyDown(object sender, KeyEventArgs e)
{
if (_inputElementWrapper == null)
{
e.Handled = e.Handled || await ViewModel!.ProcessKeyDown(e.Key, e.KeyModifiers);
}
}
public async void OnKeyUp(object sender, KeyEventArgs e)
{
if (_inputElementWrapper == null)
{
e.Handled = e.Handled || await ViewModel!.ProcessKeyUp(e.Key, e.KeyModifiers);
ViewModel!.ProcessKeyDown(e.Key, e.KeyModifiers, h => e.Handled = h);
}
}
@@ -87,7 +79,7 @@ namespace FileTime.Avalonia.Views
private void InputText_LostFocus(object sender, RoutedEventArgs e)
{
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper inputElementWrapper)
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper)
{
_inputElementWrapper = null;
}