162 lines
4.6 KiB
C#
162 lines
4.6 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.UI.Xaml;
|
|
using Microsoft.UI.Xaml.Controls;
|
|
using Microsoft.UI.Xaml.Media;
|
|
using Microsoft.UI.Xaml.Media.Animation;
|
|
using Windows.Foundation;
|
|
using Tornado3_2026Election.Domain;
|
|
using Tornado3_2026Election.ViewModels;
|
|
|
|
namespace Tornado3_2026Election.Controls;
|
|
|
|
public sealed partial class ChannelSchedulePanel : UserControl
|
|
{
|
|
public static readonly DependencyProperty ViewModelProperty =
|
|
DependencyProperty.Register(
|
|
nameof(ViewModel),
|
|
typeof(ChannelScheduleViewModel),
|
|
typeof(ChannelSchedulePanel),
|
|
new PropertyMetadata(null));
|
|
|
|
public ChannelSchedulePanel()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public ChannelScheduleViewModel? ViewModel
|
|
{
|
|
get => (ChannelScheduleViewModel?)GetValue(ViewModelProperty);
|
|
set => SetValue(ViewModelProperty, value);
|
|
}
|
|
|
|
private void PromoteToNextButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var item = GetItem(sender);
|
|
var command = ViewModel?.PromoteToNextCommand;
|
|
if (item is null || command is null || !command.CanExecute(item))
|
|
{
|
|
return;
|
|
}
|
|
|
|
command.Execute(item);
|
|
}
|
|
|
|
private void MoveUpButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_ = AnimateSwapAsync(sender, moveUp: true);
|
|
}
|
|
|
|
private void MoveDownButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
_ = AnimateSwapAsync(sender, moveUp: false);
|
|
}
|
|
|
|
private void RemoveItemButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
var item = GetItem(sender);
|
|
var command = ViewModel?.RemoveItemCommand;
|
|
if (item is null || command is null || !command.CanExecute(item))
|
|
{
|
|
return;
|
|
}
|
|
|
|
command.Execute(item);
|
|
}
|
|
|
|
private static ChannelScheduleItem? GetItem(object sender)
|
|
{
|
|
return (sender as FrameworkElement)?.DataContext as ChannelScheduleItem;
|
|
}
|
|
|
|
private async Task AnimateSwapAsync(object sender, bool moveUp)
|
|
{
|
|
if (ViewModel is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var item = GetItem(sender);
|
|
if (item is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var currentIndex = ViewModel.Queue.IndexOf(item);
|
|
var targetIndex = currentIndex + (moveUp ? -1 : 1);
|
|
if (currentIndex < 0 || targetIndex < 0 || targetIndex >= ViewModel.Queue.Count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var swappedItem = ViewModel.Queue[targetIndex];
|
|
var movingContainer = QueueListView.ContainerFromItem(item) as ListViewItem;
|
|
var swappedContainer = QueueListView.ContainerFromItem(swappedItem) as ListViewItem;
|
|
var movingTop = movingContainer is null ? (double?)null : GetTop(movingContainer);
|
|
var swappedTop = swappedContainer is null ? (double?)null : GetTop(swappedContainer);
|
|
|
|
var command = moveUp ? ViewModel.MoveUpCommand : ViewModel.MoveDownCommand;
|
|
if (!command.CanExecute(item))
|
|
{
|
|
return;
|
|
}
|
|
|
|
command.Execute(item);
|
|
|
|
await Task.Yield();
|
|
QueueListView.UpdateLayout();
|
|
|
|
if (movingTop.HasValue)
|
|
{
|
|
AnimateToCurrentPosition(QueueListView.ContainerFromItem(item) as ListViewItem, movingTop.Value);
|
|
}
|
|
|
|
if (swappedTop.HasValue)
|
|
{
|
|
AnimateToCurrentPosition(QueueListView.ContainerFromItem(swappedItem) as ListViewItem, swappedTop.Value);
|
|
}
|
|
}
|
|
|
|
private double GetTop(FrameworkElement element)
|
|
{
|
|
return element.TransformToVisual(QueueListView).TransformPoint(new Point(0, 0)).Y;
|
|
}
|
|
|
|
private void AnimateToCurrentPosition(ListViewItem? container, double previousTop)
|
|
{
|
|
if (container is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var currentTop = GetTop(container);
|
|
var delta = previousTop - currentTop;
|
|
if (Math.Abs(delta) < 0.5)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var transform = container.RenderTransform as TranslateTransform;
|
|
if (transform is null)
|
|
{
|
|
transform = new TranslateTransform();
|
|
container.RenderTransform = transform;
|
|
}
|
|
|
|
transform.Y = delta;
|
|
|
|
var animation = new DoubleAnimation
|
|
{
|
|
To = 0,
|
|
Duration = new Duration(TimeSpan.FromMilliseconds(180)),
|
|
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
|
};
|
|
|
|
var storyboard = new Storyboard();
|
|
storyboard.Children.Add(animation);
|
|
Storyboard.SetTarget(animation, transform);
|
|
Storyboard.SetTargetProperty(animation, nameof(TranslateTransform.Y));
|
|
storyboard.Begin();
|
|
}
|
|
}
|