Skip to content

Commit

Permalink
Implemented AnimatedPopUp for dialog view. New option to ask for conf…
Browse files Browse the repository at this point in the history
…irmation upon exit and confirmation dialog when permanently deleting file #171
  • Loading branch information
Ruben2776 committed Jan 1, 2025
1 parent c14c58d commit 718a8cd
Show file tree
Hide file tree
Showing 38 changed files with 610 additions and 45 deletions.
3 changes: 2 additions & 1 deletion src/PicView.Avalonia.MacOS/macOSKeybindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ public static class MacOsKeybindings
"Cmd+V": "Paste",
"Cmd+P": "Print",
"Alt+Z": "ToggleInterface",
"Delete": "DeleteFile"
"Delete": "DeleteFile",
"Shift+Delete": "DeleteFilePermanently"
}
""";
}
3 changes: 2 additions & 1 deletion src/PicView.Avalonia.Win32/WindowsKeybindings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ public static class WindowsKeybindings
"Ctrl+V": "Paste",
"Ctrl+P": "Print",
"Alt+Z": "ToggleInterface",
"Delete": "DeleteFile"
"Delete": "DeleteFile",
"Shift+Delete": "DeleteFilePermanently"
}
""";
}
52 changes: 52 additions & 0 deletions src/PicView.Avalonia/Animations/AnimationsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,57 @@ public static Animation ZoomAnimation(double initialZoom, double zoomValue, doub
}
};
}

public static Animation CenteringAnimation(double fromX, double fromY, double toX, double toY, double speed)
{
return CenteringAnimation(fromX, fromY, toX, toY, TimeSpan.FromSeconds(speed));
}

public static Animation CenteringAnimation(double fromX, double fromY, double toX, double toY, TimeSpan duration)
{
return new Animation
{
Duration = duration,
Easing = new SplineEasing(), // Using SplineEasing for smooth motion
FillMode = FillMode.Forward,
Children =
{
new KeyFrame
{
Setters =
{
new Setter
{
Property = TranslateTransform.XProperty,
Value = fromX
},
new Setter
{
Property = TranslateTransform.YProperty,
Value = fromY
}
},
Cue = new Cue(0d)
},
new KeyFrame
{
Setters =
{
new Setter
{
Property = TranslateTransform.XProperty,
Value = toX
},
new Setter
{
Property = TranslateTransform.YProperty,
Value = toY
}
},
Cue = new Cue(1d)
},
}
};
}
}

81 changes: 81 additions & 0 deletions src/PicView.Avalonia/CustomControls/AnimatedPopUp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using PicView.Avalonia.Animations;
using PicView.Avalonia.UI;

namespace PicView.Avalonia.CustomControls;

[TemplatePart("PART_Overlay", typeof(Panel))]
[TemplatePart("PART_Border", typeof(Border))]
public class AnimatedPopUp : ContentControl
{
private Panel? _partOverlay;
private Border? _partBorder;

public static readonly AvaloniaProperty<bool> ClickingOutSideClosesProperty =
AvaloniaProperty.Register<CopyButton, bool>(nameof(ClickingOutSideCloses));

public bool ClickingOutSideCloses
{
get => (bool)GetValue(ClickingOutSideClosesProperty)!;
set => SetValue(ClickingOutSideClosesProperty, value);
}

protected override Type StyleKeyOverride => typeof(AnimatedPopUp);

protected AnimatedPopUp()
{
Loaded += async delegate
{
await AnimatedOpening();
};
}

protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_partOverlay = e.NameScope.Find<Panel>("PART_Overlay");
_partBorder = e.NameScope.Find<Border>("PART_Border");

_partOverlay.Opacity = 0;
_partBorder.Opacity = 0;

// Handle click outside to close
_partOverlay.PointerPressed += async delegate
{
if (!ClickingOutSideCloses)
{
return;
}
if (!_partBorder.IsPointerOver)
{
await AnimatedClosing();
}
};
}

