Rework preview tracks to reduce usage complexities

This commit is contained in:
smoogipoo 2018-06-21 16:19:07 +09:00
parent ab2889da1f
commit b2066c5d73
10 changed files with 172 additions and 90 deletions

View File

@ -0,0 +1,16 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Audio
{
/// <summary>
/// Interface for objects that can own <see cref="IPreviewTrack"/>s.
/// </summary>
/// <remarks>
/// <see cref="IPreviewTrackOwner"/>s can cancel the currently playing <see cref="PreviewTrack"/> through the
/// global <see cref="PreviewTrackManager"/> if they're the owner of the playing <see cref="PreviewTrack"/>.
/// </remarks>
public interface IPreviewTrackOwner
{
}
}

View File

@ -5,49 +5,87 @@
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Framework.Threading;
namespace osu.Game.Audio
{
public class PreviewTrack : Component
public abstract class PreviewTrack : Component
{
public Track Track { get; private set; }
private readonly OverlayContainer owner;
private readonly BeatmapSetInfo beatmapSetInfo;
public event Action Stopped;
public event Action Started;
public PreviewTrack(BeatmapSetInfo beatmapSetInfo, OverlayContainer owner)
{
this.beatmapSetInfo = beatmapSetInfo;
this.owner = owner;
}
private Track track;
private bool wasPlaying;
[BackgroundDependencyLoader]
private void load(PreviewTrackManager previewTrackManager)
private void load()
{
Track = previewTrackManager.Get(this, beatmapSetInfo);
}
track = GetTrack();
public void Start()
{
Track.Restart();
Started?.Invoke();
if (track != null)
track.Looping = false;
}
/// <summary>
/// Stop preview playback
/// Length of the track.
/// </summary>
/// <param name="source">An <see cref="OverlayContainer"/> which is probably the owner of this <see cref="PreviewTrack"/></param>
public void Stop(OverlayContainer source = null)
public double Length => track?.Length ?? 0;
/// <summary>
/// The current track time.
/// </summary>
public double CurrentTime => track?.CurrentTime ?? 0;
/// <summary>
/// Whether the track is loaded.
/// </summary>
public bool TrackLoaded => track?.IsLoaded ?? false;
protected override void Update()
{
if (source != null && owner != source)
base.Update();
// Todo: Track currently doesn't signal its completion, so we have to handle it manually
if (track != null && wasPlaying && track.HasCompleted)
Stop();
}
private ScheduledDelegate startDelegate;
public void Start() => startDelegate = Schedule(() =>
{
if (!IsLoaded)
return;
Track.Stop();
if (track == null)
return;
if (wasPlaying)
return;
wasPlaying = true;
track.Restart();
Started?.Invoke();
});
public void Stop()
{
startDelegate?.Cancel();
if (!IsLoaded)
return;
if (track == null)
return;
if (!wasPlaying)
return;
wasPlaying = false;
track.Stop();
Stopped?.Invoke();
}
protected abstract Track GetTrack();
}
}

View File

@ -13,17 +13,17 @@ namespace osu.Game.Audio
{
public class PreviewTrackManager : Component
{
private readonly BindableDouble muteBindable = new BindableDouble();
private AudioManager audio;
private TrackManager trackManager;
private BindableDouble muteBindable;
public PreviewTrack CurrentTrack { get; private set; }
private TrackManagerPreviewTrack current;
[BackgroundDependencyLoader]
private void load(AudioManager audio, FrameworkConfigManager config)
{
trackManager = new TrackManager(new OnlineStore());
muteBindable = new BindableDouble();
this.audio = audio;
audio.AddItem(trackManager);
@ -31,30 +31,55 @@ private void load(AudioManager audio, FrameworkConfigManager config)
config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume);
}
protected override void Update()
public PreviewTrack Get(BeatmapSetInfo beatmapSetInfo)
{
if (CurrentTrack?.Track.HasCompleted ?? false)
CurrentTrack.Stop();
var track = new TrackManagerPreviewTrack(beatmapSetInfo, trackManager);
base.Update();
}
public Track Get(PreviewTrack previewTrack, BeatmapSetInfo beatmapSetInfo)
{
previewTrack.Started += () =>
track.Started += () =>
{
CurrentTrack?.Stop();
CurrentTrack = previewTrack;
current?.Stop();
current = track;
audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable);
};
previewTrack.Stopped += () =>
track.Stopped += () =>
{
CurrentTrack = null;
current = null;
audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
};
return trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3");
return track;
}
public void Stop(IPreviewTrackOwner source)
{
if (current?.Owner != source)
return;
current?.Stop();
current = null;
}
private class TrackManagerPreviewTrack : PreviewTrack
{
public IPreviewTrackOwner Owner { get; private set; }
private readonly BeatmapSetInfo beatmapSetInfo;
private readonly TrackManager trackManager;
public TrackManagerPreviewTrack(BeatmapSetInfo beatmapSetInfo, TrackManager trackManager)
{
this.beatmapSetInfo = beatmapSetInfo;
this.trackManager = trackManager;
}
[BackgroundDependencyLoader]
private void load(IPreviewTrackOwner owner)
{
Owner = owner;
}
protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo?.OnlineBeatmapSetID}.mp3");
}
}
}

View File

