// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing.Panels { public class PlayButton : Container { public readonly BindableBool Playing = new BindableBool(); public PreviewTrack Preview { get; private set; } private BeatmapSetInfo beatmapSet; public BeatmapSetInfo BeatmapSet { get => beatmapSet; set { if (value == beatmapSet) return; beatmapSet = value; Preview?.Stop(); Preview?.Expire(); Preview = null; Playing.Value = false; } } private Color4 hoverColour; private readonly SpriteIcon icon; private readonly LoadingSpinner loadingSpinner; private const float transition_duration = 500; private bool loading { set { if (value) { icon.FadeTo(0.5f, transition_duration, Easing.OutQuint); loadingSpinner.Show(); } else { icon.FadeTo(1, transition_duration, Easing.OutQuint); loadingSpinner.Hide(); } } } public PlayButton(BeatmapSetInfo setInfo = null) { BeatmapSet = setInfo; AddRange(new Drawable[] { icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, FillMode = FillMode.Fit, RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.Play, }, loadingSpinner = new LoadingSpinner { Size = new Vector2(15), }, }); Playing.ValueChanged += playingStateChanged; } [Resolved] private PreviewTrackManager previewTrackManager { get; set; } [BackgroundDependencyLoader] private void load(OsuColour colour) { hoverColour = colour.Yellow; } protected override bool OnClick(ClickEvent e) { Playing.Toggle(); return true; } protected override bool OnHover(HoverEvent e) { icon.FadeColour(hoverColour, 120, Easing.InOutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { if (!Playing.Value) icon.FadeColour(Color4.White, 120, Easing.InOutQuint); base.OnHoverLost(e); } private void playingStateChanged(ValueChangedEvent e) { icon.Icon = e.NewValue ? FontAwesome.Solid.Stop : FontAwesome.Solid.Play; icon.FadeColour(e.NewValue || IsHovered ? hoverColour : Color4.White, 120, Easing.InOutQuint); if (e.NewValue) { if (BeatmapSet == null) { Playing.Value = false; return; } if (Preview != null) { attemptStart(); return; } loading = true; LoadComponentAsync(Preview = previewTrackManager.Get(beatmapSet), preview => { // beatmapset may have changed. if (Preview != preview) return; AddInternal(preview); loading = false; preview.Stopped += () => Playing.Value = false; // user may have changed their mind. if (Playing.Value) attemptStart(); }); } else { Preview?.Stop(); loading = false; } } private void attemptStart() { if (Preview?.Start() != true) Playing.Value = false; } protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); Playing.Value = false; } } }