mirror of
https://github.com/Heretek-AI/not-zune.git
synced 2026-10-11 21:19:55 +00:00
204 lines
7.6 KiB
C#
204 lines
7.6 KiB
C#
using System.Windows.Input;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using NotZune.Application.Events;
|
|
using NotZune.Application.Interfaces;
|
|
using NotZune.Domain.Enums;
|
|
using NotZune.Domain.Models;
|
|
|
|
namespace NotZune.UI.ViewModels;
|
|
|
|
public enum NavigationPivot
|
|
{
|
|
Quickplay,
|
|
Collection,
|
|
NowPlaying,
|
|
Device,
|
|
Settings
|
|
}
|
|
|
|
public class MainShellViewModel : ViewModelBase
|
|
{
|
|
private readonly IPlayerCoordinator _playerCoordinator;
|
|
private readonly IMediaLibraryService _libraryService;
|
|
private readonly IDeviceSyncService _deviceSyncService;
|
|
|
|
private NavigationPivot _activePivot = NavigationPivot.Quickplay;
|
|
private ViewModelBase _currentView;
|
|
|
|
public QuickplayViewModel QuickplayVM { get; }
|
|
public CollectionViewModel CollectionVM { get; }
|
|
public NowPlayingViewModel NowPlayingVM { get; }
|
|
public DeviceViewModel DeviceVM { get; }
|
|
public SettingsViewModel SettingsVM { get; }
|
|
|
|
public NavigationPivot ActivePivot
|
|
{
|
|
get => _activePivot;
|
|
set
|
|
{
|
|
if (SetProperty(ref _activePivot, value))
|
|
{
|
|
OnPropertyChanged(nameof(IsQuickplayActive));
|
|
OnPropertyChanged(nameof(IsCollectionActive));
|
|
OnPropertyChanged(nameof(IsNowPlayingActive));
|
|
OnPropertyChanged(nameof(IsDeviceActive));
|
|
OnPropertyChanged(nameof(IsSettingsActive));
|
|
|
|
CurrentView = _activePivot switch
|
|
{
|
|
NavigationPivot.Quickplay => QuickplayVM,
|
|
NavigationPivot.Collection => CollectionVM,
|
|
NavigationPivot.NowPlaying => NowPlayingVM,
|
|
NavigationPivot.Device => DeviceVM,
|
|
NavigationPivot.Settings => SettingsVM,
|
|
_ => QuickplayVM
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsQuickplayActive => _activePivot == NavigationPivot.Quickplay;
|
|
public bool IsCollectionActive => _activePivot == NavigationPivot.Collection;
|
|
public bool IsNowPlayingActive => _activePivot == NavigationPivot.NowPlaying;
|
|
public bool IsDeviceActive => _activePivot == NavigationPivot.Device;
|
|
public bool IsSettingsActive => _activePivot == NavigationPivot.Settings;
|
|
|
|
public ViewModelBase CurrentView
|
|
{
|
|
get => _currentView;
|
|
private set => SetProperty(ref _currentView, value);
|
|
}
|
|
|
|
// Playback HUD properties
|
|
public Track? CurrentTrack => _playerCoordinator.CurrentTrack;
|
|
public PlaybackState State => _playerCoordinator.State;
|
|
public bool IsPlaying => State == PlaybackState.Playing;
|
|
public TimeSpan CurrentPosition => _playerCoordinator.CurrentPosition;
|
|
public TimeSpan Duration => _playerCoordinator.Duration;
|
|
|
|
public double ProgressPercentage
|
|
{
|
|
get
|
|
{
|
|
if (Duration.TotalSeconds <= 0) return 0.0;
|
|
return Math.Clamp(CurrentPosition.TotalSeconds / Duration.TotalSeconds, 0.0, 1.0);
|
|
}
|
|
}
|
|
|
|
public string ElapsedTimeText => CurrentPosition.ToString(@"m\:ss");
|
|
public string RemainingTimeText => (Duration - CurrentPosition).ToString(@"\-m\:ss");
|
|
|
|
public double Volume
|
|
{
|
|
get => _playerCoordinator.Volume * 100.0;
|
|
set
|
|
{
|
|
_playerCoordinator.Volume = value / 100.0;
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
|
|
public HeartRating CurrentRating => CurrentTrack?.Rating ?? HeartRating.None;
|
|
public bool IsFavorite => CurrentRating == HeartRating.Favorite;
|
|
public bool IsDisliked => CurrentRating == HeartRating.Dislike;
|
|
|
|
// Commands
|
|
public ICommand SelectPivotCommand { get; }
|
|
public ICommand PlayPauseCommand { get; }
|
|
public ICommand NextCommand { get; }
|
|
public ICommand PreviousCommand { get; }
|
|
public ICommand ToggleFavoriteCommand { get; }
|
|
public ICommand ToggleDislikeCommand { get; }
|
|
public ICommand ToggleNowPlayingCommand { get; }
|
|
|
|
public MainShellViewModel(
|
|
IPlayerCoordinator playerCoordinator,
|
|
IMediaLibraryService libraryService,
|
|
IDeviceSyncService deviceSyncService,
|
|
ISmartDJService smartDJService)
|
|
{
|
|
_playerCoordinator = playerCoordinator;
|
|
_libraryService = libraryService;
|
|
_deviceSyncService = deviceSyncService;
|
|
|
|
// Child ViewModels
|
|
QuickplayVM = new QuickplayViewModel(playerCoordinator, libraryService, smartDJService);
|
|
CollectionVM = new CollectionViewModel(playerCoordinator, libraryService);
|
|
NowPlayingVM = new NowPlayingViewModel(playerCoordinator, libraryService);
|
|
DeviceVM = new DeviceViewModel(deviceSyncService);
|
|
SettingsVM = new SettingsViewModel();
|
|
|
|
_currentView = QuickplayVM;
|
|
|
|
// Wire events
|
|
_playerCoordinator.TrackChanged += OnPlayerTrackChanged;
|
|
_playerCoordinator.StateChanged += OnPlayerStateChanged;
|
|
_playerCoordinator.RatingChanged += OnPlayerRatingChanged;
|
|
|
|
// Setup commands
|
|
SelectPivotCommand = new RelayCommand<NavigationPivot>(pivot => ActivePivot = pivot);
|
|
PlayPauseCommand = new AsyncRelayCommand(() => _playerCoordinator.PlayPauseAsync());
|
|
NextCommand = new AsyncRelayCommand(() => _playerCoordinator.NextAsync());
|
|
PreviousCommand = new AsyncRelayCommand(() => _playerCoordinator.PreviousAsync());
|
|
ToggleFavoriteCommand = new AsyncRelayCommand(OnToggleFavoriteAsync);
|
|
ToggleDislikeCommand = new AsyncRelayCommand(OnToggleDislikeAsync);
|
|
ToggleNowPlayingCommand = new RelayCommand(() =>
|
|
{
|
|
ActivePivot = ActivePivot == NavigationPivot.NowPlaying
|
|
? NavigationPivot.Collection
|
|
: NavigationPivot.NowPlaying;
|
|
});
|
|
}
|
|
|
|
private async Task OnToggleFavoriteAsync()
|
|
{
|
|
if (CurrentTrack == null) return;
|
|
var newRating = CurrentRating == HeartRating.Favorite ? HeartRating.None : HeartRating.Favorite;
|
|
await _playerCoordinator.SetRatingAsync(CurrentTrack.Id, newRating);
|
|
await _libraryService.SetTrackRatingAsync(CurrentTrack.Id, newRating);
|
|
}
|
|
|
|
private async Task OnToggleDislikeAsync()
|
|
{
|
|
if (CurrentTrack == null) return;
|
|
var newRating = CurrentRating == HeartRating.Dislike ? HeartRating.None : HeartRating.Dislike;
|
|
await _playerCoordinator.SetRatingAsync(CurrentTrack.Id, newRating);
|
|
await _libraryService.SetTrackRatingAsync(CurrentTrack.Id, newRating);
|
|
if (newRating == HeartRating.Dislike)
|
|
{
|
|
// Auto skip disliked song
|
|
await _playerCoordinator.NextAsync();
|
|
}
|
|
}
|
|
|
|
private void OnPlayerTrackChanged(object? sender, TrackChangedEventArgs e)
|
|
{
|
|
OnPropertyChanged(nameof(CurrentTrack));
|
|
OnPropertyChanged(nameof(Duration));
|
|
OnPropertyChanged(nameof(CurrentPosition));
|
|
OnPropertyChanged(nameof(ProgressPercentage));
|
|
OnPropertyChanged(nameof(ElapsedTimeText));
|
|
OnPropertyChanged(nameof(RemainingTimeText));
|
|
OnPropertyChanged(nameof(CurrentRating));
|
|
OnPropertyChanged(nameof(IsFavorite));
|
|
OnPropertyChanged(nameof(IsDisliked));
|
|
}
|
|
|
|
private void OnPlayerStateChanged(object? sender, PlaybackStateChangedEventArgs e)
|
|
{
|
|
OnPropertyChanged(nameof(State));
|
|
OnPropertyChanged(nameof(IsPlaying));
|
|
OnPropertyChanged(nameof(CurrentPosition));
|
|
OnPropertyChanged(nameof(ProgressPercentage));
|
|
OnPropertyChanged(nameof(ElapsedTimeText));
|
|
OnPropertyChanged(nameof(RemainingTimeText));
|
|
}
|
|
|
|
private void OnPlayerRatingChanged(object? sender, HeartRatingChangedEventArgs e)
|
|
{
|
|
OnPropertyChanged(nameof(CurrentRating));
|
|
OnPropertyChanged(nameof(IsFavorite));
|
|
OnPropertyChanged(nameof(IsDisliked));
|
|
}
|
|
}
|