6
2025-11-12 10:55:00 +03:00

401 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Shared._Horizon.MediaPlayer;
using Robust.Client.Audio;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Audio.Components;
using Robust.Shared.Timing;
namespace Content.Client._Horizon.MediaPlayer;
[GenerateTypedNameReferences]
public sealed partial class MediaPlayerMenu : FancyWindow
{
[Dependency] private readonly IEntityManager _entManager = null!;
private readonly AudioSystem _audioSystem;
// events
public event Action<MediaSelectedMessage>? OnFileSelected;
public event Action<MediaRepeatMessage>? OnRepeatPressed;
public event Action<MediaVolumeMessage>? OnVolumePressed;
public event Action<MediaStopMessage>? OnStopPressed;
public event Action<bool>? OnPlayPressed;
public event Action<float>? SetTime;
// counters and stuff
public EntityUid? Audio;
private sbyte _repeatCounter;
private sbyte _volumeCounter;
private float _volume = -2;
private MediaFile? _currentMediaFile;
private readonly string _waitText = Loc.GetString("media-wait-message");
public MediaPlayerMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_audioSystem = _entManager.System<AudioSystem>();
DisableButtons();
CurrentPlaying.Text = _waitText;
RepeatButton.OnPressed += _ => Repeat();
VolumeButton.OnPressed += _ => Volume();
StopButton.OnPressed += _ => Switch(_currentMediaFile);
PlaybackSlider.OnReleased += _ => SetTime?.Invoke(PlaybackSlider.Value);
PlayButton.OnPressed += _ =>
{
PlayPause(PlayButton.Pressed);
OnPlayPressed?.Invoke(PlayButton.Pressed);
};
Search.OnTextChanged += _ =>
{
if (MediaList.ChildCount == 0)
return;
foreach (var control in MediaList.Children.ToArray())
{
if (control is not MediaFile mediaFile)
continue;
var songName = $"{mediaFile.MusicAuthor.Text} {mediaFile.MusicName.Text}";
mediaFile.Visible = songName.Contains(Search.Text, StringComparison.CurrentCultureIgnoreCase);
}
};
// UpDown
StopButton.OnButtonDown += OnDown;
StopButton.OnButtonUp += OnUp;
PlayButton.OnButtonDown += OnDown;
PlayButton.OnButtonUp += OnUp;
VolumeButton.OnButtonDown += OnDown;
VolumeButton.OnButtonUp += OnUp;
}
#region Buttons events
private static void OnDown(BaseButton.ButtonEventArgs args)
{
args.Button.Modulate = Color.Gray;
}
private static void OnUp(BaseButton.ButtonEventArgs args)
{
args.Button.Modulate = Color.White;
}
/// <summary>
/// Called when the song field is selected.
/// </summary>
/// <param name="args">A field that stores data about a song</param>
private void OnSelect(MediaFile args)
{
// Если выбраная панель уже была выбрана - останавливаем музыку.
if (_currentMediaFile == args)
{
Switch(_currentMediaFile);
return;
}
// Если файл не совпадает с предидущим - останавливаем музыку
if (_currentMediaFile != null)
{
Switch(_currentMediaFile, args);
return;
}
EnableButtons();
SetTitle(newMedia: args);
PlayPause(true);
_currentMediaFile = args;
OnFileSelected?.Invoke(new MediaSelectedMessage(_volume, args.SongId, args.SongPath));
}
/// <summary>
/// Switch that turns music on/off
/// customizing the UI depending on the switch state
/// </summary>
/// <param name="oldMedia">Media that should be turned off and replaced with new one.</param>
/// <param name="newMedia">Media that should be turned on and shown in the UI with music</param>
private void Switch(MediaFile? oldMedia = null, MediaFile? newMedia = null)
{
if (oldMedia is null)
return;
SetTitle(oldMedia, newMedia);
if (newMedia is not null)
{
PlayPause(true);
EnableButtons();
_currentMediaFile = newMedia;
OnFileSelected?.Invoke(new MediaSelectedMessage(_volume, newMedia.SongId, newMedia.SongPath));
}
else
{
PlayPause(false);
DisableButtons();
_currentMediaFile = null;
OnStopPressed?.Invoke(new MediaStopMessage(false));
}
}
private void PlayPause(bool state)
{
if (state)
{
PlayButton.TexturePath = "/Textures/_Horizon/Interface/pause.png";
PlayButton.Pressed = state;
return;
}
PlayButton.TexturePath = "/Textures/_Horizon/Interface/play.png";
PlayButton.Pressed = state;
}
private void Volume()
{
switch (_volumeCounter)
{
case 0:
VolumeButton.TexturePath = "/Textures/_Horizon/Interface/volume_2.png";
_volume = -5;
break;
case 1:
VolumeButton.TexturePath = "/Textures/_Horizon/Interface/volume_3.png";
_volume = 0;
break;
case 2:
VolumeButton.TexturePath = "/Textures/_Horizon/Interface/volume_1.png";
_volume = -10;
_volumeCounter = -1;
break;
}
OnVolumePressed?.Invoke(new MediaVolumeMessage(_volume));
_volumeCounter++;
}
private void Repeat()
{
var type = RepeatType.None;
switch (_repeatCounter)
{
case 0:
RepeatButton.Modulate = Color.Gray;
type = RepeatType.Playlist;
break;
case 1:
RepeatButton.TexturePath = "/Textures/_Horizon/Interface/repeat_one.png";
type = RepeatType.Single;
break;
case 2:
RepeatButton.Modulate = Color.White;
RepeatButton.TexturePath = "/Textures/_Horizon/Interface/repeat.png";
type = RepeatType.None;
_repeatCounter = -1;
break;
}
OnRepeatPressed?.Invoke(new MediaRepeatMessage(type));
_repeatCounter++;
}
#endregion Buttons events
#region Events
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (Audio is null || PlaybackSlider.Disabled)
return;
DurationLabel.Text = _entManager.TryGetComponent(Audio, out AudioComponent? audioComp)
? $@"{TimeSpan.FromSeconds(audioComp.PlaybackPosition):mm\:ss} / {TimeSpan.FromSeconds(PlaybackSlider.MaxValue):mm\:ss}"
: $"00:00 / 00:00";
if (PlaybackSlider.Grabbed)
return;
if (audioComp != null || _entManager.TryGetComponent(Audio, out audioComp))
{
PlaybackSlider.SetValueWithoutEvent(audioComp.PlaybackPosition);
}
else if (PlayButton.Pressed)
{
PlaybackSlider.SetValueWithoutEvent(0f);
if (_repeatCounter == 0)
Switch(_currentMediaFile);
}
}
/// <summary>
/// Adds new tracks to the list
/// </summary>
/// <param name="files">Files we wish to add</param>
public void PopulateMediaList(List<MediaFilePrototype> files)
{
MediaList.RemoveAllChildren();
foreach (var file in files)
{
var mediaFile = new MediaFile()
{
SongId = file.ID,
MusicAuthor = { Text = $"{file.Author}" },
MusicName = { Text = $"{file.SongName}" },
MusicTimer = { Text = $@"{_audioSystem.GetAudioLength(_audioSystem.ResolveSound(file.SoundPath)):mm\:ss}" },
FullSongName = $"{Loc.GetString("media-now-playing-message")}:\n{file.Author} - {file.SongName}",
SongPath = file.SoundPath,
};
mediaFile.OnPanelClicked += OnSelect;
MediaList.AddChild(mediaFile);
}
}
/// <summary>
/// Set selected song, and length for slider
/// </summary>
/// <param name="length">Song length in seconds</param>
public void SetSliderLength(float length)
{
PlaybackSlider.MaxValue = length;
PlaybackSlider.SetValueWithoutEvent(0);
}
public void UpdateState(string id, RepeatType type, float volume)
{
// Setup old state of UI
SetupRepeatButton(type);
SetupVolumeButton(volume);
foreach (var control in MediaList.Children.ToArray())
{
if (control is not MediaFile mediaFile)
continue;
if (mediaFile.SongId != id)
continue;
SetTitle(newMedia: mediaFile);
mediaFile.MusicTitle.Modulate = Color.Green;
mediaFile.TitlePressed = true;
_currentMediaFile = mediaFile;
if (!_entManager.TryGetComponent(Audio, out AudioComponent? comp))
return;
EnableButtons();
PlayPause(comp.Playing);
}
}
private void EnableButtons()
{
// Enable
PlayButton.Disabled = false;
StopButton.Disabled = false;
PlaybackSlider.Disabled = false;
}
private void DisableButtons()
{
// Disable
PlayButton.Disabled = true;
StopButton.Disabled = true;
PlaybackSlider.Disabled = true;
}
private void SetupRepeatButton(RepeatType type)
{
switch (type)
{
case RepeatType.Playlist:
RepeatButton.Modulate = Color.Gray;
_repeatCounter = 1;
return;
case RepeatType.Single:
RepeatButton.Modulate = Color.Gray;
RepeatButton.TexturePath = "/Textures/_Horizon/Interface/repeat_one.png";
_repeatCounter = 2;
return;
case RepeatType.None:
RepeatButton.TexturePath = "/Textures/_Horizon/Interface/repeat.png";
_repeatCounter = 0;
return;
}
}
private void SetupVolumeButton(float volume)
{
switch (volume)
{
case -5:
VolumeButton.TexturePath = "/Textures/_Horizon/Interface/volume_2.png";
_volume = volume;
_volumeCounter = 1;
return;
case 0:
VolumeButton.TexturePath = "/Textures/_Horizon/Interface/volume_3.png";
_volume = volume;
_volumeCounter = 2;
return;
case -10:
VolumeButton.TexturePath = "/Textures/_Horizon/Interface/volume_1.png";
_volume = volume;
_volumeCounter = 0;
return;
}
}
public void ChangeTitle(string id)
{
foreach (var control in MediaList.Children.ToArray())
{
if (control is not MediaFile mediaFile || id != mediaFile.SongId)
continue;
EnableButtons();
PlayPause(true);
if (_currentMediaFile == mediaFile)
return;
mediaFile.TitlePressed = true;
mediaFile.MusicTitle.Modulate = Color.Green;
SetTitle(_currentMediaFile, mediaFile);
_currentMediaFile = mediaFile;
}
}
/// <summary>
/// Sets labels based on input data
/// </summary>
/// <param name="oldMedia">Media that should be disabled and removed from display in the UI</param>
/// <param name="newMedia">Media that should be enabled and add to display in the UI</param>
private void SetTitle(MediaFile? oldMedia = null, MediaFile? newMedia = null)
{
if (oldMedia is not null && oldMedia.TitlePressed)
{
oldMedia.TitlePressed = !oldMedia.TitlePressed;
oldMedia.MusicTitle.Modulate = Color.White;
}
if (newMedia is not null)
{
CurrentPlaying.Text = newMedia.FullSongName;
return;
}
CurrentPlaying.Text = _waitText;
DurationLabel.Text = "00:00 / 00:00";
}
#endregion
}