public async Task AnimatedOpening()
{
UIHelper.IsDialogOpen = true;
var fadeIn = AnimationsHelper.OpacityAnimation(0, 1, 0.3);
var centering = AnimationsHelper.CenteringAnimation(50, 100, 0, 0, 0.3);
await Task.WhenAll(fadeIn.RunAsync(_partOverlay), fadeIn.RunAsync(_partBorder), centering.RunAsync(_partBorder));
}

public async Task AnimatedClosing()
{
UIHelper.IsDialogOpen = false;
var fadeIn = AnimationsHelper.OpacityAnimation(1, 0, 0.3);
var centering = AnimationsHelper.CenteringAnimation(0, 0, 50, 100, 0.3);
await Task.WhenAll(fadeIn.RunAsync(_partOverlay), fadeIn.RunAsync(_partBorder), centering.RunAsync(_partBorder));
UIHelper.GetMainView.MainGrid.Children.Remove(this);
}

public void KeyDownHandler(object? sender, KeyEventArgs e)
{
RaiseEvent(e);
}
}
36 changes: 36 additions & 0 deletions src/PicView.Avalonia/FileSystem/FileManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using PicView.Avalonia.UI;
using PicView.Avalonia.ViewModels;
using PicView.Avalonia.Views.UC.PopUps;
using PicView.Core.FileHandling;
using PicView.Core.Localization;

namespace PicView.Avalonia.FileSystem;

public static class FileManager
{
public static async Task DeleteFile(bool recycle, MainViewModel vm)
{
if (vm.FileInfo is null)
{
return;
}

var errorMsg = string.Empty;

if(!recycle)
{
var prompt = $"{TranslationHelper.GetTranslation("DeleteFilePermanently")}";
var deleteDialog = new DeleteDialog(prompt, vm.FileInfo.FullName);
UIHelper.GetMainView.MainGrid.Children.Add(deleteDialog);
}
else
{
errorMsg = await Task.FromResult(FileDeletionHelper.DeleteFileWithErrorMsg(vm.FileInfo.FullName, recycle));
}

if (!string.IsNullOrEmpty(errorMsg))
{
await TooltipHelper.ShowTooltipMessageAsync(errorMsg, true);
}
}
}
20 changes: 14 additions & 6 deletions src/PicView.Avalonia/Input/MainKeyboardShortcuts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Runtime.InteropServices;
using Avalonia.Input;
using PicView.Avalonia.Crop;
using PicView.Avalonia.CustomControls;
using PicView.Avalonia.UI;
using PicView.Avalonia.Views.UC;

Expand Down Expand Up @@ -73,10 +74,6 @@ public static async Task MainWindow_KeysDownAsync(KeyEventArgs e)
await FunctionsHelper.ShowStartUpMenu();
return;
#endif

case Key.Escape:
await FunctionsHelper.Close().ConfigureAwait(false);
return;

case Key.LeftShift:
case Key.RightShift:
Expand Down Expand Up @@ -126,7 +123,19 @@ public static async Task MainWindow_KeysDownAsync(KeyEventArgs e)

if (CropFunctions.IsCropping)
{
await UIHelper.GetMainView.MainGrid.Children.OfType<CropControl>().First().KeyDownHandler(null,e);
await UIHelper.GetMainView.MainGrid.Children.OfType<CropControl>().FirstOrDefault().KeyDownHandler(null,e);
return;
}

if (UIHelper.IsDialogOpen)
{
UIHelper.GetMainView.MainGrid.Children.OfType<AnimatedPopUp>().FirstOrDefault().KeyDownHandler(null,e);
return;
}

if (e.Key == Key.Escape)
{
await FunctionsHelper.Close().ConfigureAwait(false);
return;
}

Expand All @@ -142,7 +151,6 @@ public static async Task MainWindow_KeysDownAsync(KeyEventArgs e)
}
// Execute the associated action
await func.Invoke().ConfigureAwait(false);
ClearKeyDownModifiers();
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/PicView.Avalonia/PicView.Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@
<DependentUpon>SingleImageResizeView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\UC\PopUps\DeleteDialog.axaml.cs">
<DependentUpon>DeleteDialog.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>


