// Copyright (c) ppy Pty Ltd . 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.Framework.Graphics.Containers; using osu.Game.Database; using osu.Game.Online.API; namespace osu.Game.Online { /// /// A component which tracks a beatmap through potential download/import/deletion. /// public abstract class DownloadTrackingComposite : CompositeDrawable where TModel : class, IEquatable where TModelManager : class, IModelDownloader { protected readonly Bindable Model = new Bindable(); private TModelManager manager; /// /// Holds the current download state of the beatmap, whether is has already been downloaded, is in progress, or is not downloaded. /// protected readonly Bindable State = new Bindable(); protected readonly Bindable Progress = new Bindable(); protected DownloadTrackingComposite(TModel model = null) { Model.Value = model; } [BackgroundDependencyLoader(true)] private void load(TModelManager manager) { this.manager = manager; Model.BindValueChanged(modelInfo => { if (modelInfo.NewValue == null) attachDownload(null); else if (manager.IsAvailableLocally(modelInfo.NewValue)) State.Value = DownloadState.LocallyAvailable; else attachDownload(manager.GetExistingDownload(modelInfo.NewValue)); }, true); manager.DownloadBegan += download => { if (download.Model.Equals(Model.Value)) attachDownload(download); }; manager.DownloadFailed += download => { if (download.Model.Equals(Model.Value)) attachDownload(null); }; manager.ItemAdded += itemAdded; manager.ItemRemoved += itemRemoved; } private ArchiveDownloadRequest attachedRequest; private void attachDownload(ArchiveDownloadRequest request) { if (attachedRequest != null) { attachedRequest.Failure -= onRequestFailure; attachedRequest.DownloadProgressed -= onRequestProgress; attachedRequest.Success -= onRequestSuccess; } attachedRequest = request; if (attachedRequest != null) { if (attachedRequest.Progress == 1) { State.Value = DownloadState.Downloaded; Progress.Value = 1; } else { State.Value = DownloadState.Downloading; Progress.Value = attachedRequest.Progress; attachedRequest.Failure += onRequestFailure; attachedRequest.DownloadProgressed += onRequestProgress; attachedRequest.Success += onRequestSuccess; } } else { State.Value = DownloadState.NotDownloaded; } } private void onRequestSuccess(string _) => Schedule(() => State.Value = DownloadState.Downloaded); private void onRequestProgress(float progress) => Schedule(() => Progress.Value = progress); private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null)); private void itemAdded(TModel s) => setDownloadStateFromManager(s, DownloadState.LocallyAvailable); private void itemRemoved(TModel s) => setDownloadStateFromManager(s, DownloadState.NotDownloaded); private void setDownloadStateFromManager(TModel s, DownloadState state) => Schedule(() => { if (!s.Equals(Model.Value)) return; State.Value = state; }); #region Disposal protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); if (manager != null) { manager.DownloadBegan -= attachDownload; manager.ItemAdded -= itemAdded; } State.UnbindAll(); attachDownload(null); } #endregion } }