3ae99c82cc
* refactor(Icon): 将SymbolIcon替换为FontIcon以使用Segoe Fluent Icons Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> * chore: 移除 Costura.Fody 的 IncludeAssets 配置 Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com> --------- Signed-off-by: doudou0720 <98651603+doudou0720@users.noreply.github.com>
612 lines
22 KiB
C#
612 lines
22 KiB
C#
using Ink_Canvas.Helpers;
|
||
using iNKORE.UI.WPF.Modern.Common.IconKeys;
|
||
using System;
|
||
using System.Media;
|
||
using System.Timers;
|
||
using System.Windows;
|
||
using System.Windows.Input;
|
||
using System.Windows.Interop;
|
||
using System.Windows.Media;
|
||
|
||
namespace Ink_Canvas
|
||
{
|
||
/// <summary>
|
||
/// Interaction logic for StopwatchWindow.xaml
|
||
/// </summary>
|
||
public partial class CountdownTimerWindow : Window
|
||
{
|
||
public CountdownTimerWindow()
|
||
{
|
||
InitializeComponent();
|
||
AnimationsHelper.ShowWithSlideFromBottomAndFade(this, 0.25);
|
||
|
||
timer.Elapsed += Timer_Elapsed;
|
||
timer.Interval = 50;
|
||
InitializeUI();
|
||
|
||
// 应用主题
|
||
ApplyTheme();
|
||
}
|
||
|
||
public static Window CreateTimerWindow()
|
||
{
|
||
return new CountdownTimerWindow();
|
||
}
|
||
|
||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||
{
|
||
if (!isTimerRunning || isPaused)
|
||
{
|
||
timer.Stop();
|
||
return;
|
||
}
|
||
|
||
TimeSpan timeSpan = DateTime.Now - startTime;
|
||
TimeSpan totalTimeSpan = new TimeSpan(hour, minute, second);
|
||
double spentTimePercent = timeSpan.TotalMilliseconds / (totalSeconds * 1000.0);
|
||
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
if (!isOvertimeMode)
|
||
{
|
||
TimeSpan leftTimeSpan = totalTimeSpan - timeSpan;
|
||
if (leftTimeSpan.Milliseconds > 0) leftTimeSpan += new TimeSpan(0, 0, 1);
|
||
|
||
ProcessBarTime.CurrentValue = 1 - spentTimePercent;
|
||
TextBlockHour.Text = leftTimeSpan.Hours.ToString("00");
|
||
TextBlockMinute.Text = leftTimeSpan.Minutes.ToString("00");
|
||
TextBlockSecond.Text = leftTimeSpan.Seconds.ToString("00");
|
||
TbCurrentTime.Text = leftTimeSpan.ToString(@"hh\:mm\:ss");
|
||
|
||
if (spentTimePercent >= 1 && MainWindow.Settings.RandSettings?.EnableOvertimeCountUp == true)
|
||
{
|
||
isOvertimeMode = true;
|
||
ProcessBarTime.CurrentValue = 0;
|
||
ProcessBarTime.Visibility = Visibility.Collapsed;
|
||
BorderStopTime.Visibility = Visibility.Collapsed;
|
||
|
||
// 播放提醒音
|
||
PlayTimerSound();
|
||
}
|
||
else if (spentTimePercent >= 1)
|
||
{
|
||
ProcessBarTime.CurrentValue = 0;
|
||
TextBlockHour.Text = "00";
|
||
TextBlockMinute.Text = "00";
|
||
TextBlockSecond.Text = "00";
|
||
timer.Stop();
|
||
isTimerRunning = false;
|
||
FontIconStart.Icon = SegoeFluentIcons.Play;
|
||
BtnStartCover.Visibility = Visibility.Visible;
|
||
var textForeground = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground != null)
|
||
{
|
||
TextBlockHour.Foreground = textForeground;
|
||
}
|
||
else
|
||
{
|
||
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
|
||
}
|
||
BorderStopTime.Visibility = Visibility.Collapsed;
|
||
|
||
// 播放提醒音
|
||
PlayTimerSound();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TimeSpan overtimeSpan = timeSpan - totalTimeSpan;
|
||
TextBlockHour.Text = overtimeSpan.Hours.ToString("00");
|
||
TextBlockMinute.Text = overtimeSpan.Minutes.ToString("00");
|
||
TextBlockSecond.Text = overtimeSpan.Seconds.ToString("00");
|
||
TbCurrentTime.Text = overtimeSpan.ToString(@"hh\:mm\:ss");
|
||
|
||
if (MainWindow.Settings.RandSettings?.EnableOvertimeRedText == true)
|
||
{
|
||
TextBlockHour.Foreground = Brushes.Red;
|
||
TextBlockMinute.Foreground = Brushes.Red;
|
||
TextBlockSecond.Foreground = Brushes.Red;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
SoundPlayer player = new SoundPlayer();
|
||
MediaPlayer mediaPlayer = new MediaPlayer();
|
||
|
||
int hour = 0;
|
||
int minute = 1;
|
||
int second = 0;
|
||
int totalSeconds = 60;
|
||
|
||
DateTime startTime = DateTime.Now;
|
||
DateTime pauseTime = DateTime.Now;
|
||
|
||
bool isTimerRunning = false;
|
||
bool isPaused = false;
|
||
bool useLegacyUI = false;
|
||
bool isOvertimeMode = false;
|
||
|
||
Timer timer = new Timer();
|
||
|
||
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
if (isTimerRunning) return;
|
||
|
||
var textForeground = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
|
||
if (ProcessBarTime.Visibility == Visibility.Visible && isTimerRunning == false)
|
||
{
|
||
ProcessBarTime.Visibility = Visibility.Collapsed;
|
||
GridAdjustHour.Visibility = Visibility.Visible;
|
||
if (textForeground != null)
|
||
{
|
||
TextBlockHour.Foreground = textForeground;
|
||
}
|
||
else
|
||
{
|
||
TextBlockHour.Foreground = Brushes.Black;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ProcessBarTime.Visibility = Visibility.Visible;
|
||
GridAdjustHour.Visibility = Visibility.Collapsed;
|
||
if (textForeground != null)
|
||
{
|
||
TextBlockHour.Foreground = textForeground;
|
||
}
|
||
else
|
||
{
|
||
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
|
||
}
|
||
|
||
if (hour == 0 && minute == 0 && second == 0)
|
||
{
|
||
second = 1;
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
}
|
||
}
|
||
}
|
||
|
||
private void Button_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
hour++;
|
||
if (hour >= 100) hour = 0;
|
||
TextBlockHour.Text = hour.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_1(object sender, RoutedEventArgs e)
|
||
{
|
||
hour += 5;
|
||
if (hour >= 100) hour = 0;
|
||
TextBlockHour.Text = hour.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_2(object sender, RoutedEventArgs e)
|
||
{
|
||
hour--;
|
||
if (hour < 0) hour = 99;
|
||
TextBlockHour.Text = hour.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_3(object sender, RoutedEventArgs e)
|
||
{
|
||
hour -= 5;
|
||
if (hour < 0) hour = 99;
|
||
TextBlockHour.Text = hour.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_4(object sender, RoutedEventArgs e)
|
||
{
|
||
minute++;
|
||
if (minute >= 60) minute = 0;
|
||
TextBlockMinute.Text = minute.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_5(object sender, RoutedEventArgs e)
|
||
{
|
||
minute += 5;
|
||
if (minute >= 60) minute = 0;
|
||
TextBlockMinute.Text = minute.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_6(object sender, RoutedEventArgs e)
|
||
{
|
||
minute--;
|
||
if (minute < 0) minute = 59;
|
||
TextBlockMinute.Text = minute.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_7(object sender, RoutedEventArgs e)
|
||
{
|
||
minute -= 5;
|
||
if (minute < 0) minute = 59;
|
||
TextBlockMinute.Text = minute.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_8(object sender, RoutedEventArgs e)
|
||
{
|
||
second += 5;
|
||
if (second >= 60) second = 0;
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_9(object sender, RoutedEventArgs e)
|
||
{
|
||
second++;
|
||
if (second >= 60) second = 0;
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_10(object sender, RoutedEventArgs e)
|
||
{
|
||
second--;
|
||
if (second < 0) second = 59;
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
}
|
||
|
||
private void Button_Click_11(object sender, RoutedEventArgs e)
|
||
{
|
||
second -= 5;
|
||
if (second < 0) second = 59;
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
}
|
||
|
||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||
{
|
||
ProcessBarTime.Visibility = Visibility.Visible;
|
||
GridAdjustHour.Visibility = Visibility.Collapsed;
|
||
BorderStopTime.Visibility = Visibility.Collapsed;
|
||
}
|
||
|
||
private void BtnFullscreen_MouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
if (WindowState == WindowState.Normal)
|
||
{
|
||
WindowState = WindowState.Maximized;
|
||
FontIconFullscreen.Icon = SegoeFluentIcons.BackToWindow;
|
||
}
|
||
else
|
||
{
|
||
WindowState = WindowState.Normal;
|
||
FontIconFullscreen.Icon = SegoeFluentIcons.FullScreen;
|
||
}
|
||
}
|
||
|
||
private void BtnReset_MouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
if (!isTimerRunning)
|
||
{
|
||
TextBlockHour.Text = hour.ToString("00");
|
||
TextBlockMinute.Text = minute.ToString("00");
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
BtnResetCover.Visibility = Visibility.Visible;
|
||
BtnStartCover.Visibility = Visibility.Collapsed;
|
||
BorderStopTime.Visibility = Visibility.Collapsed;
|
||
var textForeground3 = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground3 != null)
|
||
TextBlockHour.Foreground = textForeground3;
|
||
else
|
||
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
|
||
|
||
isOvertimeMode = false;
|
||
ProcessBarTime.Visibility = Visibility.Visible;
|
||
}
|
||
else if (isTimerRunning && isPaused)
|
||
{
|
||
TextBlockHour.Text = hour.ToString("00");
|
||
TextBlockMinute.Text = minute.ToString("00");
|
||
TextBlockSecond.Text = second.ToString("00");
|
||
BtnResetCover.Visibility = Visibility.Visible;
|
||
BtnStartCover.Visibility = Visibility.Collapsed;
|
||
BorderStopTime.Visibility = Visibility.Collapsed;
|
||
var textForeground3 = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground3 != null)
|
||
TextBlockHour.Foreground = textForeground3;
|
||
else
|
||
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
|
||
FontIconStart.Icon = SegoeFluentIcons.Play;
|
||
isTimerRunning = false;
|
||
timer.Stop();
|
||
isPaused = false;
|
||
ProcessBarTime.CurrentValue = 0;
|
||
ProcessBarTime.IsPaused = false;
|
||
|
||
isOvertimeMode = false;
|
||
ProcessBarTime.Visibility = Visibility.Visible;
|
||
}
|
||
else
|
||
{
|
||
UpdateStopTime();
|
||
startTime = DateTime.Now;
|
||
Timer_Elapsed(timer, null);
|
||
}
|
||
}
|
||
|
||
void UpdateStopTime()
|
||
{
|
||
TimeSpan totalTimeSpan = new TimeSpan(hour, minute, second);
|
||
TextBlockStopTime.Text = (startTime + totalTimeSpan).ToString("t");
|
||
}
|
||
|
||
private Color StringToColor(string colorStr)
|
||
{
|
||
Byte[] argb = new Byte[4];
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
char[] charArray = colorStr.Substring(i * 2 + 1, 2).ToCharArray();
|
||
//string str = "11";
|
||
Byte b1 = toByte(charArray[0]);
|
||
Byte b2 = toByte(charArray[1]);
|
||
argb[i] = (Byte)(b2 | (b1 << 4));
|
||
}
|
||
|
||
return Color.FromArgb(argb[0], argb[1], argb[2], argb[3]); //#FFFFFFFF
|
||
}
|
||
|
||
private static byte toByte(char c)
|
||
{
|
||
byte b = (byte)"0123456789ABCDEF".IndexOf(c);
|
||
return b;
|
||
}
|
||
|
||
private void BtnStart_MouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
if (isPaused && isTimerRunning)
|
||
{
|
||
//继续
|
||
startTime += DateTime.Now - pauseTime;
|
||
ProcessBarTime.IsPaused = false;
|
||
var textForeground1 = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground1 != null)
|
||
TextBlockHour.Foreground = textForeground1;
|
||
else
|
||
TextBlockHour.Foreground = Brushes.Black;
|
||
FontIconStart.Icon = SegoeFluentIcons.Pause;
|
||
isPaused = false;
|
||
timer.Start();
|
||
UpdateStopTime();
|
||
BorderStopTime.Visibility = Visibility.Visible;
|
||
}
|
||
else if (isTimerRunning)
|
||
{
|
||
//暂停
|
||
pauseTime = DateTime.Now;
|
||
ProcessBarTime.IsPaused = true;
|
||
var textForeground3 = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground3 != null)
|
||
TextBlockHour.Foreground = textForeground3;
|
||
else
|
||
TextBlockHour.Foreground = new SolidColorBrush(StringToColor("#FF5B5D5F"));
|
||
FontIconStart.Icon = SegoeFluentIcons.Play;
|
||
BorderStopTime.Visibility = Visibility.Collapsed;
|
||
isPaused = true;
|
||
timer.Stop();
|
||
}
|
||
else
|
||
{
|
||
//从头开始
|
||
startTime = DateTime.Now;
|
||
totalSeconds = ((hour * 60) + minute) * 60 + second;
|
||
ProcessBarTime.IsPaused = false;
|
||
var textForeground2 = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground2 != null)
|
||
TextBlockHour.Foreground = textForeground2;
|
||
else
|
||
TextBlockHour.Foreground = Brushes.Black;
|
||
FontIconStart.Icon = SegoeFluentIcons.Pause;
|
||
BtnResetCover.Visibility = Visibility.Collapsed;
|
||
|
||
if (totalSeconds <= 10)
|
||
{
|
||
timer.Interval = 20;
|
||
}
|
||
else if (totalSeconds <= 60)
|
||
{
|
||
timer.Interval = 30;
|
||
}
|
||
else if (totalSeconds <= 120)
|
||
{
|
||
timer.Interval = 50;
|
||
}
|
||
else
|
||
{
|
||
timer.Interval = 100;
|
||
}
|
||
|
||
isPaused = false;
|
||
isTimerRunning = true;
|
||
isOvertimeMode = false;
|
||
ProcessBarTime.Visibility = Visibility.Visible;
|
||
timer.Start();
|
||
UpdateStopTime();
|
||
BorderStopTime.Visibility = Visibility.Visible;
|
||
}
|
||
}
|
||
|
||
private void InitializeUI()
|
||
{
|
||
// 从设置中读取配置
|
||
if (MainWindow.Settings.RandSettings != null)
|
||
{
|
||
useLegacyUI = MainWindow.Settings.RandSettings.UseLegacyTimerUI;
|
||
UpdateButtonTexts();
|
||
}
|
||
}
|
||
|
||
private void ApplyTheme()
|
||
{
|
||
try
|
||
{
|
||
// 根据主题设置文本颜色
|
||
var textForeground = Application.Current.FindResource("TimerWindowTextForeground") as SolidColorBrush;
|
||
if (textForeground != null)
|
||
{
|
||
TextBlockHour.Foreground = textForeground;
|
||
TextBlockMinute.Foreground = textForeground;
|
||
TextBlockSecond.Foreground = textForeground;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.WriteLogToFile($"应用倒计时窗口主题出错: {ex.Message}", LogHelper.LogType.Error);
|
||
}
|
||
}
|
||
|
||
public void RefreshUI()
|
||
{
|
||
InitializeUI();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新主题,当主窗口主题切换时调用
|
||
/// </summary>
|
||
public void RefreshTheme()
|
||
{
|
||
try
|
||
{
|
||
// 重新应用主题
|
||
ApplyTheme();
|
||
|
||
// 强制刷新UI
|
||
InvalidateVisual();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogHelper.WriteLogToFile($"刷新计时器窗口主题出错: {ex.Message}", LogHelper.LogType.Error);
|
||
}
|
||
}
|
||
|
||
private void UpdateButtonTexts()
|
||
{
|
||
if (useLegacyUI)
|
||
{
|
||
// 老版UI:使用+5, +1, -1, -5
|
||
HourPlus5Text.Text = "+5";
|
||
HourPlus1Text.Text = "+1";
|
||
HourMinus1Text.Text = "-1";
|
||
HourMinus5Text.Text = "-5";
|
||
|
||
MinutePlus5Text.Text = "+5";
|
||
MinutePlus1Text.Text = "+1";
|
||
MinuteMinus1Text.Text = "-1";
|
||
MinuteMinus5Text.Text = "-5";
|
||
|
||
SecondPlus5Text.Text = "+5";
|
||
SecondPlus1Text.Text = "+1";
|
||
SecondMinus1Text.Text = "-1";
|
||
SecondMinus5Text.Text = "-5";
|
||
}
|
||
else
|
||
{
|
||
// 新版UI:使用箭头符号
|
||
HourPlus5Text.Text = "∧∧";
|
||
HourPlus1Text.Text = "∧";
|
||
HourMinus1Text.Text = "∨";
|
||
HourMinus5Text.Text = "∨∨";
|
||
|
||
MinutePlus5Text.Text = "∧∧";
|
||
MinutePlus1Text.Text = "∧";
|
||
MinuteMinus1Text.Text = "∨";
|
||
MinuteMinus5Text.Text = "∨∨";
|
||
|
||
SecondPlus5Text.Text = "∧∧";
|
||
SecondPlus1Text.Text = "∧";
|
||
SecondMinus1Text.Text = "∨";
|
||
SecondMinus5Text.Text = "∨∨";
|
||
}
|
||
}
|
||
|
||
private void PlayTimerSound()
|
||
{
|
||
try
|
||
{
|
||
double volume = MainWindow.Settings.RandSettings?.TimerVolume ?? 1.0;
|
||
mediaPlayer.Volume = volume;
|
||
|
||
if (!string.IsNullOrEmpty(MainWindow.Settings.RandSettings?.CustomTimerSoundPath) &&
|
||
System.IO.File.Exists(MainWindow.Settings.RandSettings.CustomTimerSoundPath))
|
||
{
|
||
// 播放自定义铃声
|
||
mediaPlayer.Open(new Uri(MainWindow.Settings.RandSettings.CustomTimerSoundPath));
|
||
}
|
||
else
|
||
{
|
||
// 播放默认铃声
|
||
string tempPath = System.IO.Path.GetTempFileName() + ".wav";
|
||
using (var stream = Properties.Resources.TimerDownNotice)
|
||
{
|
||
using (var fileStream = new System.IO.FileStream(tempPath, System.IO.FileMode.Create))
|
||
{
|
||
stream.CopyTo(fileStream);
|
||
}
|
||
}
|
||
mediaPlayer.Open(new Uri(tempPath));
|
||
}
|
||
|
||
mediaPlayer.Play();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 如果播放失败,静默处理
|
||
System.Diagnostics.Debug.WriteLine($"播放计时器铃声失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||
{
|
||
isTimerRunning = false;
|
||
}
|
||
|
||
private void BtnClose_MouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
Close();
|
||
}
|
||
|
||
private bool _isInCompact = false;
|
||
|
||
private void BtnMinimal_OnMouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
if (_isInCompact)
|
||
{
|
||
Width = 1100;
|
||
Height = 700;
|
||
BigViewController.Visibility = Visibility.Visible;
|
||
TbCurrentTime.Visibility = Visibility.Collapsed;
|
||
|
||
// Set to center
|
||
double dpiScaleX = 1, dpiScaleY = 1;
|
||
PresentationSource source = PresentationSource.FromVisual(this);
|
||
if (source != null)
|
||
{
|
||
dpiScaleX = source.CompositionTarget.TransformToDevice.M11;
|
||
dpiScaleY = source.CompositionTarget.TransformToDevice.M22;
|
||
}
|
||
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
|
||
System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.FromHandle(windowHandle);
|
||
double screenWidth = screen.Bounds.Width / dpiScaleX, screenHeight = screen.Bounds.Height / dpiScaleY;
|
||
Left = (screenWidth / 2) - (Width / 2);
|
||
Top = (screenHeight / 2) - (Height / 2);
|
||
Left = (screenWidth / 2) - (Width / 2);
|
||
Top = (screenHeight / 2) - (Height / 2);
|
||
}
|
||
else
|
||
{
|
||
if (WindowState == WindowState.Maximized) WindowState = WindowState.Normal;
|
||
Width = 400;
|
||
Height = 250;
|
||
BigViewController.Visibility = Visibility.Collapsed;
|
||
TbCurrentTime.Visibility = Visibility.Visible;
|
||
}
|
||
|
||
_isInCompact = !_isInCompact;
|
||
}
|
||
|
||
private void WindowDragMove(object sender, MouseEventArgs e)
|
||
{
|
||
if (e.LeftButton == MouseButtonState.Pressed)
|
||
DragMove();
|
||
}
|
||
}
|
||
} |