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