Fix blink issue when fast trigering show/hide

This commit is contained in:
DB p 2025-03-06 14:14:25 +09:00
parent 758717848c
commit 4042231fb3
2 changed files with 58 additions and 21 deletions

View file

@ -27,6 +27,9 @@ using DataObject = System.Windows.DataObject;
using System.Windows.Media;
using System.Windows.Interop;
using Windows.Win32;
using Microsoft.VisualBasic.Devices;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using Window = System.Windows.Window;
namespace Flow.Launcher
{
@ -46,6 +49,11 @@ namespace Flow.Launcher
private MediaPlayer animationSoundWMP;
private SoundPlayer animationSoundWPF;
//For Window Animations
private Storyboard clocksb;
private Storyboard iconsb;
private Storyboard windowsb;
#endregion
public MainWindow(Settings settings, MainViewModel mainVM)
@ -476,6 +484,19 @@ namespace Flow.Launcher
isProgressBarStoryboardPaused = true;
}
public void ResetAnimation()
{
// 애니메이션 중지
clocksb?.Stop(ClockPanel);
iconsb?.Stop(SearchIcon);
windowsb?.Stop(FlowMainWindow);
// UI 요소 상태 초기화
ClockPanel.Margin = new Thickness(0, 0, ClockPanel.Margin.Right, 0);
ClockPanel.Opacity = 0;
SearchIcon.Opacity = 0;
}
public void WindowAnimator()
{
if (_animating)
@ -485,11 +506,10 @@ namespace Flow.Launcher
_animating = true;
UpdatePosition();
Storyboard windowsb = new Storyboard();
Storyboard clocksb = new Storyboard();
Storyboard iconsb = new Storyboard();
CircleEase easing = new CircleEase();
easing.EasingMode = EasingMode.EaseInOut;
windowsb = new Storyboard();
clocksb = new Storyboard();
iconsb = new Storyboard();
CircleEase easing = new CircleEase { EasingMode = EasingMode.EaseInOut };
var animationLength = _settings.AnimationSpeed switch
{
@ -501,19 +521,21 @@ namespace Flow.Launcher
var WindowOpacity = new DoubleAnimation
{
From = 0,
From = 1,
To = 1,
Duration = TimeSpan.FromMilliseconds(animationLength * 2 / 3),
FillBehavior = FillBehavior.Stop
};
// 📌 항상 같은 위치에서 시작하도록 `_originalTop`을 사용
var WindowMotion = new DoubleAnimation
{
From = Top,
To = Top,
From = Top + 10, // 원래 위치에서 10px 내려온 후
To = Top, // 다시 원래 위치로 이동
Duration = TimeSpan.FromMilliseconds(animationLength * 2 / 3),
FillBehavior = FillBehavior.Stop
};
var IconMotion = new DoubleAnimation
{
From = 12,
@ -529,16 +551,17 @@ namespace Flow.Launcher
To = 1,
EasingFunction = easing,
Duration = TimeSpan.FromMilliseconds(animationLength),
FillBehavior = FillBehavior.Stop
FillBehavior = FillBehavior.HoldEnd
};
double TargetIconOpacity = SearchIcon.Opacity; // Animation Target Opacity from Style
double TargetIconOpacity = SearchIcon.Opacity;
var IconOpacity = new DoubleAnimation
{
From = 0,
To = TargetIconOpacity,
To = 1,
EasingFunction = easing,
Duration = TimeSpan.FromMilliseconds(animationLength),
FillBehavior = FillBehavior.Stop
FillBehavior = FillBehavior.HoldEnd
};
double right = ClockPanel.Margin.Right;
@ -548,18 +571,29 @@ namespace Flow.Launcher
To = new Thickness(0, 0, right, 0),
EasingFunction = easing,
Duration = TimeSpan.FromMilliseconds(animationLength),
FillBehavior = FillBehavior.Stop
FillBehavior = FillBehavior.HoldEnd
};
// 애니메이션 타겟 설정
Storyboard.SetTargetProperty(ClockOpacity, new PropertyPath(OpacityProperty));
Storyboard.SetTarget(ClockOpacity, ClockPanel);
Storyboard.SetTargetName(thicknessAnimation, "ClockPanel");
Storyboard.SetTargetProperty(thicknessAnimation, new PropertyPath(MarginProperty));
Storyboard.SetTarget(WindowOpacity, this);
Storyboard.SetTargetProperty(WindowOpacity, new PropertyPath(Window.OpacityProperty));
Storyboard.SetTarget(WindowMotion, this);
Storyboard.SetTargetProperty(WindowMotion, new PropertyPath(Window.TopProperty));
Storyboard.SetTarget(IconMotion, SearchIcon);
Storyboard.SetTargetProperty(IconMotion, new PropertyPath(TopProperty));
Storyboard.SetTarget(IconOpacity, SearchIcon);
Storyboard.SetTargetProperty(IconOpacity, new PropertyPath(OpacityProperty));
// 스토리보드에 애니메이션 추가
clocksb.Children.Add(thicknessAnimation);
clocksb.Children.Add(ClockOpacity);
windowsb.Children.Add(WindowOpacity);
@ -569,7 +603,6 @@ namespace Flow.Launcher
windowsb.Completed += (_, _) => _animating = false;
_settings.WindowLeft = Left;
_settings.WindowTop = Top;
isArrowKeyPressed = false;
if (QueryTextBox.Text.Length == 0)
@ -581,6 +614,8 @@ namespace Flow.Launcher
windowsb.Begin(FlowMainWindow);
}
private void InitSoundEffects()
{
if (_settings.WMPInstalled)

View file

@ -1393,11 +1393,15 @@ namespace Flow.Launcher.ViewModel
});
}
public async void Hide()
public void Hide()
{
lastHistoryIndex = 1;
// MainWindow 인스턴스를 가져와서 애니메이션 초기화
if (Application.Current.MainWindow is MainWindow mainWindow)
{
mainWindow.ResetAnimation(); // 애니메이션 강제 리셋
}
// Trick for no delay
lastHistoryIndex = 1;
MainWindowOpacity = 0;
if (ExternalPreviewVisible)
@ -1408,7 +1412,6 @@ namespace Flow.Launcher.ViewModel
SelectedResults = Results;
}
// 📌 모든 LastQueryMode에서 텍스트 필드 즉시 업데이트 + 강제 UI 갱신
Application.Current.Dispatcher.Invoke(() =>
{
switch (Settings.LastQueryMode)
@ -1437,11 +1440,9 @@ namespace Flow.Launcher.ViewModel
break;
}
// 📌 UI 강제 갱신
Application.Current.MainWindow.UpdateLayout();
}, DispatcherPriority.Render); // UI 스레드에서 즉시 실행
}, DispatcherPriority.Render);
// 📌 창 숨김 처리 (텍스트 변경 후)
MainWindowVisibilityStatus = false;
MainWindowVisibility = Visibility.Collapsed;
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = false });
@ -1449,6 +1450,7 @@ namespace Flow.Launcher.ViewModel
/// <summary>
/// Checks if Flow Launcher should ignore any hotkeys
/// </summary>