Expand Down
25 changes: 25 additions & 0 deletions src/PicView.Avalonia/PicViewTheme/Controls/AnimatedPopUp.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<ResourceDictionary
x:ClassModifier="internal"
xmlns="https://github.com/avaloniaui"
xmlns:customControls="clr-namespace:PicView.Avalonia.CustomControls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ControlTheme TargetType="customControls:AnimatedPopUp" x:Key="{x:Type customControls:AnimatedPopUp}">
<Setter Property="Template">
<ControlTemplate>
<Panel Background="#A8000000" x:Name="PART_Overlay">
<Border
Background="{DynamicResource MainBackgroundColor}"
BorderBrush="{DynamicResource MainBorderColor}"
BorderThickness="1"
CornerRadius="8"
HorizontalAlignment="Center"
Padding="{TemplateBinding Padding}"
VerticalAlignment="Center"
x:Name="PART_Border">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</Panel>
</ControlTemplate>
</Setter>
</ControlTheme>
</ResourceDictionary>
1 change: 1 addition & 0 deletions src/PicView.Avalonia/PicViewTheme/Index.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ResourceInclude Source="ResourceDictionaries/Variables.axaml" />
<ResourceInclude Source="Icons.axaml" />

<ResourceInclude Source="Controls/AnimatedPopUp.axaml" />
<ResourceInclude Source="Controls/AutoScrollViewer.axaml" />
<ResourceInclude Source="Controls/Border.axaml" />
<ResourceInclude Source="Controls/Button.axaml" />
Expand Down
4 changes: 2 additions & 2 deletions src/PicView.Avalonia/Preloading/Preloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ namespace PicView.Avalonia.Preloading;

public sealed class PreLoader : IAsyncDisposable
{

#if DEBUG

// ReSharper disable once ConvertToConstant.Local
private static readonly bool ShowAddRemove = true;


#endif

private readonly PreLoaderConfig _config = new();

private readonly ConcurrentDictionary<int, PreLoadValue> _preLoadList = new();
Expand Down
44 changes: 12 additions & 32 deletions src/PicView.Avalonia/UI/FunctionsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public static Task<Func<Task>> GetFunctionByName(string functionName)

// File functions
"DeleteFile" => DeleteFile,
"DeleteFilePermanently" => DeleteFilePermanently,
"Rename" => Rename,
"ShowFileProperties" => ShowFileProperties,

Expand Down Expand Up @@ -416,38 +417,11 @@ await Dispatcher.UIThread.InvokeAsync(() =>

public static async Task Close()
{
if (UIHelper.IsAnyMenuOpen(Vm))
{
UIHelper.CloseMenus(Vm);
return;
}

if (CropFunctions.IsCropping)
{
CropFunctions.CloseCropControl(Vm);
return;
}

if (Navigation.Slideshow.IsRunning)
{
Navigation.Slideshow.StopSlideshow(Vm);
return;
}

if (SettingsHelper.Settings.WindowProperties.Fullscreen)
{
await WindowFunctions.MaximizeRestore();
return;
}
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
if (Vm is null)
{
return;
}
await Dispatcher.UIThread.InvokeAsync(() =>
{
// TODO: Make it a setting to close the window
desktop.MainWindow?.Close();
});
await UIHelper.Close(Vm);
}

public static async Task Center()
Expand Down Expand Up @@ -633,12 +607,18 @@ public static async Task DeleteFile()
{
return;
}
var errorMsg = await Task.FromResult(FileDeletionHelper.DeleteFileWithErrorMsg(Vm.FileInfo?.FullName, true));

if (!string.IsNullOrEmpty(errorMsg))
await FileManager.DeleteFile(true, Vm);
}

public static async Task DeleteFilePermanently()
{
if (Vm is null)
{
await TooltipHelper.ShowTooltipMessageAsync(errorMsg, true);
return;
}

await FileManager.DeleteFile(false, Vm);
}

public static async Task Rename()
Expand Down
Loading

0 comments on commit 718a8cd

Please sign in to comment.