added keyboard navigation for selected images -> TOOD: allow visual keyboardnavigation when photo is not maximized
This commit is contained in:
@@ -91,10 +91,29 @@ public partial class MainWindowViewModel : ViewModelBase
|
|||||||
await SelectedPhoto.LoadFullImage();
|
await SelectedPhoto.LoadFullImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectedPhotoClicked()
|
public void ResetSelectedPhoto()
|
||||||
{
|
{
|
||||||
if (SelectedPhoto is null) return;
|
if (SelectedPhoto is null) return;
|
||||||
SelectedPhoto.FullImage = null;
|
SelectedPhoto.FullImage = null;
|
||||||
SelectedPhoto = null;
|
SelectedPhoto = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task TryFocusImage(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= Photos.Count ) return;
|
||||||
|
// if(SelectedPhoto != null) ResetSelectedPhoto();
|
||||||
|
SelectedPhoto = Photos[index];
|
||||||
|
await SelectedPhoto.LoadFullImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnfocusPhoto() => ResetSelectedPhoto();
|
||||||
|
|
||||||
|
public bool IsPhotoFocused() => SelectedPhoto != null;
|
||||||
|
|
||||||
|
public int GetImageIndex(Image i)
|
||||||
|
{
|
||||||
|
var p = Photos.FirstOrDefault(x => x.PreviewImage == i.Source);
|
||||||
|
if (p is null) return -1;
|
||||||
|
return Photos.IndexOf(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,9 @@
|
|||||||
ExtendClientAreaChromeHints="NoChrome"
|
ExtendClientAreaChromeHints="NoChrome"
|
||||||
TransparencyLevelHint="AcrylicBlur"
|
TransparencyLevelHint="AcrylicBlur"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ExtendClientAreaToDecorationsHint="True">
|
ExtendClientAreaToDecorationsHint="True"
|
||||||
|
Focusable="True"
|
||||||
|
KeyDown="OnKeyDownHandler">
|
||||||
|
|
||||||
<Design.DataContext>
|
<Design.DataContext>
|
||||||
<vm:MainWindowViewModel/>
|
<vm:MainWindowViewModel/>
|
||||||
@@ -115,7 +117,8 @@
|
|||||||
<ItemsRepeater ItemsSource="{Binding Photos}"
|
<ItemsRepeater ItemsSource="{Binding Photos}"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
ClipToBounds="False">
|
ClipToBounds="False"
|
||||||
|
IsTabStop="True">
|
||||||
<ItemsRepeater.Layout>
|
<ItemsRepeater.Layout>
|
||||||
<UniformGridLayout MinItemWidth="220"
|
<UniformGridLayout MinItemWidth="220"
|
||||||
MinItemHeight="290"
|
MinItemHeight="290"
|
||||||
@@ -150,7 +153,9 @@
|
|||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Background="#14000000">
|
Background="#14000000">
|
||||||
<Image Source="{Binding PreviewImage}"
|
<Image Source="{Binding PreviewImage}"
|
||||||
Stretch="UniformToFill"/>
|
Stretch="UniformToFill"
|
||||||
|
PointerEntered="PointerEnteredPhotoHandler"
|
||||||
|
/>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<TextBlock Text="{Binding DisplayName}"
|
<TextBlock Text="{Binding DisplayName}"
|
||||||
@@ -184,14 +189,15 @@
|
|||||||
<TransitioningContentControl Grid.Row="0"
|
<TransitioningContentControl Grid.Row="0"
|
||||||
Grid.RowSpan="2"
|
Grid.RowSpan="2"
|
||||||
Content="{Binding SelectedPhoto}"
|
Content="{Binding SelectedPhoto}"
|
||||||
ZIndex="50">
|
ZIndex="50"
|
||||||
|
>
|
||||||
<TransitioningContentControl.PageTransition>
|
<TransitioningContentControl.PageTransition>
|
||||||
<CrossFade Duration="0:0:0.18"/>
|
<CrossFade Duration="0:0:0.18"/>
|
||||||
</TransitioningContentControl.PageTransition>
|
</TransitioningContentControl.PageTransition>
|
||||||
|
|
||||||
<i:Interaction.Behaviors>
|
<i:Interaction.Behaviors>
|
||||||
<ic:EventTriggerBehavior EventName="PointerReleased">
|
<ic:EventTriggerBehavior EventName="PointerReleased">
|
||||||
<ic:InvokeCommandAction Command="{Binding Path=DataContext.SelectedPhotoClicked, ElementName=Root}"/>
|
<ic:InvokeCommandAction Command="{Binding Path=DataContext.ResetSelectedPhoto, ElementName=Root}"/>
|
||||||
</ic:EventTriggerBehavior>
|
</ic:EventTriggerBehavior>
|
||||||
</i:Interaction.Behaviors>
|
</i:Interaction.Behaviors>
|
||||||
|
|
||||||
@@ -211,7 +217,7 @@
|
|||||||
Stretch="Uniform">
|
Stretch="Uniform">
|
||||||
<i:Interaction.Behaviors>
|
<i:Interaction.Behaviors>
|
||||||
<ic:EventTriggerBehavior EventName="PointerReleased">
|
<ic:EventTriggerBehavior EventName="PointerReleased">
|
||||||
<ic:InvokeCommandAction Command="{Binding Path=DataContext.SelectedPhotoClicked, ElementName=Root}"/>
|
<ic:InvokeCommandAction Command="{Binding Path=DataContext.ResetSelectedPhoto, ElementName=Root}"/>
|
||||||
</ic:EventTriggerBehavior>
|
</ic:EventTriggerBehavior>
|
||||||
</i:Interaction.Behaviors>
|
</i:Interaction.Behaviors>
|
||||||
</Image>
|
</Image>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Xaml.Interactions.DragAndDrop;
|
using Avalonia.Xaml.Interactions.DragAndDrop;
|
||||||
@@ -9,6 +10,7 @@ namespace Photos.Views;
|
|||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private IFolderPickerService _folderPickerService;
|
private IFolderPickerService _folderPickerService;
|
||||||
|
private int _currentImageIndex = 0;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
@@ -21,4 +23,60 @@ public partial class MainWindow : Window
|
|||||||
{
|
{
|
||||||
(DataContext as MainWindowViewModel)?.WindowDropHandler(e);
|
(DataContext as MainWindowViewModel)?.WindowDropHandler(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnKeyDownHandler(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is not MainWindowViewModel vm) return;
|
||||||
|
|
||||||
|
async Task HandleEnter()
|
||||||
|
{
|
||||||
|
if (vm.IsPhotoFocused()) vm.UnfocusPhoto();
|
||||||
|
else await vm.TryFocusImage(_currentImageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleEscape()
|
||||||
|
{
|
||||||
|
vm.UnfocusPhoto();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task HandleArrowKey()
|
||||||
|
{
|
||||||
|
if(vm.IsPhotoFocused()) await vm.TryFocusImage(_currentImageIndex);
|
||||||
|
// TODO: move basic selection
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.Enter:
|
||||||
|
HandleEnter().GetAwaiter();
|
||||||
|
break;
|
||||||
|
case Key.Escape:
|
||||||
|
HandleEscape();
|
||||||
|
break;
|
||||||
|
case Key.Down:
|
||||||
|
break;
|
||||||
|
case Key.Left:
|
||||||
|
if (_currentImageIndex > 0)
|
||||||
|
{
|
||||||
|
_currentImageIndex--;
|
||||||
|
HandleArrowKey().GetAwaiter();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Key.Right:
|
||||||
|
if (_currentImageIndex < vm.Photos.Count - 1)
|
||||||
|
{
|
||||||
|
_currentImageIndex++;
|
||||||
|
HandleArrowKey().GetAwaiter();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PointerEnteredPhotoHandler(object sender, PointerEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is not Image i || DataContext is not MainWindowViewModel vm) return;
|
||||||
|
var idx = vm.GetImageIndex(i);
|
||||||
|
if (idx == -1) return;
|
||||||
|
_currentImageIndex = idx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user