mirror of
https://github.com/ppy/osu.git
synced 2025-03-15 01:27:20 +08:00
Merge pull request #15321 from peppy/beatmap-refactor/download-tracker
Replace `DownloadTrackingComposite` with instantiable `DownloadTracker` components
This commit is contained in:
commit
9e633a1b17
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Online
|
|||||||
|
|
||||||
private void addAvailabilityCheckStep(string description, Func<BeatmapAvailability> expected)
|
private void addAvailabilityCheckStep(string description, Func<BeatmapAvailability> expected)
|
||||||
{
|
{
|
||||||
AddAssert(description, () => availabilityTracker.Availability.Value.Equals(expected.Invoke()));
|
AddUntilStep(description, () => availabilityTracker.Availability.Value.Equals(expected.Invoke()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BeatmapInfo getTestBeatmapInfo(string archiveFile)
|
private static BeatmapInfo getTestBeatmapInfo(string archiveFile)
|
||||||
|
@ -13,6 +13,9 @@ namespace osu.Game.Beatmaps
|
|||||||
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
|
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
|
||||||
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
|
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
|
||||||
|
|
||||||
|
public override ArchiveDownloadRequest<BeatmapSetInfo> GetExistingDownload(BeatmapSetInfo model)
|
||||||
|
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
||||||
|
|
||||||
public BeatmapModelDownloader(IBeatmapModelManager beatmapModelManager, IAPIProvider api, GameHost host = null)
|
public BeatmapModelDownloader(IBeatmapModelManager beatmapModelManager, IAPIProvider api, GameHost host = null)
|
||||||
: base(beatmapModelManager, api, host)
|
: base(beatmapModelManager, api, host)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Database
|
|||||||
private readonly IModelManager<TModel> modelManager;
|
private readonly IModelManager<TModel> modelManager;
|
||||||
private readonly IAPIProvider api;
|
private readonly IAPIProvider api;
|
||||||
|
|
||||||
private readonly List<ArchiveDownloadRequest<TModel>> currentDownloads = new List<ArchiveDownloadRequest<TModel>>();
|
protected readonly List<ArchiveDownloadRequest<TModel>> CurrentDownloads = new List<ArchiveDownloadRequest<TModel>>();
|
||||||
|
|
||||||
protected ModelDownloader(IModelManager<TModel> modelManager, IAPIProvider api, IIpcHost importHost = null)
|
protected ModelDownloader(IModelManager<TModel> modelManager, IAPIProvider api, IIpcHost importHost = null)
|
||||||
{
|
{
|
||||||
@ -74,7 +74,7 @@ namespace osu.Game.Database
|
|||||||
if (!imported.Any())
|
if (!imported.Any())
|
||||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||||
|
|
||||||
currentDownloads.Remove(request);
|
CurrentDownloads.Remove(request);
|
||||||
}, TaskCreationOptions.LongRunning);
|
}, TaskCreationOptions.LongRunning);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ namespace osu.Game.Database
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
currentDownloads.Add(request);
|
CurrentDownloads.Add(request);
|
||||||
PostNotification?.Invoke(notification);
|
PostNotification?.Invoke(notification);
|
||||||
|
|
||||||
api.PerformAsync(request);
|
api.PerformAsync(request);
|
||||||
@ -96,7 +96,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
void triggerFailure(Exception error)
|
void triggerFailure(Exception error)
|
||||||
{
|
{
|
||||||
currentDownloads.Remove(request);
|
CurrentDownloads.Remove(request);
|
||||||
|
|
||||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model) => currentDownloads.Find(r => r.Model.Equals(model));
|
public abstract ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model);
|
||||||
|
|
||||||
private bool canDownload(TModel model) => GetExistingDownload(model) == null && api != null;
|
private bool canDownload(TModel model) => GetExistingDownload(model) == null && api != null;
|
||||||
|
|
||||||
|
155
osu.Game/Online/BeatmapDownloadTracker.cs
Normal file
155
osu.Game/Online/BeatmapDownloadTracker.cs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Online
|
||||||
|
{
|
||||||
|
public class BeatmapDownloadTracker : DownloadTracker<IBeatmapSetInfo>
|
||||||
|
{
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
protected BeatmapManager? Manager { get; private set; }
|
||||||
|
|
||||||
|
private ArchiveDownloadRequest<BeatmapSetInfo>? attachedRequest;
|
||||||
|
|
||||||
|
public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem)
|
||||||
|
: base(trackedItem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBindable<WeakReference<BeatmapSetInfo>>? managerUpdated;
|
||||||
|
private IBindable<WeakReference<BeatmapSetInfo>>? managerRemoved;
|
||||||
|
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadBegan;
|
||||||
|
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadFailed;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
if (Manager == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
||||||
|
var beatmapSetInfo = new BeatmapSetInfo { OnlineBeatmapSetID = TrackedItem.OnlineID };
|
||||||
|
|
||||||
|
if (Manager.IsAvailableLocally(beatmapSetInfo))
|
||||||
|
UpdateState(DownloadState.LocallyAvailable);
|
||||||
|
else
|
||||||
|
attachDownload(Manager.GetExistingDownload(beatmapSetInfo));
|
||||||
|
|
||||||
|
managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy();
|
||||||
|
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||||
|
managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy();
|
||||||
|
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||||
|
managerUpdated = Manager.ItemUpdated.GetBoundCopy();
|
||||||
|
managerUpdated.BindValueChanged(itemUpdated);
|
||||||
|
managerRemoved = Manager.ItemRemoved.GetBoundCopy();
|
||||||
|
managerRemoved.BindValueChanged(itemRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest)
|
||||||
|
{
|
||||||
|
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(request.Model, TrackedItem))
|
||||||
|
attachDownload(request);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest)
|
||||||
|
{
|
||||||
|
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(request.Model, TrackedItem))
|
||||||
|
attachDownload(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachDownload(ArchiveDownloadRequest<BeatmapSetInfo>? request)
|
||||||
|
{
|
||||||
|
if (attachedRequest != null)
|
||||||
|
{
|
||||||
|
attachedRequest.Failure -= onRequestFailure;
|
||||||
|
attachedRequest.DownloadProgressed -= onRequestProgress;
|
||||||
|
attachedRequest.Success -= onRequestSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachedRequest = request;
|
||||||
|
|
||||||
|
if (attachedRequest != null)
|
||||||
|
{
|
||||||
|
if (attachedRequest.Progress == 1)
|
||||||
|
{
|
||||||
|
UpdateProgress(1);
|
||||||
|
UpdateState(DownloadState.Importing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateProgress(attachedRequest.Progress);
|
||||||
|
UpdateState(DownloadState.Downloading);
|
||||||
|
|
||||||
|
attachedRequest.Failure += onRequestFailure;
|
||||||
|
attachedRequest.DownloadProgressed += onRequestProgress;
|
||||||
|
attachedRequest.Success += onRequestSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateState(DownloadState.NotDownloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRequestSuccess(string _) => Schedule(() => UpdateState(DownloadState.Importing));
|
||||||
|
|
||||||
|
private void onRequestProgress(float progress) => Schedule(() => UpdateProgress(progress));
|
||||||
|
|
||||||
|
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||||
|
|
||||||
|
private void itemUpdated(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||||
|
{
|
||||||
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(item, TrackedItem))
|
||||||
|
UpdateState(DownloadState.LocallyAvailable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void itemRemoved(ValueChangedEvent<WeakReference<BeatmapSetInfo>> weakItem)
|
||||||
|
{
|
||||||
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(item, TrackedItem))
|
||||||
|
UpdateState(DownloadState.NotDownloaded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkEquality(IBeatmapSetInfo x, IBeatmapSetInfo y) => x.OnlineID == y.OnlineID;
|
||||||
|
|
||||||
|
#region Disposal
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
attachDownload(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
39
osu.Game/Online/DownloadTracker.cs
Normal file
39
osu.Game/Online/DownloadTracker.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Online
|
||||||
|
{
|
||||||
|
public abstract class DownloadTracker<T> : Component
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
public readonly T TrackedItem;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the current download state of the download - whether is has already been downloaded, is in progress, or is not downloaded.
|
||||||
|
/// </summary>
|
||||||
|
public IBindable<DownloadState> State => state;
|
||||||
|
|
||||||
|
private readonly Bindable<DownloadState> state = new Bindable<DownloadState>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The progress of an active download.
|
||||||
|
/// </summary>
|
||||||
|
public IBindableNumber<double> Progress => progress;
|
||||||
|
|
||||||
|
private readonly BindableNumber<double> progress = new BindableNumber<double> { MinValue = 0, MaxValue = 1 };
|
||||||
|
|
||||||
|
protected DownloadTracker(T trackedItem)
|
||||||
|
{
|
||||||
|
TrackedItem = trackedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateState(DownloadState newState) => state.Value = newState;
|
||||||
|
|
||||||
|
protected void UpdateProgress(double newProgress) => progress.Value = newProgress;
|
||||||
|
}
|
||||||
|
}
|
@ -1,196 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Online.API;
|
|
||||||
|
|
||||||
namespace osu.Game.Online
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A component which tracks a <typeparamref name="TModel"/> through potential download/import/deletion.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class DownloadTrackingComposite<TModel, TModelManager> : CompositeDrawable
|
|
||||||
where TModel : class, IEquatable<TModel>
|
|
||||||
where TModelManager : class, IModelDownloader<TModel>, IModelManager<TModel>
|
|
||||||
{
|
|
||||||
protected readonly Bindable<TModel> Model = new Bindable<TModel>();
|
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
|
||||||
protected TModelManager Manager { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Holds the current download state of the <typeparamref name="TModel"/>, whether is has already been downloaded, is in progress, or is not downloaded.
|
|
||||||
/// </summary>
|
|
||||||
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
|
||||||
|
|
||||||
protected readonly BindableNumber<double> Progress = new BindableNumber<double> { MinValue = 0, MaxValue = 1 };
|
|
||||||
|
|
||||||
protected DownloadTrackingComposite(TModel model = null)
|
|
||||||
{
|
|
||||||
Model.Value = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IBindable<WeakReference<TModel>> managerUpdated;
|
|
||||||
private IBindable<WeakReference<TModel>> managerRemoved;
|
|
||||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadBegan;
|
|
||||||
private IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> managerDownloadFailed;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
Model.BindValueChanged(modelInfo =>
|
|
||||||
{
|
|
||||||
if (modelInfo.NewValue == null)
|
|
||||||
attachDownload(null);
|
|
||||||
else if (IsModelAvailableLocally())
|
|
||||||
State.Value = DownloadState.LocallyAvailable;
|
|
||||||
else
|
|
||||||
attachDownload(Manager?.GetExistingDownload(modelInfo.NewValue));
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
if (Manager == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy();
|
|
||||||
managerDownloadBegan.BindValueChanged(downloadBegan);
|
|
||||||
managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy();
|
|
||||||
managerDownloadFailed.BindValueChanged(downloadFailed);
|
|
||||||
managerUpdated = Manager.ItemUpdated.GetBoundCopy();
|
|
||||||
managerUpdated.BindValueChanged(itemUpdated);
|
|
||||||
managerRemoved = Manager.ItemRemoved.GetBoundCopy();
|
|
||||||
managerRemoved.BindValueChanged(itemRemoved);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks that a database model matches the one expected to be downloaded.
|
|
||||||
/// </summary>
|
|
||||||
/// <example>
|
|
||||||
/// For online play, this could be used to check that the databased model matches the online beatmap.
|
|
||||||
/// </example>
|
|
||||||
/// <param name="databasedModel">The model in database.</param>
|
|
||||||
protected virtual bool VerifyDatabasedModel([NotNull] TModel databasedModel) => true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the given model is available in the database.
|
|
||||||
/// By default, this calls <see cref="IModelManager{TModel}.IsAvailableLocally"/>,
|
|
||||||
/// but can be overriden to add additional checks for verifying the model in database.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual bool IsModelAvailableLocally() => Manager?.IsAvailableLocally(Model.Value) == true;
|
|
||||||
|
|
||||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<TModel>>> weakRequest)
|
|
||||||
{
|
|
||||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
if (request.Model.Equals(Model.Value))
|
|
||||||
attachDownload(request);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<TModel>>> weakRequest)
|
|
||||||
{
|
|
||||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
if (request.Model.Equals(Model.Value))
|
|
||||||
attachDownload(null);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArchiveDownloadRequest<TModel> attachedRequest;
|
|
||||||
|
|
||||||
private void attachDownload(ArchiveDownloadRequest<TModel> request)
|
|
||||||
{
|
|
||||||
if (attachedRequest != null)
|
|
||||||
{
|
|
||||||
attachedRequest.Failure -= onRequestFailure;
|
|
||||||
attachedRequest.DownloadProgressed -= onRequestProgress;
|
|
||||||
attachedRequest.Success -= onRequestSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
attachedRequest = request;
|
|
||||||
|
|
||||||
if (attachedRequest != null)
|
|
||||||
{
|
|
||||||
if (attachedRequest.Progress == 1)
|
|
||||||
{
|
|
||||||
Progress.Value = 1;
|
|
||||||
State.Value = DownloadState.Importing;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Progress.Value = attachedRequest.Progress;
|
|
||||||
State.Value = DownloadState.Downloading;
|
|
||||||
|
|
||||||
attachedRequest.Failure += onRequestFailure;
|
|
||||||
attachedRequest.DownloadProgressed += onRequestProgress;
|
|
||||||
attachedRequest.Success += onRequestSuccess;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
State.Value = DownloadState.NotDownloaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onRequestSuccess(string _) => Schedule(() => State.Value = DownloadState.Importing);
|
|
||||||
|
|
||||||
private void onRequestProgress(float progress) => Schedule(() => Progress.Value = progress);
|
|
||||||
|
|
||||||
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
|
||||||
|
|
||||||
private void itemUpdated(ValueChangedEvent<WeakReference<TModel>> weakItem)
|
|
||||||
{
|
|
||||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
if (!item.Equals(Model.Value))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!VerifyDatabasedModel(item))
|
|
||||||
{
|
|
||||||
State.Value = DownloadState.NotDownloaded;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
State.Value = DownloadState.LocallyAvailable;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void itemRemoved(ValueChangedEvent<WeakReference<TModel>> weakItem)
|
|
||||||
{
|
|
||||||
if (weakItem.NewValue.TryGetTarget(out var item))
|
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
if (item.Equals(Model.Value))
|
|
||||||
State.Value = DownloadState.NotDownloaded;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Disposal
|
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
|
|
||||||
State.UnbindAll();
|
|
||||||
|
|
||||||
attachDownload(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,8 +2,10 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -16,19 +18,27 @@ namespace osu.Game.Online.Rooms
|
|||||||
/// This differs from a regular download tracking composite as this accounts for the
|
/// This differs from a regular download tracking composite as this accounts for the
|
||||||
/// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap.
|
/// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OnlinePlayBeatmapAvailabilityTracker : DownloadTrackingComposite<BeatmapSetInfo, BeatmapManager>
|
public sealed class OnlinePlayBeatmapAvailabilityTracker : CompositeDrawable
|
||||||
{
|
{
|
||||||
public readonly IBindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
|
public readonly IBindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
|
||||||
|
|
||||||
|
// Required to allow child components to update. Can potentially be replaced with a `CompositeComponent` class if or when we make one.
|
||||||
|
protected override bool RequiresChildrenUpdate => true;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager beatmapManager { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The availability state of the currently selected playlist item.
|
/// The availability state of the currently selected playlist item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IBindable<BeatmapAvailability> Availability => availability;
|
public IBindable<BeatmapAvailability> Availability => availability;
|
||||||
|
|
||||||
private readonly Bindable<BeatmapAvailability> availability = new Bindable<BeatmapAvailability>(BeatmapAvailability.LocallyAvailable());
|
private readonly Bindable<BeatmapAvailability> availability = new Bindable<BeatmapAvailability>(BeatmapAvailability.NotDownloaded());
|
||||||
|
|
||||||
private ScheduledDelegate progressUpdate;
|
private ScheduledDelegate progressUpdate;
|
||||||
|
|
||||||
|
private BeatmapDownloadTracker downloadTracker;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
@ -40,58 +50,38 @@ namespace osu.Game.Online.Rooms
|
|||||||
if (item.NewValue == null)
|
if (item.NewValue == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Model.Value = item.NewValue.Beatmap.Value.BeatmapSet;
|
downloadTracker?.RemoveAndDisposeImmediately();
|
||||||
|
|
||||||
|
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
|
||||||
|
downloadTracker.State.BindValueChanged(_ => updateAvailability());
|
||||||
|
downloadTracker.Progress.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
if (downloadTracker.State.Value != DownloadState.Downloading)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// incoming progress changes are going to be at a very high rate.
|
||||||
|
// we don't want to flood the network with this, so rate limit how often we send progress updates.
|
||||||
|
if (progressUpdate?.Completed != false)
|
||||||
|
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddInternal(downloadTracker);
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
Progress.BindValueChanged(_ =>
|
|
||||||
{
|
|
||||||
if (State.Value != DownloadState.Downloading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// incoming progress changes are going to be at a very high rate.
|
|
||||||
// we don't want to flood the network with this, so rate limit how often we send progress updates.
|
|
||||||
if (progressUpdate?.Completed != false)
|
|
||||||
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
|
||||||
});
|
|
||||||
|
|
||||||
State.BindValueChanged(_ => updateAvailability(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool VerifyDatabasedModel(BeatmapSetInfo databasedSet)
|
|
||||||
{
|
|
||||||
int beatmapId = SelectedItem.Value?.Beatmap.Value.OnlineID ?? -1;
|
|
||||||
string checksum = SelectedItem.Value?.Beatmap.Value.MD5Hash;
|
|
||||||
|
|
||||||
var matchingBeatmap = databasedSet.Beatmaps.FirstOrDefault(b => b.OnlineBeatmapID == beatmapId && b.MD5Hash == checksum);
|
|
||||||
|
|
||||||
if (matchingBeatmap == null)
|
|
||||||
{
|
|
||||||
Logger.Log("The imported beatmap set does not match the online version.", LoggingTarget.Runtime, LogLevel.Important);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool IsModelAvailableLocally()
|
|
||||||
{
|
|
||||||
int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID;
|
|
||||||
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
|
|
||||||
|
|
||||||
var beatmap = Manager.QueryBeatmap(b => b.OnlineBeatmapID == onlineId && b.MD5Hash == checksum);
|
|
||||||
return beatmap?.BeatmapSet.DeletePending == false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAvailability()
|
private void updateAvailability()
|
||||||
{
|
{
|
||||||
switch (State.Value)
|
if (downloadTracker == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (downloadTracker.State.Value)
|
||||||
{
|
{
|
||||||
case DownloadState.NotDownloaded:
|
case DownloadState.NotDownloaded:
|
||||||
availability.Value = BeatmapAvailability.NotDownloaded();
|
availability.Value = BeatmapAvailability.NotDownloaded();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DownloadState.Downloading:
|
case DownloadState.Downloading:
|
||||||
availability.Value = BeatmapAvailability.Downloading((float)Progress.Value);
|
availability.Value = BeatmapAvailability.Downloading((float)downloadTracker.Progress.Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DownloadState.Importing:
|
case DownloadState.Importing:
|
||||||
@ -99,12 +89,27 @@ namespace osu.Game.Online.Rooms
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DownloadState.LocallyAvailable:
|
case DownloadState.LocallyAvailable:
|
||||||
availability.Value = BeatmapAvailability.LocallyAvailable();
|
bool hashMatches = checkHashValidity();
|
||||||
|
|
||||||
|
availability.Value = hashMatches ? BeatmapAvailability.LocallyAvailable() : BeatmapAvailability.NotDownloaded();
|
||||||
|
|
||||||
|
// only display a message to the user if a download seems to have just completed.
|
||||||
|
if (!hashMatches && downloadTracker.Progress.Value == 1)
|
||||||
|
Logger.Log("The imported beatmap set does not match the online version.", LoggingTarget.Runtime, LogLevel.Important);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(State));
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool checkHashValidity()
|
||||||
|
{
|
||||||
|
int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID;
|
||||||
|
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
|
||||||
|
|
||||||
|
return beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending) != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
157
osu.Game/Online/ScoreDownloadTracker.cs
Normal file
157
osu.Game/Online/ScoreDownloadTracker.cs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Online
|
||||||
|
{
|
||||||
|
public class ScoreDownloadTracker : DownloadTracker<ScoreInfo>
|
||||||
|
{
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
protected ScoreManager? Manager { get; private set; }
|
||||||
|
|
||||||
|
private ArchiveDownloadRequest<ScoreInfo>? attachedRequest;
|
||||||
|
|
||||||
|
public ScoreDownloadTracker(ScoreInfo trackedItem)
|
||||||
|
: base(trackedItem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBindable<WeakReference<ScoreInfo>>? managerUpdated;
|
||||||
|
private IBindable<WeakReference<ScoreInfo>>? managerRemoved;
|
||||||
|
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadBegan;
|
||||||
|
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadFailed;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
if (Manager == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Used to interact with manager classes that don't support interface types. Will eventually be replaced.
|
||||||
|
var scoreInfo = new ScoreInfo { OnlineScoreID = TrackedItem.OnlineScoreID };
|
||||||
|
|
||||||
|
if (Manager.IsAvailableLocally(scoreInfo))
|
||||||
|
UpdateState(DownloadState.LocallyAvailable);
|
||||||
|
else
|
||||||
|
attachDownload(Manager.GetExistingDownload(scoreInfo));
|
||||||
|
|
||||||
|
managerDownloadBegan = Manager.DownloadBegan.GetBoundCopy();
|
||||||
|
managerDownloadBegan.BindValueChanged(downloadBegan);
|
||||||
|
managerDownloadFailed = Manager.DownloadFailed.GetBoundCopy();
|
||||||
|
managerDownloadFailed.BindValueChanged(downloadFailed);
|
||||||
|
managerUpdated = Manager.ItemUpdated.GetBoundCopy();
|
||||||
|
managerUpdated.BindValueChanged(itemUpdated);
|
||||||
|
managerRemoved = Manager.ItemRemoved.GetBoundCopy();
|
||||||
|
managerRemoved.BindValueChanged(itemRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest)
|
||||||
|
{
|
||||||
|
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(request.Model, TrackedItem))
|
||||||
|
attachDownload(request);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest)
|
||||||
|
{
|
||||||
|
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(request.Model, TrackedItem))
|
||||||
|
attachDownload(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachDownload(ArchiveDownloadRequest<ScoreInfo>? request)
|
||||||
|
{
|
||||||
|
if (attachedRequest != null)
|
||||||
|
{
|
||||||
|
attachedRequest.Failure -= onRequestFailure;
|
||||||
|
attachedRequest.DownloadProgressed -= onRequestProgress;
|
||||||
|
attachedRequest.Success -= onRequestSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachedRequest = request;
|
||||||
|
|
||||||
|
if (attachedRequest != null)
|
||||||
|
{
|
||||||
|
if (attachedRequest.Progress == 1)
|
||||||
|
{
|
||||||
|
UpdateProgress(1);
|
||||||
|
UpdateState(DownloadState.Importing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateProgress(attachedRequest.Progress);
|
||||||
|
UpdateState(DownloadState.Downloading);
|
||||||
|
|
||||||
|
attachedRequest.Failure += onRequestFailure;
|
||||||
|
attachedRequest.DownloadProgressed += onRequestProgress;
|
||||||
|
attachedRequest.Success += onRequestSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateState(DownloadState.NotDownloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRequestSuccess(string _) => Schedule(() => UpdateState(DownloadState.Importing));
|
||||||
|
|
||||||
|
private void onRequestProgress(float progress) => Schedule(() => UpdateProgress(progress));
|
||||||
|
|
||||||
|
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||||
|
|
||||||
|
private void itemUpdated(ValueChangedEvent<WeakReference<ScoreInfo>> weakItem)
|
||||||
|
{
|
||||||
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (!checkEquality(item, TrackedItem))
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateState(DownloadState.NotDownloaded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void itemRemoved(ValueChangedEvent<WeakReference<ScoreInfo>> weakItem)
|
||||||
|
{
|
||||||
|
if (weakItem.NewValue.TryGetTarget(out var item))
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
if (checkEquality(item, TrackedItem))
|
||||||
|
UpdateState(DownloadState.NotDownloaded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkEquality(ScoreInfo x, ScoreInfo y) => x.OnlineScoreID == y.OnlineScoreID;
|
||||||
|
|
||||||
|
#region Disposal
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
attachDownload(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Online;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
|
||||||
{
|
|
||||||
public abstract class BeatmapDownloadTrackingComposite : DownloadTrackingComposite<BeatmapSetInfo, BeatmapManager>
|
|
||||||
{
|
|
||||||
public Bindable<BeatmapSetInfo> BeatmapSet => Model;
|
|
||||||
|
|
||||||
protected BeatmapDownloadTrackingComposite(BeatmapSetInfo set = null)
|
|
||||||
: base(set)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
@ -13,7 +14,7 @@ using osu.Game.Online;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapListing.Panels
|
namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||||
{
|
{
|
||||||
public class BeatmapPanelDownloadButton : BeatmapDownloadTrackingComposite
|
public class BeatmapPanelDownloadButton : CompositeDrawable
|
||||||
{
|
{
|
||||||
protected bool DownloadEnabled => button.Enabled.Value;
|
protected bool DownloadEnabled => button.Enabled.Value;
|
||||||
|
|
||||||
@ -26,16 +27,31 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
private readonly DownloadButton button;
|
private readonly DownloadButton button;
|
||||||
private Bindable<bool> noVideoSetting;
|
private Bindable<bool> noVideoSetting;
|
||||||
|
|
||||||
|
protected readonly BeatmapDownloadTracker DownloadTracker;
|
||||||
|
|
||||||
|
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||||
|
|
||||||
|
private readonly BeatmapSetInfo beatmapSet;
|
||||||
|
|
||||||
public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet)
|
public BeatmapPanelDownloadButton(BeatmapSetInfo beatmapSet)
|
||||||
: base(beatmapSet)
|
|
||||||
{
|
{
|
||||||
InternalChild = shakeContainer = new ShakeContainer
|
this.beatmapSet = beatmapSet;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
shakeContainer = new ShakeContainer
|
||||||
Child = button = new DownloadButton
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = button = new DownloadButton
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
State = { BindTarget = State }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
DownloadTracker = new BeatmapDownloadTracker(beatmapSet)
|
||||||
|
{
|
||||||
|
State = { BindTarget = State }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
button.Add(new DownloadProgressBar(beatmapSet)
|
button.Add(new DownloadProgressBar(beatmapSet)
|
||||||
@ -46,14 +62,6 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
button.State.BindTo(State);
|
|
||||||
FinishTransforms(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuGame game, BeatmapManager beatmaps, OsuConfigManager osuConfig)
|
private void load(OsuGame game, BeatmapManager beatmaps, OsuConfigManager osuConfig)
|
||||||
{
|
{
|
||||||
@ -61,7 +69,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
|
|
||||||
button.Action = () =>
|
button.Action = () =>
|
||||||
{
|
{
|
||||||
switch (State.Value)
|
switch (DownloadTracker.State.Value)
|
||||||
{
|
{
|
||||||
case DownloadState.Downloading:
|
case DownloadState.Downloading:
|
||||||
case DownloadState.Importing:
|
case DownloadState.Importing:
|
||||||
@ -73,11 +81,11 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
if (SelectedBeatmap.Value != null)
|
if (SelectedBeatmap.Value != null)
|
||||||
findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineBeatmapID;
|
findPredicate = b => b.OnlineBeatmapID == SelectedBeatmap.Value.OnlineBeatmapID;
|
||||||
|
|
||||||
game?.PresentBeatmap(BeatmapSet.Value, findPredicate);
|
game?.PresentBeatmap(beatmapSet, findPredicate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
beatmaps.Download(BeatmapSet.Value, noVideoSetting.Value);
|
beatmaps.Download(beatmapSet, noVideoSetting.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -92,7 +100,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (BeatmapSet.Value?.OnlineInfo?.Availability.DownloadDisabled ?? false)
|
if (beatmapSet.OnlineInfo?.Availability.DownloadDisabled ?? false)
|
||||||
{
|
{
|
||||||
button.Enabled.Value = false;
|
button.Enabled.Value = false;
|
||||||
button.TooltipText = "this beatmap is currently not available for download.";
|
button.TooltipText = "this beatmap is currently not available for download.";
|
||||||
@ -102,5 +110,11 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -12,13 +13,22 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapListing.Panels
|
namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||||
{
|
{
|
||||||
public class DownloadProgressBar : BeatmapDownloadTrackingComposite
|
public class DownloadProgressBar : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly ProgressBar progressBar;
|
private readonly ProgressBar progressBar;
|
||||||
|
private readonly BeatmapDownloadTracker downloadTracker;
|
||||||
|
|
||||||
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
|
public DownloadProgressBar(BeatmapSetInfo beatmapSet)
|
||||||
: base(beatmapSet)
|
|
||||||
{
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
progressBar = new ProgressBar(false)
|
||||||
|
{
|
||||||
|
Height = 0,
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
downloadTracker = new BeatmapDownloadTracker(beatmapSet),
|
||||||
|
};
|
||||||
AddInternal(progressBar = new ProgressBar(false)
|
AddInternal(progressBar = new ProgressBar(false)
|
||||||
{
|
{
|
||||||
Height = 0,
|
Height = 0,
|
||||||
@ -34,9 +44,9 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
|||||||
{
|
{
|
||||||
progressBar.FillColour = colours.Blue;
|
progressBar.FillColour = colours.Blue;
|
||||||
progressBar.BackgroundColour = Color4.Black.Opacity(0.7f);
|
progressBar.BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||||
progressBar.Current = Progress;
|
progressBar.Current.BindTarget = downloadTracker.Progress;
|
||||||
|
|
||||||
State.BindValueChanged(state =>
|
downloadTracker.State.BindValueChanged(state =>
|
||||||
{
|
{
|
||||||
switch (state.NewValue)
|
switch (state.NewValue)
|
||||||
{
|
{
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -21,8 +23,10 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapSet
|
namespace osu.Game.Overlays.BeatmapSet
|
||||||
{
|
{
|
||||||
public class BeatmapSetHeaderContent : BeatmapDownloadTrackingComposite
|
public class BeatmapSetHeaderContent : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
|
||||||
|
|
||||||
private const float transition_duration = 200;
|
private const float transition_duration = 200;
|
||||||
private const float buttons_height = 45;
|
private const float buttons_height = 45;
|
||||||
private const float buttons_spacing = 5;
|
private const float buttons_spacing = 5;
|
||||||
@ -45,6 +49,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
private readonly FillFlowContainer fadeContent;
|
private readonly FillFlowContainer fadeContent;
|
||||||
private readonly LoadingSpinner loading;
|
private readonly LoadingSpinner loading;
|
||||||
|
|
||||||
|
private BeatmapDownloadTracker downloadTracker;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
@ -222,13 +228,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
{
|
{
|
||||||
coverGradient.Colour = ColourInfo.GradientVertical(colourProvider.Background6.Opacity(0.3f), colourProvider.Background6.Opacity(0.8f));
|
coverGradient.Colour = ColourInfo.GradientVertical(colourProvider.Background6.Opacity(0.3f), colourProvider.Background6.Opacity(0.8f));
|
||||||
|
|
||||||
State.BindValueChanged(_ => updateDownloadButtons());
|
|
||||||
|
|
||||||
BeatmapSet.BindValueChanged(setInfo =>
|
BeatmapSet.BindValueChanged(setInfo =>
|
||||||
{
|
{
|
||||||
Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue;
|
Picker.BeatmapSet = rulesetSelector.BeatmapSet = author.BeatmapSet = beatmapAvailability.BeatmapSet = Details.BeatmapSet = setInfo.NewValue;
|
||||||
cover.OnlineInfo = setInfo.NewValue?.OnlineInfo;
|
cover.OnlineInfo = setInfo.NewValue?.OnlineInfo;
|
||||||
|
|
||||||
|
downloadTracker?.RemoveAndDisposeImmediately();
|
||||||
|
|
||||||
if (setInfo.NewValue == null)
|
if (setInfo.NewValue == null)
|
||||||
{
|
{
|
||||||
onlineStatusPill.FadeTo(0.5f, 500, Easing.OutQuint);
|
onlineStatusPill.FadeTo(0.5f, 500, Easing.OutQuint);
|
||||||
@ -241,6 +247,10 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
downloadTracker = new BeatmapDownloadTracker(setInfo.NewValue);
|
||||||
|
downloadTracker.State.BindValueChanged(_ => updateDownloadButtons());
|
||||||
|
AddInternal(downloadTracker);
|
||||||
|
|
||||||
fadeContent.FadeIn(500, Easing.OutQuint);
|
fadeContent.FadeIn(500, Easing.OutQuint);
|
||||||
|
|
||||||
loading.Hide();
|
loading.Hide();
|
||||||
@ -266,13 +276,13 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
{
|
{
|
||||||
if (BeatmapSet.Value == null) return;
|
if (BeatmapSet.Value == null) return;
|
||||||
|
|
||||||
if (BeatmapSet.Value.OnlineInfo.Availability.DownloadDisabled && State.Value != DownloadState.LocallyAvailable)
|
if (BeatmapSet.Value.OnlineInfo.Availability.DownloadDisabled && downloadTracker.State.Value != DownloadState.LocallyAvailable)
|
||||||
{
|
{
|
||||||
downloadButtonsContainer.Clear();
|
downloadButtonsContainer.Clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (State.Value)
|
switch (downloadTracker.State.Value)
|
||||||
{
|
{
|
||||||
case DownloadState.LocallyAvailable:
|
case DownloadState.LocallyAvailable:
|
||||||
// temporary for UX until new design is implemented.
|
// temporary for UX until new design is implemented.
|
||||||
|
@ -22,7 +22,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
namespace osu.Game.Overlays.BeatmapSet.Buttons
|
||||||
{
|
{
|
||||||
public class HeaderDownloadButton : BeatmapDownloadTrackingComposite, IHasTooltip
|
public class HeaderDownloadButton : CompositeDrawable, IHasTooltip
|
||||||
{
|
{
|
||||||
private const int text_size = 12;
|
private const int text_size = 12;
|
||||||
|
|
||||||
@ -35,9 +35,12 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
|||||||
private ShakeContainer shakeContainer;
|
private ShakeContainer shakeContainer;
|
||||||
private HeaderButton button;
|
private HeaderButton button;
|
||||||
|
|
||||||
|
private BeatmapDownloadTracker downloadTracker;
|
||||||
|
private readonly BeatmapSetInfo beatmapSet;
|
||||||
|
|
||||||
public HeaderDownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
public HeaderDownloadButton(BeatmapSetInfo beatmapSet, bool noVideo = false)
|
||||||
: base(beatmapSet)
|
|
||||||
{
|
{
|
||||||
|
this.beatmapSet = beatmapSet;
|
||||||
this.noVideo = noVideo;
|
this.noVideo = noVideo;
|
||||||
|
|
||||||
Width = 120;
|
Width = 120;
|
||||||
@ -49,13 +52,17 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
|||||||
{
|
{
|
||||||
FillFlowContainer textSprites;
|
FillFlowContainer textSprites;
|
||||||
|
|
||||||
AddInternal(shakeContainer = new ShakeContainer
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
shakeContainer = new ShakeContainer
|
||||||
Masking = true,
|
{
|
||||||
CornerRadius = 5,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = button = new HeaderButton { RelativeSizeAxes = Axes.Both },
|
Masking = true,
|
||||||
});
|
CornerRadius = 5,
|
||||||
|
Child = button = new HeaderButton { RelativeSizeAxes = Axes.Both },
|
||||||
|
},
|
||||||
|
downloadTracker = new BeatmapDownloadTracker(beatmapSet),
|
||||||
|
};
|
||||||
|
|
||||||
button.AddRange(new Drawable[]
|
button.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
@ -83,7 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new DownloadProgressBar(BeatmapSet.Value)
|
new DownloadProgressBar(beatmapSet)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
@ -92,20 +99,20 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
|||||||
|
|
||||||
button.Action = () =>
|
button.Action = () =>
|
||||||
{
|
{
|
||||||
if (State.Value != DownloadState.NotDownloaded)
|
if (downloadTracker.State.Value != DownloadState.NotDownloaded)
|
||||||
{
|
{
|
||||||
shakeContainer.Shake();
|
shakeContainer.Shake();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beatmaps.Download(BeatmapSet.Value, noVideo);
|
beatmaps.Download(beatmapSet, noVideo);
|
||||||
};
|
};
|
||||||
|
|
||||||
localUser.BindTo(api.LocalUser);
|
localUser.BindTo(api.LocalUser);
|
||||||
localUser.BindValueChanged(userChanged, true);
|
localUser.BindValueChanged(userChanged, true);
|
||||||
button.Enabled.BindValueChanged(enabledChanged, true);
|
button.Enabled.BindValueChanged(enabledChanged, true);
|
||||||
|
|
||||||
State.BindValueChanged(state =>
|
downloadTracker.State.BindValueChanged(state =>
|
||||||
{
|
{
|
||||||
switch (state.NewValue)
|
switch (state.NewValue)
|
||||||
{
|
{
|
||||||
@ -161,7 +168,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
|
|||||||
|
|
||||||
private LocalisableString getVideoSuffixText()
|
private LocalisableString getVideoSuffixText()
|
||||||
{
|
{
|
||||||
if (!BeatmapSet.Value.OnlineInfo.HasVideo)
|
if (!beatmapSet.OnlineInfo.HasVideo)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
return noVideo ? BeatmapsetsStrings.ShowDetailsDownloadNoVideo : BeatmapsetsStrings.ShowDetailsDownloadVideo;
|
return noVideo ? BeatmapsetsStrings.ShowDetailsDownloadNoVideo : BeatmapsetsStrings.ShowDetailsDownloadVideo;
|
||||||
|
@ -16,5 +16,8 @@ namespace osu.Game.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override ArchiveDownloadRequest<ScoreInfo> CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
protected override ArchiveDownloadRequest<ScoreInfo> CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
||||||
|
|
||||||
|
public override ArchiveDownloadRequest<ScoreInfo> GetExistingDownload(ScoreInfo model)
|
||||||
|
=> CurrentDownloads.Find(r => r.Model.OnlineScoreID == model.OnlineScoreID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,10 +248,7 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
protected virtual IEnumerable<Drawable> CreateButtons() =>
|
protected virtual IEnumerable<Drawable> CreateButtons() =>
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new PlaylistDownloadButton(Item)
|
new PlaylistDownloadButton(Item),
|
||||||
{
|
|
||||||
Size = new Vector2(50, 30)
|
|
||||||
},
|
|
||||||
new PlaylistRemoveButton
|
new PlaylistRemoveButton
|
||||||
{
|
{
|
||||||
Size = new Vector2(30, 30),
|
Size = new Vector2(30, 30),
|
||||||
@ -282,28 +279,33 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PlaylistDownloadButton : BeatmapPanelDownloadButton
|
private sealed class PlaylistDownloadButton : BeatmapPanelDownloadButton
|
||||||
{
|
{
|
||||||
private readonly PlaylistItem playlistItem;
|
private readonly PlaylistItem playlistItem;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmapManager { get; set; }
|
private BeatmapManager beatmapManager { get; set; }
|
||||||
|
|
||||||
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
// required for download tracking, as this button hides itself. can probably be removed with a bit of consideration.
|
||||||
|
public override bool IsPresent => true;
|
||||||
|
|
||||||
|
private const float width = 50;
|
||||||
|
|
||||||
public PlaylistDownloadButton(PlaylistItem playlistItem)
|
public PlaylistDownloadButton(PlaylistItem playlistItem)
|
||||||
: base(playlistItem.Beatmap.Value.BeatmapSet)
|
: base(playlistItem.Beatmap.Value.BeatmapSet)
|
||||||
{
|
{
|
||||||
this.playlistItem = playlistItem;
|
this.playlistItem = playlistItem;
|
||||||
|
|
||||||
|
Size = new Vector2(width, 30);
|
||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
State.BindValueChanged(stateChanged, true);
|
State.BindValueChanged(stateChanged, true);
|
||||||
FinishTransforms(true);
|
|
||||||
|
// base implementation calls FinishTransforms, so should be run after the above state update.
|
||||||
|
base.LoadComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stateChanged(ValueChangedEvent<DownloadState> state)
|
private void stateChanged(ValueChangedEvent<DownloadState> state)
|
||||||
@ -315,12 +317,16 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
if (beatmapManager.QueryBeatmap(b => b.MD5Hash == playlistItem.Beatmap.Value.MD5Hash) == null)
|
if (beatmapManager.QueryBeatmap(b => b.MD5Hash == playlistItem.Beatmap.Value.MD5Hash) == null)
|
||||||
State.Value = DownloadState.NotDownloaded;
|
State.Value = DownloadState.NotDownloaded;
|
||||||
else
|
else
|
||||||
this.FadeTo(0, 500);
|
{
|
||||||
|
this.FadeTo(0, 500)
|
||||||
|
.ResizeWidthTo(0, 500, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.FadeTo(1, 500);
|
this.ResizeWidthTo(width, 500, Easing.OutQuint)
|
||||||
|
.FadeTo(1, 500);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,9 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
private IBindable<WeakReference<BeatmapSetInfo>> managerUpdated;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; private set; }
|
private OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker { get; set; }
|
||||||
|
|
||||||
protected IBindable<BeatmapAvailability> BeatmapAvailability => BeatmapAvailabilityTracker.Availability;
|
protected IBindable<BeatmapAvailability> BeatmapAvailability => beatmapAvailabilityTracker.Availability;
|
||||||
|
|
||||||
public readonly Room Room;
|
public readonly Room Room;
|
||||||
private readonly bool allowEdit;
|
private readonly bool allowEdit;
|
||||||
@ -88,7 +88,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
Padding = new MarginPadding { Top = Header.HEIGHT };
|
Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||||
|
|
||||||
BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
beatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||||
{
|
{
|
||||||
SelectedItem = { BindTarget = SelectedItem }
|
SelectedItem = { BindTarget = SelectedItem }
|
||||||
};
|
};
|
||||||
@ -103,7 +103,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
BeatmapAvailabilityTracker,
|
beatmapAvailabilityTracker,
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
@ -12,13 +13,17 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Ranking
|
namespace osu.Game.Screens.Ranking
|
||||||
{
|
{
|
||||||
public class ReplayDownloadButton : DownloadTrackingComposite<ScoreInfo, ScoreManager>
|
public class ReplayDownloadButton : CompositeDrawable
|
||||||
{
|
{
|
||||||
public Bindable<ScoreInfo> Score => Model;
|
public readonly Bindable<ScoreInfo> Score = new Bindable<ScoreInfo>();
|
||||||
|
|
||||||
|
protected readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
|
||||||
|
|
||||||
private DownloadButton button;
|
private DownloadButton button;
|
||||||
private ShakeContainer shakeContainer;
|
private ShakeContainer shakeContainer;
|
||||||
|
|
||||||
|
private ScoreDownloadTracker downloadTracker;
|
||||||
|
|
||||||
private ReplayAvailability replayAvailability
|
private ReplayAvailability replayAvailability
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -26,7 +31,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
if (State.Value == DownloadState.LocallyAvailable)
|
if (State.Value == DownloadState.LocallyAvailable)
|
||||||
return ReplayAvailability.Local;
|
return ReplayAvailability.Local;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Model.Value?.Hash))
|
if (!string.IsNullOrEmpty(Score.Value?.Hash))
|
||||||
return ReplayAvailability.Online;
|
return ReplayAvailability.Online;
|
||||||
|
|
||||||
return ReplayAvailability.NotAvailable;
|
return ReplayAvailability.NotAvailable;
|
||||||
@ -34,8 +39,8 @@ namespace osu.Game.Screens.Ranking
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ReplayDownloadButton(ScoreInfo score)
|
public ReplayDownloadButton(ScoreInfo score)
|
||||||
: base(score)
|
|
||||||
{
|
{
|
||||||
|
Score.Value = score;
|
||||||
Size = new Vector2(50, 30);
|
Size = new Vector2(50, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,11 +61,11 @@ namespace osu.Game.Screens.Ranking
|
|||||||
switch (State.Value)
|
switch (State.Value)
|
||||||
{
|
{
|
||||||
case DownloadState.LocallyAvailable:
|
case DownloadState.LocallyAvailable:
|
||||||
game?.PresentScore(Model.Value, ScorePresentType.Gameplay);
|
game?.PresentScore(Score.Value, ScorePresentType.Gameplay);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DownloadState.NotDownloaded:
|
case DownloadState.NotDownloaded:
|
||||||
scores.Download(Model.Value, false);
|
scores.Download(Score.Value, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DownloadState.Importing:
|
case DownloadState.Importing:
|
||||||
@ -70,17 +75,25 @@ namespace osu.Game.Screens.Ranking
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
State.BindValueChanged(state =>
|
Score.BindValueChanged(score =>
|
||||||
{
|
{
|
||||||
button.State.Value = state.NewValue;
|
downloadTracker?.RemoveAndDisposeImmediately();
|
||||||
|
|
||||||
|
if (score.NewValue != null)
|
||||||
|
{
|
||||||
|
AddInternal(downloadTracker = new ScoreDownloadTracker(score.NewValue)
|
||||||
|
{
|
||||||
|
State = { BindTarget = State }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable;
|
||||||
updateTooltip();
|
updateTooltip();
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
Model.BindValueChanged(_ =>
|
State.BindValueChanged(state =>
|
||||||
{
|
{
|
||||||
button.Enabled.Value = replayAvailability != ReplayAvailability.NotAvailable;
|
button.State.Value = state.NewValue;
|
||||||
|
|
||||||
updateTooltip();
|
updateTooltip();
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user