@ -8,20 +8,32 @@
using osu.Framework.Input;
using OpenTK;
using osu.Framework.Configuration;
using osu.Game.Audio;
using osu.Game.Overlays;
namespace osu.Game.Graphics.Containers
{
public class OsuFocusedOverlayContainer : FocusedOverlayContainer
public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner
{
private SampleChannel samplePopIn;
private SampleChannel samplePopOut;
private PreviewTrackManager previewTrackManager;
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
[BackgroundDependencyLoader(true)]
private void load(OsuGame osuGame, AudioManager audio)
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies;
}
[BackgroundDependencyLoader(true)]
private void load(OsuGame osuGame, AudioManager audio, PreviewTrackManager previewTrackManager)
{
this.previewTrackManager = previewTrackManager;
if (osuGame != null)
OverlayActivationMode.BindTo(osuGame.OverlayActivationMode);
@ -66,5 +78,11 @@ private void onStateChanged(Visibility visibility)
break;
}
}
protected override void PopOut()
{
base.PopOut();
previewTrackManager.Stop(this);
}
}
}

View File

@ -83,7 +83,7 @@ protected override void Update()
if (Playing.Value && preview != null)
{
// prevent negative (potential infinite) width if a track without length was loaded
progress.Width = preview.Track.Length > 0 ? (float)(preview.Track.CurrentTime / preview.Track.Length) : 0f;
progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f;
}
else
progress.Width = 0;

View File

@ -8,7 +8,6 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@ -38,7 +37,6 @@ public class BeatmapSetOverlay : WaveOverlayContainer
private readonly ScrollContainer scroll;
private BeatmapSetInfo beatmapSet;
private PreviewTrackManager previewTrackManager;
public BeatmapSetInfo BeatmapSet
{
@ -111,11 +109,10 @@ public BeatmapSetOverlay()
}
[BackgroundDependencyLoader]
private void load(APIAccess api, RulesetStore rulesets, PreviewTrackManager previewTrackManager)
private void load(APIAccess api, RulesetStore rulesets)
{
this.api = api;
this.rulesets = rulesets;
this.previewTrackManager = previewTrackManager;
}
protected override void PopIn()
@ -127,8 +124,6 @@ protected override void PopIn()
protected override void PopOut()
{
base.PopOut();
previewTrackManager.CurrentTrack?.Stop(this);
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out).OnComplete(_ => BeatmapSet = null);
}

View File

@ -113,9 +113,9 @@ protected override void Update()
{
base.Update();
if (PreviewPlaying && Preview != null && Preview.Track.IsLoaded)
if (PreviewPlaying && Preview != null && Preview.TrackLoaded)
{
PreviewBar.Width = (float)(Preview.Track.CurrentTime / Preview.Track.Length);
PreviewBar.Width = (float)(Preview.CurrentTime / Preview.Length);
}
}

View File

@ -29,21 +29,14 @@ public BeatmapSetInfo BeatmapSet
if (value == beatmapSet) return;
beatmapSet = value;
Preview?.Stop(parentOverlayContainer);
if (Preview != null)
{
Preview.Stop();
RemoveInternal(Preview);
Preview = null;
}
Playing.Value = false;
Preview = null;
}
}
private OverlayContainer parentOverlayContainer
{
get
{
var d = Parent;
while (!(d is OverlayContainer))
d = d.Parent;
return (OverlayContainer)d;
}
}
@ -89,9 +82,13 @@ public PlayButton(BeatmapSetInfo setInfo = null)
Playing.ValueChanged += playingStateChanged;
}
private PreviewTrackManager previewTrackManager;
[BackgroundDependencyLoader]
private void load(OsuColour colour)
private void load(OsuColour colour, PreviewTrackManager previewTrackManager)
{
this.previewTrackManager = previewTrackManager;
hoverColour = colour.Yellow;
}
@ -103,15 +100,18 @@ protected override bool OnClick(InputState state)
{
loading = true;
LoadComponentAsync(
Preview = new PreviewTrack(beatmapSet, parentOverlayContainer),
t =>
{
Preview.Started += () => Playing.Value = true;
Preview.Stopped += () => Playing.Value = false;
Preview.Start();
loading = false;
});
Preview = previewTrackManager.Get(beatmapSet);
Preview.Started += () => Playing.Value = true;
Preview.Stopped += () => Playing.Value = false;
LoadComponentAsync(Preview, t =>
{
AddInternal(t);
Preview.Start();
loading = false;
});
return true;
}

View File

@ -262,7 +262,7 @@ private void updateSearch()
if (Header.Tabs.Current.Value == DirectTab.Search && (Filter.Search.Text == string.Empty || currentQuery == string.Empty)) return;
previewTrackManager.CurrentTrack?.Stop(this);
previewTrackManager.Stop(this);
getSetsRequest = new SearchBeatmapSetsRequest(currentQuery.Value ?? string.Empty,
((FilterControl)Filter).Ruleset.Value,
@ -289,12 +289,6 @@ private void updateSearch()
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;
protected override void PopOut()
{
previewTrackManager.CurrentTrack?.Stop(this);
base.PopOut();
}
public class ResultCounts
{
public readonly int Artists;

View File

@ -8,7 +8,6 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Audio;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
@ -31,7 +30,6 @@ public class UserProfileOverlay : WaveOverlayContainer
protected ProfileHeader Header;
private SectionsContainer<ProfileSection> sectionsContainer;
private ProfileTabControl tabs;
private PreviewTrackManager previewTrackManager;
public const float CONTENT_X_MARGIN = 50;
@ -58,10 +56,9 @@ public UserProfileOverlay()
}
[BackgroundDependencyLoader]
private void load(APIAccess api, PreviewTrackManager previewTrackManager)
private void load(APIAccess api)
{
this.api = api;
this.previewTrackManager = previewTrackManager;
}
protected override void PopIn()
@ -73,7 +70,6 @@ protected override void PopIn()
protected override void PopOut()
{
base.PopOut();
previewTrackManager.CurrentTrack?.Stop(this);
FadeEdgeEffectTo(0, WaveContainer.DISAPPEAR_DURATION, Easing.Out);
}