diff --git a/Wpf_AiSportsMicrospace/App.xaml b/Wpf_AiSportsMicrospace/App.xaml index 7854626..61792fe 100644 --- a/Wpf_AiSportsMicrospace/App.xaml +++ b/Wpf_AiSportsMicrospace/App.xaml @@ -2,6 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views" + xmlns:conv="clr-namespace:Wpf_AiSportsMicrospace.Converter" + StartupUri="Views/Main.xaml"> @@ -10,6 +12,8 @@ + + diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs index 83f0d72..7148e16 100644 --- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs +++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs @@ -155,7 +155,7 @@ namespace Wpf_AiSportsMicrospace.Common } var duration = DateTime.Now - _raiseStartTime.Value; - if (duration.TotalSeconds >= 3) + if (duration.TotalSeconds >= 1) { _raiseStartTime = null; _wristStartTime = null; diff --git a/Wpf_AiSportsMicrospace/Converter/DotColorConverter.cs b/Wpf_AiSportsMicrospace/Converter/DotColorConverter.cs new file mode 100644 index 0000000..509040c --- /dev/null +++ b/Wpf_AiSportsMicrospace/Converter/DotColorConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows; +using System.Windows.Data; +using System.Windows.Media; +using Wpf_AiSportsMicrospace.MyUserControl; + +namespace Wpf_AiSportsMicrospace.Converter +{ + public class DotColorConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool b && b) + return Brushes.Red; + return Brushes.Green; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + => throw new NotImplementedException(); + } +} diff --git a/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs b/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs index 3f01bd6..6190c8b 100644 --- a/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs +++ b/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs @@ -50,6 +50,8 @@ namespace Dto } }; + public Dictionary> MusicBeatsDic; + public MusicJumpRopeContext() { CirclePositions = new List<(double XNorm, double YNorm)> @@ -58,6 +60,8 @@ namespace Dto (0.50, 0.88), }; + MusicBeatsDic = MusicBeats["1"].GroupBy(b => (int)Math.Ceiling(b) - 1).ToDictionary(g => g.Key, g => g.ToList()); + UserList = new List(); UserNumberList = new List(); Sports = new List(); diff --git a/Wpf_AiSportsMicrospace/MyUserControl/BeatScrollDots.xaml b/Wpf_AiSportsMicrospace/MyUserControl/BeatScrollDots.xaml new file mode 100644 index 0000000..08a15d6 --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/BeatScrollDots.xaml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/BeatScrollDots.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/BeatScrollDots.xaml.cs new file mode 100644 index 0000000..6111311 --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/BeatScrollDots.xaml.cs @@ -0,0 +1,136 @@ +using Emgu.CV.Flann; +using HandyControl.Controls; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Wpf_AiSportsMicrospace.MyUserControl +{ + public partial class BeatScrollDots : UserControl + { + public ObservableCollection Dots { get; set; } = new ObservableCollection(); + + public BeatScrollDots() + { + InitializeComponent(); + DataContext = this; + } + + public int DotCount + { + get => (int)GetValue(DotCountProperty); + set => SetValue(DotCountProperty, value); + } + + public static readonly DependencyProperty DotCountProperty = + DependencyProperty.Register(nameof(DotCount), typeof(int), typeof(BeatScrollDots), + new PropertyMetadata(0, OnDotCountChanged)); + + private static void OnDotCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is BeatScrollDots ctrl) + ctrl.GenerateDots(); + } + + private void GenerateDots() + { + Dots.Clear(); + for (int i = 0; i < DotCount; i++) + Dots.Add(new DotItem { IsSelected = false }); + } + + public void SetSelected(int index, bool selected) + { + if (index >= 0 && index < Dots.Count) + Dots[index].IsSelected = selected; + } + + public Thickness DotSpacing + { + get => (Thickness)GetValue(DotSpacingProperty); + set => SetValue(DotSpacingProperty, value); + } + + public static readonly DependencyProperty DotSpacingProperty = + DependencyProperty.Register(nameof(DotSpacing), typeof(Thickness), typeof(BeatScrollDots), new PropertyMetadata(new Thickness(5, 0, 5, 0))); + + public void ScrollToDotCenter(int index, bool mirror = false) + { + if (scrollViewer == null || Dots.Count == 0) return; + + double step = 20 + DotSpacing.Left + DotSpacing.Right; + double totalWidth = Dots.Count * step; + double dotCenter = index * step + step / 2; + + double targetOffset = !mirror + ? dotCenter - scrollViewer.ActualWidth / 2 + : totalWidth - dotCenter - scrollViewer.ActualWidth / 2; + + targetOffset = System.Math.Max(0, System.Math.Min(targetOffset, scrollViewer.ScrollableWidth)); + scrollViewer.ScrollToHorizontalOffset(targetOffset); + } + + public void UpdateSpacingForCount(int count) + { + if (count <= 0) count = 1; + double spacing = (ActualWidth / count) - 20; + if (spacing < 2) spacing = 2; + DotSpacing = new Thickness(spacing / 2, 0, spacing / 2, 0); + } + public Dictionary> MusicBeatsDic + { + get => (Dictionary>)GetValue(MusicBeatsDicProperty); + set => SetValue(MusicBeatsDicProperty, value); + } + + public static readonly DependencyProperty MusicBeatsDicProperty = + DependencyProperty.Register(nameof(MusicBeatsDic), typeof(Dictionary>), typeof(BeatScrollDots), + new PropertyMetadata(null, OnMusicBeatsDicChanged)); + + private static void OnMusicBeatsDicChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is BeatScrollDots ctrl) + { + // 可选:根据第一个 key 初始化 DotCount + if (ctrl.MusicBeatsDic != null && ctrl.MusicBeatsDic.Any()) + { + int firstKey = ctrl.MusicBeatsDic.Keys.Min(); + ctrl.DotCount = ctrl.MusicBeatsDic[firstKey].Count; + ctrl.UpdateSpacingForCount(ctrl.DotCount); + } + } + } + } + + public class DotItem : INotifyPropertyChanged + { + private bool _isSelected; + + public bool IsSelected + { + get => _isSelected; + set + { + if (_isSelected != value) + { + _isSelected = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected))); + } + } + } + + public event PropertyChangedEventHandler PropertyChanged; + } +} \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml index 4f558a1..7cfde0b 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml @@ -38,9 +38,9 @@ - - + + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs index 14c5fe5..4d2df00 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs @@ -116,7 +116,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl { if (_currentItem.Progress < 1) { - _currentItem.Progress += 0.00556; // 控制速度 + _currentItem.Progress += 0.01; // 控制速度 if (spark != null) { var pos = GetSparkPosition(_currentItem.Progress, 150, 200); diff --git a/Wpf_AiSportsMicrospace/MyUserControl/WxProgressBar.xaml b/Wpf_AiSportsMicrospace/MyUserControl/WxProgressBar.xaml new file mode 100644 index 0000000..3901272 --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/WxProgressBar.xaml @@ -0,0 +1,25 @@ + + + + + + + + + + + + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/WxProgressBar.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/WxProgressBar.xaml.cs new file mode 100644 index 0000000..81435d3 --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/WxProgressBar.xaml.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Wpf_AiSportsMicrospace.MyUserControl +{ + /// + /// WxProgressBar.xaml 的交互逻辑 + /// + public partial class WxProgressBar : UserControl + { + public WxProgressBar() + { + InitializeComponent(); + this.SizeChanged += WxProgressBar_SizeChanged; + } + + private void WxProgressBar_SizeChanged(object sender, SizeChangedEventArgs e) + { + UpdateVisual(); + } + + #region 左右进度属性 + private double _leftProgress; + public double LeftProgress + { + get => _leftProgress; + set + { + _leftProgress = Clamp(value, 0, 1); + _rightProgress = 1 - _leftProgress; + UpdateVisual(); + } + } + + private double _rightProgress; + public double RightProgress + { + get => _rightProgress; + set + { + _rightProgress = Clamp(value, 0, 1); + _leftProgress = 1 - _rightProgress; + UpdateVisual(); + } + } + #endregion + + private void UpdateVisual() + { + double totalWidth = ActualWidth; + double totalHeight = ActualHeight; + if (totalWidth <= 0 || totalHeight <= 0) return; + + double barHeight = 30; // 进度条高度 + double middleLineHeight = MiddleLine.Height; + + // 左侧红条 + LeftBar.Width = totalWidth * _leftProgress; + LeftBar.Height = barHeight; + Canvas.SetLeft(LeftBar, 0); + Canvas.SetTop(LeftBar, (totalHeight - barHeight) / 2); + + // 右侧绿条 + RightBar.Width = totalWidth * _rightProgress; + RightBar.Height = barHeight; + Canvas.SetLeft(RightBar, totalWidth - RightBar.Width); + Canvas.SetTop(RightBar, (totalHeight - barHeight) / 2); + + // 分割线居中在红绿交界点 + double middleX = LeftBar.Width - MiddleLine.Width / 2; + if (middleX < 0) middleX = 0; + if (middleX > totalWidth - MiddleLine.Width) middleX = totalWidth - MiddleLine.Width; + + Canvas.SetLeft(MiddleLine, middleX); + Canvas.SetTop(MiddleLine, (totalHeight - middleLineHeight) / 2); + + // 百分比文本居中显示 + ProgressTextBlock.Text = $"{Math.Round(_leftProgress * 100)}% : {Math.Round(_rightProgress * 100)}%"; + Canvas.SetLeft(ProgressTextBlock, (totalWidth - ProgressTextBlock.ActualWidth) / 2); + Canvas.SetTop(ProgressTextBlock, (totalHeight - ProgressTextBlock.ActualHeight) / 2); + } + + private double Clamp(double value, double min, double max) => value < min ? min : value > max ? max : value; + } +} diff --git a/Wpf_AiSportsMicrospace/Resources/Img/Album/vs.png b/Wpf_AiSportsMicrospace/Resources/Img/Album/vs.png new file mode 100644 index 0000000..924e879 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/Album/vs.png differ diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs index 8a549d0..d2f8def 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -216,7 +216,7 @@ namespace Wpf_AiSportsMicrospace.Views } } - private int _currentCountdown = 3; + private double _currentCountdown = 3600; private DateTime _lastUpdateTime = DateTime.Now; private void StartCountdown(int start = 3) { @@ -233,10 +233,10 @@ namespace Wpf_AiSportsMicrospace.Views private void UpdateCountdown() { - if ((DateTime.Now - _lastUpdateTime).TotalSeconds >= 1) + if ((DateTime.Now - _lastUpdateTime).TotalMilliseconds >= 600) { _lastUpdateTime = DateTime.Now; - _currentCountdown--; + _currentCountdown -= 600; if (_currentCountdown > 0) { diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml index 7b9d6a8..1761c7c 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml @@ -35,29 +35,9 @@ TextAlignment="Center" /> - - - - - - - - - - - - - - - - - + + +