add:PPT时间胶囊(没做完不好看)
This commit is contained in:
@@ -135,4 +135,21 @@ namespace Ink_Canvas.Converter
|
|||||||
return Visibility.Visible;
|
return Visibility.Visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class RippleEffectTranslationConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is double d)
|
||||||
|
{
|
||||||
|
return -d / 2;
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ namespace Ink_Canvas.Helpers
|
|||||||
|
|
||||||
UpdateNavigationPanelsVisibility();
|
UpdateNavigationPanelsVisibility();
|
||||||
UpdateNavigationButtonStyles();
|
UpdateNavigationButtonStyles();
|
||||||
|
_mainWindow.UpdatePPTTimeCapsuleVisibility();
|
||||||
if (MainWindow.Settings.Advanced.IsEnableAvoidFullScreenHelper)
|
if (MainWindow.Settings.Advanced.IsEnableAvoidFullScreenHelper)
|
||||||
{
|
{
|
||||||
// 设置为画板模式,允许全屏操作
|
// 设置为画板模式,允许全屏操作
|
||||||
@@ -120,6 +121,7 @@ namespace Ink_Canvas.Helpers
|
|||||||
_mainWindow.BtnPPTSlideShow.Visibility = Visibility.Visible;
|
_mainWindow.BtnPPTSlideShow.Visibility = Visibility.Visible;
|
||||||
_mainWindow.BtnPPTSlideShowEnd.Visibility = Visibility.Collapsed;
|
_mainWindow.BtnPPTSlideShowEnd.Visibility = Visibility.Collapsed;
|
||||||
HideAllNavigationPanels();
|
HideAllNavigationPanels();
|
||||||
|
_mainWindow.UpdatePPTTimeCapsuleVisibility();
|
||||||
if (MainWindow.Settings.Advanced.IsEnableAvoidFullScreenHelper)
|
if (MainWindow.Settings.Advanced.IsEnableAvoidFullScreenHelper)
|
||||||
{
|
{
|
||||||
// 恢复为非画板模式,重新启用全屏限制
|
// 恢复为非画板模式,重新启用全屏限制
|
||||||
|
|||||||
@@ -2323,6 +2323,27 @@
|
|||||||
</ui:SimpleStackPanel>
|
</ui:SimpleStackPanel>
|
||||||
<TextBlock Text="# 开启后在 PPT 放映模式下也显示手势按钮" TextWrapping="Wrap"
|
<TextBlock Text="# 开启后在 PPT 放映模式下也显示手势按钮" TextWrapping="Wrap"
|
||||||
Foreground="#a1a1aa" />
|
Foreground="#a1a1aa" />
|
||||||
|
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||||
|
<TextBlock Foreground="#fafafa" Text="PPT时间显示胶囊" VerticalAlignment="Center"
|
||||||
|
FontSize="14" Margin="0,0,16,0" />
|
||||||
|
<ui:ToggleSwitch OnContent="" OffContent=""
|
||||||
|
Name="ToggleSwitchEnablePPTTimeCapsule" IsOn="True"
|
||||||
|
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||||
|
Toggled="ToggleSwitchEnablePPTTimeCapsule_Toggled" />
|
||||||
|
</ui:SimpleStackPanel>
|
||||||
|
<TextBlock Text="# 开启后在 PPT 放映模式下显示时间胶囊,可替代最小化计时器窗口" TextWrapping="Wrap"
|
||||||
|
Foreground="#a1a1aa" />
|
||||||
|
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,8,0,0">
|
||||||
|
<TextBlock Foreground="#fafafa" Text="时间胶囊位置:" VerticalAlignment="Center"
|
||||||
|
FontSize="14" Margin="0,0,16,0" />
|
||||||
|
<ComboBox Name="ComboBoxPPTTimeCapsulePosition"
|
||||||
|
Width="150"
|
||||||
|
SelectionChanged="ComboBoxPPTTimeCapsulePosition_SelectionChanged">
|
||||||
|
<ComboBoxItem Content="左上角" />
|
||||||
|
<ComboBoxItem Content="右上角" />
|
||||||
|
<ComboBoxItem Content="顶部居中" />
|
||||||
|
</ComboBox>
|
||||||
|
</ui:SimpleStackPanel>
|
||||||
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0" Stroke="#3f3f46"
|
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0" Stroke="#3f3f46"
|
||||||
StrokeThickness="1" Margin="0,4,0,4" />
|
StrokeThickness="1" Margin="0,4,0,4" />
|
||||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||||
@@ -10298,6 +10319,15 @@
|
|||||||
Height="200">
|
Height="200">
|
||||||
<Windows:MinimizedTimerControl x:Name="MinimizedTimerControl"/>
|
<Windows:MinimizedTimerControl x:Name="MinimizedTimerControl"/>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
<Border x:Name="PPTTimeCapsuleContainer"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Panel.ZIndex="999"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Margin="0,20,20,0">
|
||||||
|
<Windows:PPTTimeCapsule x:Name="PPTTimeCapsule"/>
|
||||||
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
||||||
|
|||||||
@@ -698,14 +698,30 @@ namespace Ink_Canvas
|
|||||||
if (TimerControl != null && MinimizedTimerControl != null)
|
if (TimerControl != null && MinimizedTimerControl != null)
|
||||||
{
|
{
|
||||||
MinimizedTimerControl.SetParentControl(TimerControl);
|
MinimizedTimerControl.SetParentControl(TimerControl);
|
||||||
|
|
||||||
|
// 设置PPT时间胶囊的父控件
|
||||||
|
if (PPTTimeCapsule != null)
|
||||||
|
{
|
||||||
|
PPTTimeCapsule.SetParentControl(TimerControl);
|
||||||
|
}
|
||||||
|
|
||||||
TimerControl.ShowMinimizedRequested += (s, args) =>
|
TimerControl.ShowMinimizedRequested += (s, args) =>
|
||||||
{
|
{
|
||||||
if (TimerContainer != null && MinimizedTimerContainer != null && MinimizedTimerControl != null)
|
if (TimerContainer != null && MinimizedTimerContainer != null && MinimizedTimerControl != null)
|
||||||
{
|
{
|
||||||
TimerContainer.Visibility = Visibility.Collapsed;
|
TimerContainer.Visibility = Visibility.Collapsed;
|
||||||
MinimizedTimerContainer.Visibility = Visibility.Visible;
|
|
||||||
MinimizedTimerControl.Visibility = Visibility.Visible;
|
if (Settings.PowerPointSettings.EnablePPTTimeCapsule &&
|
||||||
|
BtnPPTSlideShowEnd.Visibility == Visibility.Visible &&
|
||||||
|
PPTTimeCapsule != null)
|
||||||
|
{
|
||||||
|
MinimizedTimerContainer.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MinimizedTimerContainer.Visibility = Visibility.Visible;
|
||||||
|
MinimizedTimerControl.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -716,6 +732,24 @@ namespace Ink_Canvas
|
|||||||
MinimizedTimerContainer.Visibility = Visibility.Collapsed;
|
MinimizedTimerContainer.Visibility = Visibility.Collapsed;
|
||||||
MinimizedTimerControl.Visibility = Visibility.Collapsed;
|
MinimizedTimerControl.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果启用了PPT时间胶囊,停止倒计时显示
|
||||||
|
if (Settings.PowerPointSettings.EnablePPTTimeCapsule && PPTTimeCapsule != null)
|
||||||
|
{
|
||||||
|
PPTTimeCapsule.StopCountdown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听计时器完成事件
|
||||||
|
TimerControl.TimerCompleted += (s, args) =>
|
||||||
|
{
|
||||||
|
// 如果启用了PPT时间胶囊且在PPT模式下,触发完成动画
|
||||||
|
if (Settings.PowerPointSettings.EnablePPTTimeCapsule &&
|
||||||
|
BtnPPTSlideShowEnd.Visibility == Visibility.Visible &&
|
||||||
|
PPTTimeCapsule != null)
|
||||||
|
{
|
||||||
|
PPTTimeCapsule.OnTimerCompleted();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}), DispatcherPriority.Loaded);
|
}), DispatcherPriority.Loaded);
|
||||||
@@ -2580,6 +2614,54 @@ namespace Ink_Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ToggleSwitchEnablePPTTimeCapsule_Toggled(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!isLoaded) return;
|
||||||
|
var toggle = sender as ToggleSwitch;
|
||||||
|
Settings.PowerPointSettings.EnablePPTTimeCapsule = toggle != null && toggle.IsOn;
|
||||||
|
SaveSettingsToFile();
|
||||||
|
|
||||||
|
// 如果当前在PPT放映模式,需要立即更新时间胶囊的显示状态
|
||||||
|
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
|
||||||
|
{
|
||||||
|
UpdatePPTTimeCapsuleVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile($"PPT时间显示胶囊已{(Settings.PowerPointSettings.EnablePPTTimeCapsule ? "启用" : "禁用")}", LogHelper.LogType.Event);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"切换PPT时间显示胶囊时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ComboBoxPPTTimeCapsulePosition_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!isLoaded) return;
|
||||||
|
if (ComboBoxPPTTimeCapsulePosition != null)
|
||||||
|
{
|
||||||
|
Settings.PowerPointSettings.PPTTimeCapsulePosition = ComboBoxPPTTimeCapsulePosition.SelectedIndex;
|
||||||
|
SaveSettingsToFile();
|
||||||
|
|
||||||
|
// 如果当前在PPT放映模式,需要立即更新时间胶囊的位置
|
||||||
|
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
|
||||||
|
{
|
||||||
|
UpdatePPTTimeCapsulePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
LogHelper.WriteLogToFile($"PPT时间胶囊位置已更改为: {ComboBoxPPTTimeCapsulePosition.SelectedIndex}", LogHelper.LogType.Event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"更改PPT时间胶囊位置时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新PPT模式下手势按钮的显示状态
|
/// 更新PPT模式下手势按钮的显示状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2603,6 +2685,69 @@ namespace Ink_Canvas
|
|||||||
LogHelper.WriteLogToFile($"更新PPT模式下手势按钮显示状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
LogHelper.WriteLogToFile($"更新PPT模式下手势按钮显示状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新PPT时间胶囊的显示状态
|
||||||
|
/// </summary>
|
||||||
|
public void UpdatePPTTimeCapsuleVisibility()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (PPTTimeCapsuleContainer == null || PPTTimeCapsule == null) return;
|
||||||
|
|
||||||
|
if (Settings.PowerPointSettings.EnablePPTTimeCapsule &&
|
||||||
|
BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
|
||||||
|
{
|
||||||
|
PPTTimeCapsuleContainer.Visibility = Visibility.Visible;
|
||||||
|
UpdatePPTTimeCapsulePosition();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PPTTimeCapsuleContainer.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"更新PPT时间胶囊显示状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新PPT时间胶囊的位置
|
||||||
|
/// </summary>
|
||||||
|
private void UpdatePPTTimeCapsulePosition()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (PPTTimeCapsuleContainer == null) return;
|
||||||
|
|
||||||
|
int position = Settings.PowerPointSettings.PPTTimeCapsulePosition;
|
||||||
|
// 0-左上角, 1-右上角, 2-顶部居中
|
||||||
|
switch (position)
|
||||||
|
{
|
||||||
|
case 0: // 左上角
|
||||||
|
PPTTimeCapsuleContainer.HorizontalAlignment = HorizontalAlignment.Left;
|
||||||
|
PPTTimeCapsuleContainer.VerticalAlignment = VerticalAlignment.Top;
|
||||||
|
PPTTimeCapsuleContainer.Margin = new Thickness(20, 20, 0, 0);
|
||||||
|
break;
|
||||||
|
case 1: // 右上角
|
||||||
|
PPTTimeCapsuleContainer.HorizontalAlignment = HorizontalAlignment.Right;
|
||||||
|
PPTTimeCapsuleContainer.VerticalAlignment = VerticalAlignment.Top;
|
||||||
|
PPTTimeCapsuleContainer.Margin = new Thickness(0, 20, 20, 0);
|
||||||
|
break;
|
||||||
|
case 2: // 顶部居中
|
||||||
|
PPTTimeCapsuleContainer.HorizontalAlignment = HorizontalAlignment.Center;
|
||||||
|
PPTTimeCapsuleContainer.VerticalAlignment = VerticalAlignment.Top;
|
||||||
|
PPTTimeCapsuleContainer.Margin = new Thickness(0, 20, 0, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"更新PPT时间胶囊位置时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -480,6 +480,21 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
ToggleSwitchNotifyPreviousPage.IsOn = Settings.PowerPointSettings.IsNotifyPreviousPage;
|
ToggleSwitchNotifyPreviousPage.IsOn = Settings.PowerPointSettings.IsNotifyPreviousPage;
|
||||||
|
|
||||||
|
// PPT时间显示胶囊设置
|
||||||
|
if (ToggleSwitchEnablePPTTimeCapsule != null)
|
||||||
|
{
|
||||||
|
ToggleSwitchEnablePPTTimeCapsule.IsOn = Settings.PowerPointSettings.EnablePPTTimeCapsule;
|
||||||
|
}
|
||||||
|
if (ComboBoxPPTTimeCapsulePosition != null)
|
||||||
|
{
|
||||||
|
int position = Settings.PowerPointSettings.PPTTimeCapsulePosition;
|
||||||
|
if (position < 0 || position > 2)
|
||||||
|
{
|
||||||
|
position = 1; // 默认右上角
|
||||||
|
}
|
||||||
|
ComboBoxPPTTimeCapsulePosition.SelectedIndex = position;
|
||||||
|
}
|
||||||
|
|
||||||
// -- new --
|
// -- new --
|
||||||
ToggleSwitchShowPPTButton.IsOn = Settings.PowerPointSettings.ShowPPTButton;
|
ToggleSwitchShowPPTButton.IsOn = Settings.PowerPointSettings.ShowPPTButton;
|
||||||
|
|
||||||
|
|||||||
@@ -333,6 +333,10 @@ namespace Ink_Canvas
|
|||||||
public bool ShowGestureButtonInSlideShow { get; set; } = false;
|
public bool ShowGestureButtonInSlideShow { get; set; } = false;
|
||||||
[JsonProperty("skipAnimationsWhenGoNext")]
|
[JsonProperty("skipAnimationsWhenGoNext")]
|
||||||
public bool SkipAnimationsWhenGoNext { get; set; } = false;
|
public bool SkipAnimationsWhenGoNext { get; set; } = false;
|
||||||
|
[JsonProperty("enablePPTTimeCapsule")]
|
||||||
|
public bool EnablePPTTimeCapsule { get; set; } = true;
|
||||||
|
[JsonProperty("pptTimeCapsulePosition")]
|
||||||
|
public int PPTTimeCapsulePosition { get; set; } = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Automation
|
public class Automation
|
||||||
|
|||||||
@@ -0,0 +1,191 @@
|
|||||||
|
<UserControl x:Class="Ink_Canvas.Windows.PPTTimeCapsule"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Converter="clr-namespace:Ink_Canvas.Converter"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="60" d:DesignWidth="200">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="DigitResources.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<!-- 小时滚动动画:新时间从上方滚入 -->
|
||||||
|
<Storyboard x:Key="HourScrollAnimation" x:Name="HourScrollStoryboard">
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="HourContentTransform"
|
||||||
|
Storyboard.TargetProperty="(TranslateTransform.Y)">
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="-40">
|
||||||
|
<EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
<ExponentialEase EasingMode="EaseOut"/>
|
||||||
|
</EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00.25" Value="0">
|
||||||
|
<EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
<ExponentialEase EasingMode="EaseOut"/>
|
||||||
|
</EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="HourPanel"
|
||||||
|
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="0">
|
||||||
|
<EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
<ExponentialEase EasingMode="EaseOut"/>
|
||||||
|
</EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00.25" Value="1">
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
|
||||||
|
<!-- 分钟滚动动画:新时间从上方滚入 -->
|
||||||
|
<Storyboard x:Key="MinuteScrollAnimation" x:Name="MinuteScrollStoryboard">
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MinuteContentTransform"
|
||||||
|
Storyboard.TargetProperty="(TranslateTransform.Y)">
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="-40">
|
||||||
|
<EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
<ExponentialEase EasingMode="EaseOut"/>
|
||||||
|
</EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00.25" Value="0">
|
||||||
|
<EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
<ExponentialEase EasingMode="EaseOut"/>
|
||||||
|
</EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="MinutePanel"
|
||||||
|
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="0">
|
||||||
|
<EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
<ExponentialEase EasingMode="EaseOut"/>
|
||||||
|
</EasingDoubleKeyFrame.EasingFunction>
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
<EasingDoubleKeyFrame KeyTime="00:00:00.25" Value="1">
|
||||||
|
</EasingDoubleKeyFrame>
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
|
||||||
|
<!-- 胶囊伸长动画 -->
|
||||||
|
<Storyboard x:Key="CapsuleExpandAnimation" x:Name="CapsuleExpandStoryboard">
|
||||||
|
<DoubleAnimation Storyboard.TargetName="MainCapsule"
|
||||||
|
Storyboard.TargetProperty="(FrameworkElement.Width)"
|
||||||
|
Duration="0:0:0.3">
|
||||||
|
<DoubleAnimation.EasingFunction>
|
||||||
|
<CubicEase EasingMode="EaseOut"/>
|
||||||
|
</DoubleAnimation.EasingFunction>
|
||||||
|
</DoubleAnimation>
|
||||||
|
</Storyboard>
|
||||||
|
|
||||||
|
<!-- 胶囊缩短动画 -->
|
||||||
|
<Storyboard x:Key="CapsuleShrinkAnimation" x:Name="CapsuleShrinkStoryboard">
|
||||||
|
<DoubleAnimation Storyboard.TargetName="MainCapsule"
|
||||||
|
Storyboard.TargetProperty="(FrameworkElement.Width)"
|
||||||
|
Duration="0:0:0.3">
|
||||||
|
<DoubleAnimation.EasingFunction>
|
||||||
|
<CubicEase EasingMode="EaseIn"/>
|
||||||
|
</DoubleAnimation.EasingFunction>
|
||||||
|
</DoubleAnimation>
|
||||||
|
</Storyboard>
|
||||||
|
|
||||||
|
<!-- 冒号闪动动画:1秒完成一次完整闪动 -->
|
||||||
|
<Storyboard x:Key="ColonBlinkAnimation" x:Name="ColonBlinkStoryboard" RepeatBehavior="Forever">
|
||||||
|
<DoubleAnimation Storyboard.TargetName="ColonDisplay"
|
||||||
|
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||||
|
From="1.0"
|
||||||
|
To="0.3"
|
||||||
|
Duration="0:0:0.5"
|
||||||
|
AutoReverse="True">
|
||||||
|
<DoubleAnimation.EasingFunction>
|
||||||
|
<SineEase EasingMode="EaseInOut"/>
|
||||||
|
</DoubleAnimation.EasingFunction>
|
||||||
|
</DoubleAnimation>
|
||||||
|
</Storyboard>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<!-- 主胶囊容器 -->
|
||||||
|
<Border x:Name="MainCapsule"
|
||||||
|
CornerRadius="15"
|
||||||
|
Padding="16,8"
|
||||||
|
Width="120"
|
||||||
|
Cursor="Hand"
|
||||||
|
MouseLeftButtonDown="MainCapsule_MouseLeftButtonDown">
|
||||||
|
<Border.Background>
|
||||||
|
<SolidColorBrush x:Name="CapsuleBackgroundBrush" Color="#CCFFFFFF"/>
|
||||||
|
</Border.Background>
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect BlurRadius="8" ShadowDepth="0" Opacity="0.2" Color="Black"/>
|
||||||
|
</Border.Effect>
|
||||||
|
|
||||||
|
<StackPanel x:Name="ContentPanel" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<!-- 时间显示区域 -->
|
||||||
|
<StackPanel x:Name="TimeDisplayPanel" Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<!-- 小时部分 -->
|
||||||
|
<Border x:Name="HourContainer" ClipToBounds="True" Height="18" VerticalAlignment="Center">
|
||||||
|
<StackPanel x:Name="HourPanel" Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<StackPanel.RenderTransform>
|
||||||
|
<TranslateTransform x:Name="HourContentTransform"/>
|
||||||
|
</StackPanel.RenderTransform>
|
||||||
|
<Path x:Name="Hour1Display"
|
||||||
|
Data="{StaticResource Digit0}"
|
||||||
|
Fill="#FF000000"
|
||||||
|
Width="14" Height="18"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Stretch="Uniform"
|
||||||
|
Margin="0,0,2,0"/>
|
||||||
|
<Path x:Name="Hour2Display"
|
||||||
|
Data="{StaticResource Digit0}"
|
||||||
|
Fill="#FF000000"
|
||||||
|
Width="14" Height="18"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Stretch="Uniform"
|
||||||
|
Margin="0,0,2,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 冒号 -->
|
||||||
|
<TextBlock x:Name="ColonDisplay" Text=":" FontSize="16" FontWeight="Bold"
|
||||||
|
Foreground="#FF000000" VerticalAlignment="Center" Margin="0,0,2,0"
|
||||||
|
LineHeight="16" LineStackingStrategy="BlockLineHeight"/>
|
||||||
|
|
||||||
|
<!-- 分钟部分 -->
|
||||||
|
<Border x:Name="MinuteContainer" ClipToBounds="True" Height="18" VerticalAlignment="Center">
|
||||||
|
<StackPanel x:Name="MinutePanel" Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<StackPanel.RenderTransform>
|
||||||
|
<TranslateTransform x:Name="MinuteContentTransform"/>
|
||||||
|
</StackPanel.RenderTransform>
|
||||||
|
<Path x:Name="Minute1Display"
|
||||||
|
Data="{StaticResource Digit0}"
|
||||||
|
Fill="#FF000000"
|
||||||
|
Width="14" Height="18"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Stretch="Uniform"
|
||||||
|
Margin="0,0,2,0"/>
|
||||||
|
<Path x:Name="Minute2Display"
|
||||||
|
Data="{StaticResource Digit0}"
|
||||||
|
Fill="#FF000000"
|
||||||
|
Width="14" Height="18"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Stretch="Uniform"
|
||||||
|
Margin="0,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 倒计时显示区域(动态显示) -->
|
||||||
|
<StackPanel x:Name="CountdownPanel" Orientation="Horizontal" VerticalAlignment="Center"
|
||||||
|
Visibility="Collapsed" Margin="8,0,0,0">
|
||||||
|
<TextBlock x:Name="CountdownText" Text="00:00" FontSize="20" FontWeight="Bold"
|
||||||
|
Foreground="#80000000" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
|
|
||||||
@@ -0,0 +1,670 @@
|
|||||||
|
using Ink_Canvas.Helpers;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Timers;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using File = System.IO.File;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Windows
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// PPT时间显示胶囊控件
|
||||||
|
/// </summary>
|
||||||
|
public partial class PPTTimeCapsule : UserControl
|
||||||
|
{
|
||||||
|
private System.Timers.Timer timeUpdateTimer;
|
||||||
|
private System.Timers.Timer countdownUpdateTimer; // 倒计时更新定时器(参考MinimizedTimerControl)
|
||||||
|
private DateTime lastTime = DateTime.MinValue;
|
||||||
|
private TimerControl parentControl; // 父计时器控件引用(参考MinimizedTimerControl)
|
||||||
|
private bool wasTimerRunning = false; // 上次检查时计时器是否运行
|
||||||
|
private bool isOvertime = false;
|
||||||
|
private Storyboard capsuleExpandStoryboard;
|
||||||
|
private Storyboard capsuleShrinkStoryboard;
|
||||||
|
private Storyboard colonBlinkStoryboard;
|
||||||
|
private double originalCapsuleWidth = 0;
|
||||||
|
|
||||||
|
public PPTTimeCapsule()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
InitializeTimers();
|
||||||
|
ApplyTheme();
|
||||||
|
|
||||||
|
// 监听主题变化
|
||||||
|
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
|
||||||
|
|
||||||
|
Loaded += PPTTimeCapsule_Loaded;
|
||||||
|
Unloaded += PPTTimeCapsule_Unloaded;
|
||||||
|
IsVisibleChanged += PPTTimeCapsule_IsVisibleChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PPTTimeCapsule_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (Visibility == Visibility.Visible)
|
||||||
|
{
|
||||||
|
ApplyTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PPTTimeCapsule_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 记录初始宽度
|
||||||
|
if (MainCapsule != null && originalCapsuleWidth == 0)
|
||||||
|
{
|
||||||
|
originalCapsuleWidth = MainCapsule.ActualWidth > 0 ? MainCapsule.ActualWidth : 120;
|
||||||
|
}
|
||||||
|
UpdateTimeDisplay();
|
||||||
|
StartTimeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PPTTimeCapsule_Unloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
StopTimeUpdate();
|
||||||
|
SystemEvents.UserPreferenceChanged -= SystemEvents_UserPreferenceChanged;
|
||||||
|
|
||||||
|
if (countdownUpdateTimer != null)
|
||||||
|
{
|
||||||
|
countdownUpdateTimer.Stop();
|
||||||
|
countdownUpdateTimer.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeTimers()
|
||||||
|
{
|
||||||
|
// 时间更新定时器(每秒更新)
|
||||||
|
timeUpdateTimer = new System.Timers.Timer(1000);
|
||||||
|
timeUpdateTimer.Elapsed += TimeUpdateTimer_Elapsed;
|
||||||
|
|
||||||
|
// 倒计时更新定时器
|
||||||
|
countdownUpdateTimer = new System.Timers.Timer(100);
|
||||||
|
countdownUpdateTimer.Elapsed += CountdownUpdateTimer_Elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimeUpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
UpdateTimeDisplay();
|
||||||
|
}), DispatcherPriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CountdownUpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
if (this.Visibility != Visibility.Visible)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateCountdownDisplay();
|
||||||
|
}), DispatcherPriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartTimeUpdate()
|
||||||
|
{
|
||||||
|
if (timeUpdateTimer != null && !timeUpdateTimer.Enabled)
|
||||||
|
{
|
||||||
|
timeUpdateTimer.Start();
|
||||||
|
}
|
||||||
|
if (countdownUpdateTimer != null && !countdownUpdateTimer.Enabled)
|
||||||
|
{
|
||||||
|
countdownUpdateTimer.Start();
|
||||||
|
}
|
||||||
|
// 启动冒号闪动动画
|
||||||
|
StartColonBlinkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopTimeUpdate()
|
||||||
|
{
|
||||||
|
if (timeUpdateTimer != null)
|
||||||
|
{
|
||||||
|
timeUpdateTimer.Stop();
|
||||||
|
}
|
||||||
|
if (countdownUpdateTimer != null)
|
||||||
|
{
|
||||||
|
countdownUpdateTimer.Stop();
|
||||||
|
}
|
||||||
|
// 停止冒号闪动动画
|
||||||
|
StopColonBlinkAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置父计时器控件
|
||||||
|
/// </summary>
|
||||||
|
public void SetParentControl(TimerControl parent)
|
||||||
|
{
|
||||||
|
parentControl = parent;
|
||||||
|
if (parentControl != null)
|
||||||
|
{
|
||||||
|
UpdateCountdownDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTimeDisplay()
|
||||||
|
{
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
|
||||||
|
// 检查小时是否改变
|
||||||
|
if (lastTime != DateTime.MinValue && lastTime.Hour != now.Hour)
|
||||||
|
{
|
||||||
|
// 先更新数字内容
|
||||||
|
SetDigitDisplay("Hour1Display", now.Hour / 10);
|
||||||
|
SetDigitDisplay("Hour2Display", now.Hour % 10);
|
||||||
|
|
||||||
|
// 重置Transform位置到上方
|
||||||
|
HourContentTransform.Y = -40;
|
||||||
|
HourPanel.Opacity = 0;
|
||||||
|
|
||||||
|
// 播放小时滚动动画:从上方滚入
|
||||||
|
PlayHourScrollAnimation();
|
||||||
|
}
|
||||||
|
else if (lastTime == DateTime.MinValue)
|
||||||
|
{
|
||||||
|
// 首次加载,直接更新显示
|
||||||
|
SetDigitDisplay("Hour1Display", now.Hour / 10);
|
||||||
|
SetDigitDisplay("Hour2Display", now.Hour % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查分钟是否改变
|
||||||
|
if (lastTime != DateTime.MinValue && lastTime.Minute != now.Minute)
|
||||||
|
{
|
||||||
|
// 先更新数字内容
|
||||||
|
SetDigitDisplay("Minute1Display", now.Minute / 10);
|
||||||
|
SetDigitDisplay("Minute2Display", now.Minute % 10);
|
||||||
|
|
||||||
|
// 重置Transform位置到上方
|
||||||
|
MinuteContentTransform.Y = -40;
|
||||||
|
MinutePanel.Opacity = 0;
|
||||||
|
|
||||||
|
// 播放分钟滚动动画:从上方滚入
|
||||||
|
PlayMinuteScrollAnimation();
|
||||||
|
}
|
||||||
|
else if (lastTime == DateTime.MinValue)
|
||||||
|
{
|
||||||
|
// 首次加载,直接更新显示
|
||||||
|
SetDigitDisplay("Minute1Display", now.Minute / 10);
|
||||||
|
SetDigitDisplay("Minute2Display", now.Minute % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayHourScrollAnimation()
|
||||||
|
{
|
||||||
|
// 新时间从上方滚入(-25到0)
|
||||||
|
var scrollAnimation = (Storyboard)Resources["HourScrollAnimation"];
|
||||||
|
scrollAnimation.Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayMinuteScrollAnimation()
|
||||||
|
{
|
||||||
|
// 新时间从上方滚入(-25到0)
|
||||||
|
var scrollAnimation = (Storyboard)Resources["MinuteScrollAnimation"];
|
||||||
|
scrollAnimation.Begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据数字值设置SVG数字显示
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pathName">Path控件的名称</param>
|
||||||
|
/// <param name="digit">要显示的数字(0-9)</param>
|
||||||
|
private void SetDigitDisplay(string pathName, int digit)
|
||||||
|
{
|
||||||
|
var path = this.FindName(pathName) as System.Windows.Shapes.Path;
|
||||||
|
if (path != null)
|
||||||
|
{
|
||||||
|
digit = Math.Max(0, Math.Min(9, digit));
|
||||||
|
|
||||||
|
string resourceKey = $"Digit{digit}";
|
||||||
|
var geometry = this.FindResource(resourceKey) as Geometry;
|
||||||
|
if (geometry != null)
|
||||||
|
{
|
||||||
|
path.Data = geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置SVG数字的填充颜色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pathName">Path控件的名称</param>
|
||||||
|
/// <param name="color">填充颜色</param>
|
||||||
|
private void SetDigitFill(string pathName, Color color)
|
||||||
|
{
|
||||||
|
var path = this.FindName(pathName) as System.Windows.Shapes.Path;
|
||||||
|
if (path != null)
|
||||||
|
{
|
||||||
|
path.Fill = new SolidColorBrush(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartColonBlinkAnimation()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (colonBlinkStoryboard == null)
|
||||||
|
{
|
||||||
|
colonBlinkStoryboard = (Storyboard)Resources["ColonBlinkAnimation"];
|
||||||
|
}
|
||||||
|
if (colonBlinkStoryboard != null)
|
||||||
|
{
|
||||||
|
colonBlinkStoryboard.Begin(ColonDisplay, true); // true表示HandoffBehavior.SnapshotAndReplace
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"启动冒号闪动动画失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopColonBlinkAnimation()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (colonBlinkStoryboard != null)
|
||||||
|
{
|
||||||
|
colonBlinkStoryboard.Stop(ColonDisplay);
|
||||||
|
// 恢复冒号透明度
|
||||||
|
if (ColonDisplay != null)
|
||||||
|
{
|
||||||
|
ColonDisplay.Opacity = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"停止冒号闪动动画失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 停止倒计时
|
||||||
|
/// </summary>
|
||||||
|
public void StopCountdown()
|
||||||
|
{
|
||||||
|
bool wasRunning = wasTimerRunning;
|
||||||
|
wasTimerRunning = false;
|
||||||
|
CountdownPanel.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
// 重置超时状态
|
||||||
|
isOvertime = false;
|
||||||
|
// 根据主题恢复倒计时文本颜色
|
||||||
|
ApplyTheme();
|
||||||
|
|
||||||
|
// 播放胶囊缩短动画
|
||||||
|
if (wasRunning)
|
||||||
|
{
|
||||||
|
PlayCapsuleShrinkAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCountdownDisplay()
|
||||||
|
{
|
||||||
|
if (parentControl == null) return;
|
||||||
|
|
||||||
|
// 检查计时器是否正在运行(参考MinimizedTimerControl)
|
||||||
|
bool isRunning = parentControl.IsTimerRunning;
|
||||||
|
|
||||||
|
// 如果状态改变,更新UI
|
||||||
|
if (isRunning != wasTimerRunning)
|
||||||
|
{
|
||||||
|
wasTimerRunning = isRunning;
|
||||||
|
if (isRunning)
|
||||||
|
{
|
||||||
|
// 计时器开始运行,显示倒计时面板并播放伸长动画
|
||||||
|
CountdownPanel.Visibility = Visibility.Visible;
|
||||||
|
// 确保倒计时文本使用主题颜色
|
||||||
|
ApplyTheme();
|
||||||
|
PlayCapsuleExpandAnimation();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 计时器停止,隐藏倒计时面板并播放缩短动画
|
||||||
|
CountdownPanel.Visibility = Visibility.Collapsed;
|
||||||
|
PlayCapsuleShrinkAnimation();
|
||||||
|
isOvertime = false;
|
||||||
|
// 根据主题恢复倒计时文本颜色
|
||||||
|
ApplyTheme();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果计时器未运行,不更新显示
|
||||||
|
if (!isRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接从parentControl获取剩余时间
|
||||||
|
var remainingTime = parentControl.GetRemainingTime();
|
||||||
|
if (!remainingTime.HasValue)
|
||||||
|
{
|
||||||
|
// 如果无法获取剩余时间(可能是暂停状态),不更新显示
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeSpan = remainingTime.Value;
|
||||||
|
bool isOvertimeMode = timeSpan.TotalSeconds < 0;
|
||||||
|
|
||||||
|
// 处理超时状态
|
||||||
|
if (isOvertimeMode)
|
||||||
|
{
|
||||||
|
if (!isOvertime)
|
||||||
|
{
|
||||||
|
isOvertime = true;
|
||||||
|
OnTimerOvertime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保倒计时文本为红色(如果启用了超时红色文本设置)
|
||||||
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
||||||
|
if (mainWindow != null && MainWindow.Settings.RandSettings?.EnableOvertimeRedText == true)
|
||||||
|
{
|
||||||
|
CountdownText.Foreground = new SolidColorBrush(Colors.Red);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示超时时间
|
||||||
|
var overtimeSpan = -timeSpan;
|
||||||
|
if (overtimeSpan.TotalHours >= 1)
|
||||||
|
{
|
||||||
|
int hours = (int)overtimeSpan.TotalHours;
|
||||||
|
CountdownText.Text = $"{hours:D2}:{overtimeSpan.Minutes:D2}:{overtimeSpan.Seconds:D2}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CountdownText.Text = $"{overtimeSpan.Minutes:D2}:{overtimeSpan.Seconds:D2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 正常倒计时
|
||||||
|
if (isOvertime)
|
||||||
|
{
|
||||||
|
// 从超时状态恢复
|
||||||
|
isOvertime = false;
|
||||||
|
// 根据主题恢复倒计时文本颜色(如果未启用超时红色文本)
|
||||||
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
||||||
|
if (mainWindow == null || MainWindow.Settings.RandSettings?.EnableOvertimeRedText != true)
|
||||||
|
{
|
||||||
|
ApplyTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 确保正常倒计时时使用主题颜色(如果未启用超时红色文本)
|
||||||
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
||||||
|
if (mainWindow == null || MainWindow.Settings.RandSettings?.EnableOvertimeRedText != true)
|
||||||
|
{
|
||||||
|
// 检查当前颜色是否是红色,如果不是红色,则应用主题
|
||||||
|
if (CountdownText.Foreground is SolidColorBrush brush && brush.Color != Colors.Red)
|
||||||
|
{
|
||||||
|
ApplyTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeSpan.TotalHours >= 1)
|
||||||
|
{
|
||||||
|
int hours = (int)timeSpan.TotalHours;
|
||||||
|
CountdownText.Text = $"{hours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CountdownText.Text = $"{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayCapsuleExpandAnimation()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (MainCapsule != null)
|
||||||
|
{
|
||||||
|
// 记录原始宽度
|
||||||
|
if (originalCapsuleWidth == 0)
|
||||||
|
{
|
||||||
|
originalCapsuleWidth = MainCapsule.ActualWidth > 0 ? MainCapsule.ActualWidth : 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算目标宽度(根据倒计时文本长度估算)
|
||||||
|
double targetWidth = originalCapsuleWidth + 80; // 增加约80像素用于显示倒计时
|
||||||
|
|
||||||
|
if (capsuleExpandStoryboard == null)
|
||||||
|
{
|
||||||
|
capsuleExpandStoryboard = (Storyboard)Resources["CapsuleExpandAnimation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capsuleExpandStoryboard != null)
|
||||||
|
{
|
||||||
|
// 设置动画的目标值
|
||||||
|
var animation = capsuleExpandStoryboard.Children[0] as DoubleAnimation;
|
||||||
|
if (animation != null)
|
||||||
|
{
|
||||||
|
animation.From = originalCapsuleWidth;
|
||||||
|
animation.To = targetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsuleExpandStoryboard.Begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"播放胶囊伸长动画失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayCapsuleShrinkAnimation()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (MainCapsule != null && originalCapsuleWidth > 0)
|
||||||
|
{
|
||||||
|
if (capsuleShrinkStoryboard == null)
|
||||||
|
{
|
||||||
|
capsuleShrinkStoryboard = (Storyboard)Resources["CapsuleShrinkAnimation"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capsuleShrinkStoryboard != null)
|
||||||
|
{
|
||||||
|
// 设置动画的目标值
|
||||||
|
var animation = capsuleShrinkStoryboard.Children[0] as DoubleAnimation;
|
||||||
|
if (animation != null)
|
||||||
|
{
|
||||||
|
animation.From = MainCapsule.ActualWidth;
|
||||||
|
animation.To = originalCapsuleWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsuleShrinkStoryboard.Begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"播放胶囊缩短动画失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTimerOvertime()
|
||||||
|
{
|
||||||
|
// 改变倒计时文字颜色为红色
|
||||||
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
||||||
|
if (mainWindow != null && MainWindow.Settings.RandSettings?.EnableOvertimeRedText == true)
|
||||||
|
{
|
||||||
|
CountdownText.Foreground = new SolidColorBrush(Colors.Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理计时器完成事件
|
||||||
|
/// </summary>
|
||||||
|
public void OnTimerCompleted()
|
||||||
|
{
|
||||||
|
// 确保在UI线程上执行
|
||||||
|
if (!Dispatcher.CheckAccess())
|
||||||
|
{
|
||||||
|
Dispatcher.BeginInvoke(new Action(() => OnTimerCompleted()), DispatcherPriority.Normal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止倒计时
|
||||||
|
StopCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainCapsule_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
// 点击恢复主计时器窗口(不重置计时器)
|
||||||
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
||||||
|
if (mainWindow != null)
|
||||||
|
{
|
||||||
|
// 显示主计时器窗口
|
||||||
|
var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement;
|
||||||
|
if (timerContainer != null)
|
||||||
|
{
|
||||||
|
timerContainer.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 隐藏最小化计时器容器
|
||||||
|
var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement;
|
||||||
|
if (minimizedContainer != null)
|
||||||
|
{
|
||||||
|
minimizedContainer.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainWindow.TimerControl != null)
|
||||||
|
{
|
||||||
|
mainWindow.TimerControl.UpdateActivityTime();
|
||||||
|
|
||||||
|
mainWindow.TimerControl.CloseRequested -= TimerControl_CloseRequested;
|
||||||
|
mainWindow.TimerControl.CloseRequested += TimerControl_CloseRequested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimerControl_CloseRequested(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// 当计时器窗口关闭时,隐藏TimerContainer
|
||||||
|
var mainWindow = Application.Current.MainWindow as MainWindow;
|
||||||
|
if (mainWindow != null)
|
||||||
|
{
|
||||||
|
var timerContainer = mainWindow.FindName("TimerContainer") as FrameworkElement;
|
||||||
|
if (timerContainer != null)
|
||||||
|
{
|
||||||
|
timerContainer.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minimizedContainer = mainWindow.FindName("MinimizedTimerContainer") as FrameworkElement;
|
||||||
|
if (minimizedContainer != null)
|
||||||
|
{
|
||||||
|
minimizedContainer.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
ApplyTheme();
|
||||||
|
}), DispatcherPriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyTheme()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检测系统主题
|
||||||
|
bool isDarkTheme = IsDarkTheme();
|
||||||
|
|
||||||
|
if (isDarkTheme)
|
||||||
|
{
|
||||||
|
// 深色主题:使用80%不透明度的深色背景
|
||||||
|
CapsuleBackgroundBrush.Color = Color.FromArgb(204, 32, 32, 32); // #CC202020,约80%不透明度
|
||||||
|
SetDigitFill("Hour1Display", Colors.White);
|
||||||
|
SetDigitFill("Hour2Display", Colors.White);
|
||||||
|
SetDigitFill("Minute1Display", Colors.White);
|
||||||
|
SetDigitFill("Minute2Display", Colors.White);
|
||||||
|
ColonDisplay.Foreground = new SolidColorBrush(Colors.White);
|
||||||
|
CountdownText.Foreground = new SolidColorBrush(Color.FromArgb(200, 255, 255, 255));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 浅色主题:使用80%不透明度的白色背景
|
||||||
|
CapsuleBackgroundBrush.Color = Color.FromArgb(204, 255, 255, 255); // #CCFFFFFF,约80%不透明度
|
||||||
|
SetDigitFill("Hour1Display", Colors.Black);
|
||||||
|
SetDigitFill("Hour2Display", Colors.Black);
|
||||||
|
SetDigitFill("Minute1Display", Colors.Black);
|
||||||
|
SetDigitFill("Minute2Display", Colors.Black);
|
||||||
|
ColonDisplay.Foreground = new SolidColorBrush(Colors.Black);
|
||||||
|
CountdownText.Foreground = new SolidColorBrush(Color.FromArgb(128, 0, 0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"应用PPT时间胶囊主题失败: {ex.Message}", LogHelper.LogType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsDarkTheme()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string settingsPath = Path.Combine(App.RootPath, "Configs", "Settings.json");
|
||||||
|
if (File.Exists(settingsPath))
|
||||||
|
{
|
||||||
|
string jsonText = File.ReadAllText(settingsPath);
|
||||||
|
var settings = JsonConvert.DeserializeObject<Settings>(jsonText);
|
||||||
|
|
||||||
|
if (settings?.Appearance != null)
|
||||||
|
{
|
||||||
|
if (settings.Appearance.Theme == 1)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (settings.Appearance.Theme == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int systemTheme = (int)Microsoft.Win32.Registry.GetValue(
|
||||||
|
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
|
||||||
|
"AppsUseLightTheme", 1);
|
||||||
|
return systemTheme == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fallbackTheme = (int)Microsoft.Win32.Registry.GetValue(
|
||||||
|
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
|
||||||
|
"AppsUseLightTheme", 1);
|
||||||
|
return fallbackTheme == 0;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前倒计时状态
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCountdownRunning => parentControl != null && parentControl.IsTimerRunning;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取是否超时
|
||||||
|
/// </summary>
|
||||||
|
public bool IsOvertime => isOvertime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user