mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-22 00:54:26 +08:00
0.7.7.1
This commit is contained in:
144
VoiceHubLanDesktop/Views/VoiceHubScheduleControl.axaml
Normal file
144
VoiceHubLanDesktop/Views/VoiceHubScheduleControl.axaml
Normal file
@@ -0,0 +1,144 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
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"
|
||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="400"
|
||||
x:Class="VoiceHubLanDesktop.Views.VoiceHubScheduleControl"
|
||||
x:DataType="VoiceHubLanDesktop.Views.VoiceHubScheduleControl">
|
||||
|
||||
<Design.DataContext>
|
||||
<VoiceHubLanDesktop.Views.VoiceHubScheduleControl/>
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<!-- 标题栏 -->
|
||||
<Border Grid.Row="0"
|
||||
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
|
||||
Padding="12,8"
|
||||
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="16"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
|
||||
<TextBlock Text="{Binding TitleText}"
|
||||
FontWeight="SemiBold"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding DateText}"
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
|
||||
Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<Grid Grid.Row="1">
|
||||
<!-- 加载状态 -->
|
||||
<StackPanel x:Name="LoadingPanel"
|
||||
Orientation="Vertical"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="12"
|
||||
IsVisible="{Binding IsLoading}">
|
||||
<ProgressBar IsIndeterminate="True"
|
||||
Width="100"
|
||||
Height="4"/>
|
||||
<TextBlock Text="正在加载排期..."
|
||||
FontSize="13"
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 排期列表 -->
|
||||
<ScrollViewer x:Name="SchedulePanel"
|
||||
IsVisible="{Binding IsNormal}"
|
||||
Padding="8,8,8,8">
|
||||
<ItemsControl ItemsSource="{Binding Songs}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Background="{DynamicResource SystemControlBackgroundChromeMediumBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12,10"
|
||||
Margin="0,0,0,8">
|
||||
<Grid ColumnDefinitions="Auto,*">
|
||||
<!-- 序号 -->
|
||||
<Border Grid.Column="0"
|
||||
Background="{DynamicResource SystemAccentColor}"
|
||||
CornerRadius="12"
|
||||
Width="24"
|
||||
Height="24"
|
||||
Margin="0,0,12,0"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Sequence}"
|
||||
FontSize="11"
|
||||
FontWeight="Bold"
|
||||
Foreground="White"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<!-- 歌曲信息 -->
|
||||
<StackPanel Grid.Column="1" Spacing="4">
|
||||
<TextBlock Text="{Binding Song.Title}"
|
||||
FontSize="14"
|
||||
FontWeight="Medium"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
MaxLines="1"/>
|
||||
<TextBlock FontSize="12"
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
MaxLines="1">
|
||||
<Run Text="{Binding Song.Artist}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<StackPanel x:Name="EmptyPanel"
|
||||
Orientation="Vertical"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="8"
|
||||
IsVisible="{Binding IsEmpty}">
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="48"
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseMediumLowBrush}"/>
|
||||
<TextBlock Text="{Binding EmptyMessage}"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<StackPanel x:Name="ErrorPanel"
|
||||
Orientation="Vertical"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="8"
|
||||
IsVisible="{Binding IsError}">
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="48"
|
||||
Foreground="#FFB00020"/>
|
||||
<TextBlock Text="{Binding ErrorMessage}"
|
||||
FontSize="14"
|
||||
Foreground="#FFB00020"
|
||||
TextWrapping="Wrap"
|
||||
MaxWidth="200"
|
||||
TextAlignment="Center"/>
|
||||
<Button Content="重试"
|
||||
Command="{Binding RetryCommand}"
|
||||
Margin="0,8,0,0"
|
||||
HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
168
VoiceHubLanDesktop/Views/VoiceHubScheduleControl.axaml.cs
Normal file
168
VoiceHubLanDesktop/Views/VoiceHubScheduleControl.axaml.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using VoiceHubLanDesktop.Models;
|
||||
using VoiceHubLanDesktop.Services;
|
||||
|
||||
namespace VoiceHubLanDesktop.Views;
|
||||
|
||||
/// <summary>
|
||||
/// 广播站排期显示组件
|
||||
/// </summary>
|
||||
public sealed partial class VoiceHubScheduleControl : UserControl
|
||||
{
|
||||
private readonly VoiceHubScheduleService _scheduleService;
|
||||
private readonly VoiceHubSettingsService _settingsService;
|
||||
private readonly DispatcherTimer? _refreshTimer;
|
||||
private CancellationTokenSource? _loadCts;
|
||||
|
||||
public ObservableCollection<SongItem> Songs { get; } = [];
|
||||
|
||||
[ObservableProperty] private string _titleText = "广播站排期";
|
||||
[ObservableProperty] private string _dateText = "";
|
||||
[ObservableProperty] private string _emptyMessage = "暂无排期数据";
|
||||
[ObservableProperty] private string _errorMessage = "";
|
||||
[ObservableProperty] private bool _isLoading = true;
|
||||
[ObservableProperty] private bool _isNormal = false;
|
||||
[ObservableProperty] private bool _isEmpty = false;
|
||||
[ObservableProperty] private bool _isError = false;
|
||||
|
||||
public VoiceHubScheduleControl(
|
||||
VoiceHubScheduleService scheduleService,
|
||||
VoiceHubSettingsService settingsService,
|
||||
IPluginRuntimeContext runtimeContext)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
|
||||
_scheduleService = scheduleService;
|
||||
_settingsService = settingsService;
|
||||
|
||||
// 设置刷新定时器
|
||||
var settings = _settingsService.GetSettings();
|
||||
_refreshTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMinutes(settings.RefreshIntervalMinutes)
|
||||
};
|
||||
_refreshTimer.Tick += async (_, _) => await RefreshAsync();
|
||||
_refreshTimer.Start();
|
||||
|
||||
// 监听设置变化
|
||||
_settingsService.SettingsChanged += OnSettingsChanged;
|
||||
|
||||
// 初始加载
|
||||
_ = LoadAsync();
|
||||
}
|
||||
|
||||
private void OnSettingsChanged(object? sender, PluginSettings settings)
|
||||
{
|
||||
if (_refreshTimer != null)
|
||||
{
|
||||
_refreshTimer.Interval = TimeSpan.FromMinutes(settings.RefreshIntervalMinutes);
|
||||
}
|
||||
_scheduleService.ClearCache();
|
||||
_ = RefreshAsync();
|
||||
}
|
||||
|
||||
private async Task LoadAsync()
|
||||
{
|
||||
SetState(ComponentState.Loading);
|
||||
|
||||
try
|
||||
{
|
||||
_loadCts?.Cancel();
|
||||
_loadCts = new CancellationTokenSource();
|
||||
|
||||
var displayData = await _scheduleService.GetTodayScheduleAsync(_loadCts.Token);
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
ApplyDisplayData(displayData);
|
||||
});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 忽略取消
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
SetState(ComponentState.NetworkError, $"加载失败: {ex.Message}");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyDisplayData(DisplayData data)
|
||||
{
|
||||
switch (data.State)
|
||||
{
|
||||
case ComponentState.Normal:
|
||||
Songs.Clear();
|
||||
foreach (var song in data.Songs)
|
||||
{
|
||||
Songs.Add(song);
|
||||
}
|
||||
DateText = data.DisplayDate?.ToString("MM月dd日") ?? "";
|
||||
SetState(ComponentState.Normal);
|
||||
break;
|
||||
|
||||
case ComponentState.NoSchedule:
|
||||
EmptyMessage = data.ErrorMessage ?? "暂无排期数据";
|
||||
SetState(ComponentState.NoSchedule);
|
||||
break;
|
||||
|
||||
case ComponentState.NetworkError:
|
||||
SetState(ComponentState.NetworkError, data.ErrorMessage ?? "网络错误");
|
||||
break;
|
||||
|
||||
default:
|
||||
SetState(ComponentState.Loading);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetState(ComponentState state, string? message = null)
|
||||
{
|
||||
IsLoading = state == ComponentState.Loading;
|
||||
IsNormal = state == ComponentState.Normal;
|
||||
IsEmpty = state == ComponentState.NoSchedule;
|
||||
IsError = state == ComponentState.NetworkError;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
if (state == ComponentState.NetworkError)
|
||||
{
|
||||
ErrorMessage = message;
|
||||
}
|
||||
else if (state == ComponentState.NoSchedule)
|
||||
{
|
||||
EmptyMessage = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task RetryAsync()
|
||||
{
|
||||
_scheduleService.ClearCache();
|
||||
await LoadAsync();
|
||||
}
|
||||
|
||||
public async Task RefreshAsync()
|
||||
{
|
||||
await LoadAsync();
|
||||
}
|
||||
|
||||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnDetachedFromVisualTree(e);
|
||||
|
||||
_refreshTimer?.Stop();
|
||||
_loadCts?.Cancel();
|
||||
_settingsService.SettingsChanged -= OnSettingsChanged;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user