2019-01-31 10:17:42 +00:00
// 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.
2019-01-17 12:10:34 +00:00
2019-01-18 05:28:06 +00:00
using System ;
2019-01-17 12:10:34 +00:00
using osu.Framework.Allocation ;
2019-02-21 10:04:31 +00:00
using osu.Framework.Bindables ;
2019-01-17 12:10:34 +00:00
using osu.Framework.Graphics.Containers ;
2019-06-11 17:31:01 +00:00
using osu.Game.Database ;
2019-06-11 15:41:30 +00:00
using osu.Game.Online.API ;
2019-01-17 12:10:34 +00:00
2019-06-11 17:31:01 +00:00
namespace osu.Game.Online
2019-01-17 12:10:34 +00:00
{
2019-02-14 07:21:01 +00:00
/// <summary>
2019-11-17 12:48:23 +00:00
/// A component which tracks a <typeparamref name="TModel"/> through potential download/import/deletion.
2019-02-14 07:21:01 +00:00
/// </summary>
2019-06-11 17:31:01 +00:00
public abstract class DownloadTrackingComposite < TModel , TModelManager > : CompositeDrawable
2019-06-11 17:53:40 +00:00
where TModel : class , IEquatable < TModel >
2019-06-11 19:11:17 +00:00
where TModelManager : class , IModelDownloader < TModel >
2019-01-17 12:10:34 +00:00
{
2019-06-26 15:29:09 +00:00
protected readonly Bindable < TModel > Model = new Bindable < TModel > ( ) ;
2019-01-18 05:28:06 +00:00
2020-02-14 13:59:51 +00:00
[Resolved(CanBeNull = true)]
2020-02-14 13:14:00 +00:00
private TModelManager manager { get ; set ; }
2019-01-17 12:10:34 +00:00
2019-01-18 05:28:06 +00:00
/// <summary>
2019-11-17 12:48:23 +00:00
/// Holds the current download state of the <typeparamref name="TModel"/>, whether is has already been downloaded, is in progress, or is not downloaded.
2019-01-18 05:28:06 +00:00
/// </summary>
protected readonly Bindable < DownloadState > State = new Bindable < DownloadState > ( ) ;
2019-01-17 12:10:34 +00:00
2019-12-10 09:08:11 +00:00
protected readonly BindableNumber < double > Progress = new BindableNumber < double > { MinValue = 0 , MaxValue = 1 } ;
2019-01-17 12:10:34 +00:00
2019-06-11 17:31:01 +00:00
protected DownloadTrackingComposite ( TModel model = null )
2019-01-17 12:10:34 +00:00
{
2019-06-26 15:29:09 +00:00
Model . Value = model ;
2019-01-17 12:10:34 +00:00
}
2020-05-27 07:08:47 +00:00
private IBindable < WeakReference < TModel > > managedUpdated ;
2020-05-19 07:44:22 +00:00
private IBindable < WeakReference < TModel > > managerRemoved ;
private IBindable < WeakReference < ArchiveDownloadRequest < TModel > > > managerDownloadBegan ;
private IBindable < WeakReference < ArchiveDownloadRequest < TModel > > > managerDownloadFailed ;
2019-01-17 12:10:34 +00:00
[BackgroundDependencyLoader(true)]
2020-02-14 13:14:00 +00:00
private void load ( )
2019-01-17 12:10:34 +00:00
{
2019-06-26 15:29:09 +00:00
Model . BindValueChanged ( modelInfo = >
2019-02-13 19:04:49 +00:00
{
2019-06-11 17:31:01 +00:00
if ( modelInfo . NewValue = = null )
2019-02-13 19:04:49 +00:00
attachDownload ( null ) ;
2019-06-11 17:31:01 +00:00
else if ( manager . IsAvailableLocally ( modelInfo . NewValue ) )
2019-02-13 19:04:49 +00:00
State . Value = DownloadState . LocallyAvailable ;
else
2019-06-11 17:31:01 +00:00
attachDownload ( manager . GetExistingDownload ( modelInfo . NewValue ) ) ;
2019-02-13 19:04:49 +00:00
} , true ) ;
2019-01-18 05:28:06 +00:00
2020-05-19 07:44:22 +00:00
managerDownloadBegan = manager . DownloadBegan . GetBoundCopy ( ) ;
managerDownloadBegan . BindValueChanged ( downloadBegan ) ;
managerDownloadFailed = manager . DownloadFailed . GetBoundCopy ( ) ;
managerDownloadFailed . BindValueChanged ( downloadFailed ) ;
2020-05-27 07:08:47 +00:00
managedUpdated = manager . ItemUpdated . GetBoundCopy ( ) ;
managedUpdated . BindValueChanged ( itemUpdated ) ;
2020-05-19 07:44:22 +00:00
managerRemoved = manager . ItemRemoved . GetBoundCopy ( ) ;
managerRemoved . BindValueChanged ( itemRemoved ) ;
2019-01-17 12:10:34 +00:00
}
2020-05-19 07:44:22 +00:00
private void downloadBegan ( ValueChangedEvent < WeakReference < ArchiveDownloadRequest < TModel > > > weakRequest )
2019-08-05 08:58:16 +00:00
{
2020-05-19 07:44:22 +00:00
if ( weakRequest . NewValue . TryGetTarget ( out var request ) )
{
Schedule ( ( ) = >
{
if ( request . Model . Equals ( Model . Value ) )
attachDownload ( request ) ;
} ) ;
}
}
2019-08-05 08:58:16 +00:00
2020-05-19 07:44:22 +00:00
private void downloadFailed ( ValueChangedEvent < WeakReference < ArchiveDownloadRequest < TModel > > > weakRequest )
2019-08-05 08:58:16 +00:00
{
2020-05-19 07:44:22 +00:00
if ( weakRequest . NewValue . TryGetTarget ( out var request ) )
{
Schedule ( ( ) = >
{
if ( request . Model . Equals ( Model . Value ) )
attachDownload ( null ) ;
} ) ;
}
}
2019-08-05 08:58:16 +00:00
2019-06-26 12:52:37 +00:00
private ArchiveDownloadRequest < TModel > attachedRequest ;
2019-01-17 12:10:34 +00:00
2019-06-26 12:52:37 +00:00
private void attachDownload ( ArchiveDownloadRequest < TModel > request )
2019-01-18 05:28:06 +00:00
{
if ( attachedRequest ! = null )
{
attachedRequest . Failure - = onRequestFailure ;
attachedRequest . DownloadProgressed - = onRequestProgress ;
attachedRequest . Success - = onRequestSuccess ;
}
attachedRequest = request ;
if ( attachedRequest ! = null )
{
2019-01-31 10:08:45 +00:00
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 ;
}
2019-01-18 05:28:06 +00:00
}
else
{
State . Value = DownloadState . NotDownloaded ;
}
2019-01-17 12:10:34 +00:00
}
2019-02-14 07:21:01 +00:00
private void onRequestSuccess ( string _ ) = > Schedule ( ( ) = > State . Value = DownloadState . Downloaded ) ;
2019-01-17 12:10:34 +00:00
2019-02-14 07:21:01 +00:00
private void onRequestProgress ( float progress ) = > Schedule ( ( ) = > Progress . Value = progress ) ;
2019-01-17 12:10:34 +00:00
2019-02-14 07:21:01 +00:00
private void onRequestFailure ( Exception e ) = > Schedule ( ( ) = > attachDownload ( null ) ) ;
2019-01-17 12:10:34 +00:00
2020-05-27 07:08:47 +00:00
private void itemUpdated ( ValueChangedEvent < WeakReference < TModel > > weakItem )
2020-05-19 07:44:22 +00:00
{
if ( weakItem . NewValue . TryGetTarget ( out var item ) )
setDownloadStateFromManager ( item , DownloadState . LocallyAvailable ) ;
}
2019-02-13 19:11:46 +00:00
2020-05-19 07:44:22 +00:00
private void itemRemoved ( ValueChangedEvent < WeakReference < TModel > > weakItem )
{
if ( weakItem . NewValue . TryGetTarget ( out var item ) )
setDownloadStateFromManager ( item , DownloadState . NotDownloaded ) ;
}
2019-02-13 19:11:46 +00:00
2019-06-11 17:31:01 +00:00
private void setDownloadStateFromManager ( TModel s , DownloadState state ) = > Schedule ( ( ) = >
2019-01-17 12:10:34 +00:00
{
2019-06-26 15:29:09 +00:00
if ( ! s . Equals ( Model . Value ) )
2019-01-17 12:10:34 +00:00
return ;
2019-02-14 07:21:01 +00:00
State . Value = state ;
} ) ;
2019-06-26 15:29:38 +00:00
#region Disposal
protected override void Dispose ( bool isDisposing )
{
base . Dispose ( isDisposing ) ;
State . UnbindAll ( ) ;
attachDownload ( null ) ;
}
#endregion
2019-01-17 12:10:34 +00:00
}
2019-01-18 05:28:06 +00:00
}