Skip to content

Commit

Permalink
Added DownloadStarted callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-luberda committed Sep 24, 2016
1 parent 1d54b74 commit 8bbb1d8
Show file tree
Hide file tree
Showing 17 changed files with 149 additions and 35 deletions.
4 changes: 2 additions & 2 deletions source/FFImageLoading.Common/Cache/IDownloadCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public interface IDownloadCache

HttpClient DownloadHttpClient { get; set; }

Task<DownloadedData> GetAsync (string url, CancellationToken token, TimeSpan? duration = null, string key = null, CacheType? cacheType = null);
Task<DownloadedData> GetAsync (string url, CancellationToken token, Action<DownloadInformation> onDownloadStarted, TimeSpan? duration = null, string key = null, CacheType? cacheType = null);

Task<CacheStream> GetStreamAsync (string url, CancellationToken token, TimeSpan? duration = null, string key = null, CacheType? cacheType = null);
Task<CacheStream> GetStreamAsync (string url, CancellationToken token, Action<DownloadInformation> onDownloadStarted, TimeSpan? duration = null, string key = null, CacheType? cacheType = null);
}
}

15 changes: 15 additions & 0 deletions source/FFImageLoading.Common/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Linq;

namespace FFImageLoading
{
public static class StringExtensions
{
public static string ToSanitizedKey(this string key)
{
return new string(key.ToCharArray()
.Where(c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
.ToArray());
}
}
}
6 changes: 4 additions & 2 deletions source/FFImageLoading.Common/FFImageLoading.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,17 @@
<Compile Include="Concurrency\PlatformHelper.cs" />
<Compile Include="Helpers\IPlatformPerformance.cs" />
<Compile Include="Helpers\MiniLoggerWrapper.cs" />
<Compile Include="Work\DownloadInformation.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<ProjectExtensions>
<MonoDevelop>
<Properties>
<Policies>
<TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
<TextStylePolicy FileWidth="80" TabWidth="4" TabsToSpaces="True" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="True" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" IndentSwitchSection="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
</Policies>
</Properties>
</MonoDevelop>
Expand Down
25 changes: 25 additions & 0 deletions source/FFImageLoading.Common/Work/DownloadInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
namespace FFImageLoading
{
public class DownloadInformation
{
public DownloadInformation(string url, string customCacheKey, string fileName, bool allowDiskCaching, TimeSpan? cacheValidity)
{
Url = url;
CustomCacheKey = customCacheKey;
FileName = fileName?.ToSanitizedKey();
AllowDiskCaching = allowDiskCaching;
CacheValidity = cacheValidity;
}

public string Url { get; private set; }

public string CustomCacheKey { get; private set; }

public string FileName { get; private set; }

public bool AllowDiskCaching { get; private set; }

public TimeSpan? CacheValidity { get; private set; }
}
}
38 changes: 24 additions & 14 deletions source/FFImageLoading.Common/Work/TaskParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,27 +77,21 @@ private TaskParameter()
Transformations = new List<ITransformation>();

// default values so we don't have a null value
OnSuccess = (s,r) =>
{
};

OnError = ex =>
{
};

OnFinish = scheduledWork =>
{
};
OnSuccess = (s,r) => {};
OnError = ex => { };
OnFinish = scheduledWork => { };
OnDownloadStarted = downloadInformation => { };
}

public void Dispose()
{
if (!_disposed)
{
// remove reference to callbacks
OnSuccess = (s, r) => {};
OnError = (e) => {};
OnFinish = (sw) => {};
OnSuccess = (s, r) => { };
OnError = ex => { };
OnFinish = scheduledWork => { };
OnDownloadStarted = downloadInformation => { };

Transformations = null;
Stream = null;
Expand Down Expand Up @@ -138,6 +132,8 @@ public void Dispose()

public Action<IScheduledWork> OnFinish { get; private set; }

public Action<DownloadInformation> OnDownloadStarted { get; private set; }

public List<ITransformation> Transformations { get; private set; }

public bool? LoadTransparencyChannel { get; private set; }
Expand Down Expand Up @@ -403,6 +399,20 @@ public TaskParameter Finish(Action<IScheduledWork> action)
OnFinish = action;
return this;
}

/// <summary>
/// If image starts downloading from Internet this callback is called
/// </summary>
/// <returns>The TaskParameter instance for chaining the call.</returns>
/// <param name="action">Action.</param>
public TaskParameter DownloadStarted(Action<DownloadInformation> action)
{
if (action == null)
throw new Exception("Given lambda should not be null.");

OnDownloadStarted = action;
return this;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public UrlStreamResolver(TaskParameter parameter, IDownloadCache downloadCache)

public async Task<WithLoadingResult<Stream>> GetStream(string identifier, CancellationToken token)
{
var cachedStream = await DownloadCache.GetStreamAsync(identifier, token, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);
var cachedStream = await DownloadCache.GetStreamAsync(identifier, token, Parameters.OnDownloadStarted, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);

var imageInformation = new ImageInformation();
imageInformation.SetPath(identifier);
Expand Down
3 changes: 3 additions & 0 deletions source/FFImageLoading.Forms.Droid/CachedImageRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ private void UpdateBitmap(CachedImage previous = null)
imageLoader.Error((exception) =>
element.OnError(new CachedImageEvents.ErrorEventArgs(exception)));

imageLoader.DownloadStarted((downloadInformation) =>
element.OnDownloadStarted(new CachedImageEvents.DownloadStartedEventArgs(downloadInformation)));

_currentTask = imageLoader.Into(imageView);
}
}
Expand Down
3 changes: 3 additions & 0 deletions source/FFImageLoading.Forms.Touch/CachedImageRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ private void SetImage(CachedImage oldElement = null)

imageLoader.Error((exception) =>
element.OnError(new CachedImageEvents.ErrorEventArgs(exception)));

imageLoader.DownloadStarted((downloadInformation) =>
element.OnDownloadStarted(new CachedImageEvents.DownloadStartedEventArgs(downloadInformation)));

_currentTask = imageLoader.Into(Control);
}
Expand Down
3 changes: 3 additions & 0 deletions source/FFImageLoading.Forms.WinRT/CachedImageRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ private async void UpdateSource()
imageLoader.Error((exception) =>
element.OnError(new CachedImageEvents.ErrorEventArgs(exception)));

imageLoader.DownloadStarted((downloadInformation) =>
element.OnDownloadStarted(new CachedImageEvents.DownloadStartedEventArgs(downloadInformation)));

_currentTask = imageLoader.Into(Control);
}
}
Expand Down
10 changes: 10 additions & 0 deletions source/FFImageLoading.Forms/Args/CachedImageEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ public FinishEventArgs(IScheduledWork scheduledWork)

public IScheduledWork ScheduledWork { get; private set; }
}

public class DownloadStartedEventArgs : EventArgs
{
public DownloadStartedEventArgs(DownloadInformation downloadInformation)
{
DownloadInformation = downloadInformation;
}

public DownloadInformation DownloadInformation { get; private set; }
}
}
}

39 changes: 39 additions & 0 deletions source/FFImageLoading.Forms/CachedImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,45 @@ internal void OnFinish(CachedImageEvents.FinishEventArgs e)
var finishCommand = FinishCommand;
if (finishCommand != null && finishCommand.CanExecute(e))
finishCommand.Execute(e);
}


/// <summary>
/// Occurs when an image starts downloading from web.
/// </summary>
public event EventHandler<EventArgs> DownloadStarted;

/// <summary>
/// The DownloadStartedCommandProperty.
/// </summary>
public static readonly BindableProperty DownloadStartedCommandProperty = BindableProperty.Create(nameof(DownloadStartedCommand), typeof(ICommand), typeof(CachedImage));

/// <summary>
/// Gets or sets the DownloadStartedCommand.
/// Occurs when an image starts downloading from web.
/// Command parameter: EventArgs
/// </summary>
/// <value>The download started command.</value>
public ICommand DownloadStartedCommand
{
get
{
return (ICommand)GetValue(DownloadStartedCommandProperty);
}
set
{
SetValue(DownloadStartedCommandProperty, value);
}
}

internal void OnDownloadStarted(EventArgs e)
{
var handler = DownloadStarted;
if (handler != null) handler(this, e);

var downloadStartedCommand = DownloadStartedCommand;
if (downloadStartedCommand != null && downloadStartedCommand.CanExecute(e))
downloadStartedCommand.Execute(e);
}

/// <summary>
Expand Down
22 changes: 15 additions & 7 deletions source/FFImageLoading.Shared/Cache/DownloadCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,47 @@ public async Task<string> GetDiskCacheFilePathAsync(string url, string key = nul
return await _diskCache.GetFilePathAsync(filename);
}

public async Task<DownloadedData> GetAsync(string url, CancellationToken token, TimeSpan? duration = null, string key = null, CacheType? cacheType = null)
public async Task<DownloadedData> GetAsync(string url, CancellationToken token, Action<DownloadInformation> onDownloadStarted, TimeSpan? duration = null, string key = null, CacheType? cacheType = null)
{
string filename = string.IsNullOrWhiteSpace(key) ? _md5Helper.MD5(url) : _md5Helper.MD5(key);
var allowDiskCaching = AllowDiskCaching(cacheType);
string filepath = allowDiskCaching == false ? null : await _diskCache.GetFilePathAsync(filename);

if (allowDiskCaching)
{
byte[] data = await _diskCache.TryGetAsync(filename, token).ConfigureAwait(false);
if (data != null)
return new DownloadedData(filepath, data) { RetrievedFromDiskCache = true };
}

var bytes = await DownloadBytesAndCacheAsync(url, filename, filepath, token, duration, cacheType).ConfigureAwait(false);
var downloadInformation = new DownloadInformation(url, key, filename, allowDiskCaching, duration);
onDownloadStarted?.Invoke(downloadInformation);

var bytes = await DownloadBytesAndCacheAsync(url, filename, token, duration, cacheType).ConfigureAwait(false);
return new DownloadedData(filepath, bytes);
}

public async Task<CacheStream> GetStreamAsync(string url, CancellationToken token, TimeSpan? duration = null, string key = null, CacheType? cacheType = null)
public async Task<CacheStream> GetStreamAsync(string url, CancellationToken token, Action<DownloadInformation> onDownloadStarted, TimeSpan? duration = null, string key = null, CacheType? cacheType = null)
{
string filename = string.IsNullOrWhiteSpace(key) ? _md5Helper.MD5(url) : _md5Helper.MD5(key);
var allowDiskCaching = AllowDiskCaching(cacheType);
string filepath = allowDiskCaching == false ? null : await _diskCache.GetFilePathAsync(filename);
// string filepath = allowDiskCaching == false ? null : await _diskCache.GetFilePathAsync(filename);

if (allowDiskCaching)
{
var diskStream = await _diskCache.TryGetStreamAsync(filename).ConfigureAwait(false);
if (diskStream != null)
return new CacheStream(diskStream, true);
}

var memoryStream = await DownloadStreamAndCacheAsync(url, filename, filepath, token, duration, cacheType).ConfigureAwait(false);
var downloadInformation = new DownloadInformation(url, key, filename, allowDiskCaching, duration);
onDownloadStarted?.Invoke(downloadInformation);

var memoryStream = await DownloadStreamAndCacheAsync(url, filename, token, duration, cacheType).ConfigureAwait(false);
return new CacheStream(memoryStream, false);
}

private async Task<MemoryStream> DownloadStreamAndCacheAsync(string url, string filename, string filepath, CancellationToken token, TimeSpan? duration, CacheType? cacheType)
private async Task<MemoryStream> DownloadStreamAndCacheAsync(string url, string filename, CancellationToken token, TimeSpan? duration, CacheType? cacheType)
{
var responseBytes = await DownloadAsync(url, filename, token).ConfigureAwait(false);
if (responseBytes == null)
Expand All @@ -78,7 +86,7 @@ private async Task<MemoryStream> DownloadStreamAndCacheAsync(string url, string
return memoryStream;
}

private async Task<byte[]> DownloadBytesAndCacheAsync(string url, string filename, string filepath, CancellationToken token, TimeSpan? duration, CacheType? cacheType)
private async Task<byte[]> DownloadBytesAndCacheAsync(string url, string filename, CancellationToken token, TimeSpan? duration, CacheType? cacheType)
{
var responseBytes = await DownloadAsync(url, filename, token).ConfigureAwait(false);
if (responseBytes == null)
Expand Down
4 changes: 1 addition & 3 deletions source/FFImageLoading.Shared/Cache/SimpleDiskCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,7 @@ void CleanCallback(object state)

private string SanitizeKey(string key)
{
return new string (key
.Where (c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
.ToArray ());
return key.ToSanitizedKey();
}
}
}
2 changes: 1 addition & 1 deletion source/FFImageLoading.Shared/Work/ImageLoaderTaskBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ protected async virtual Task<GenerateResult> TryDownloadImageAsync()
if (Parameters.Source != ImageSource.Url)
throw new InvalidOperationException("DownloadOnly: Only Url ImageSource is supported.");

var data = await DownloadCache.GetStreamAsync(Parameters.Path, CancellationToken.Token, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);
var data = await DownloadCache.GetStreamAsync(Parameters.Path, CancellationToken.Token, Parameters.OnDownloadStarted, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);
using (var imageStream = data.ImageStream)
{
if (!data.RetrievedFromDiskCache)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public UrlDataResolver(TaskParameter parameter, IDownloadCache downloadCache) {

public async Task<UIImageData> GetData(string identifier, CancellationToken token)
{
var downloadedData = await DownloadCache.GetAsync(identifier, token, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);
var downloadedData = await DownloadCache.GetAsync(identifier, token, Parameters.OnDownloadStarted, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);
var bytes = downloadedData.Bytes;
var path = downloadedData.CachedPath;
var result = downloadedData.RetrievedFromDiskCache ? LoadingResult.DiskCache : LoadingResult.Internet;
Expand Down
4 changes: 1 addition & 3 deletions source/FFImageLoading.Windows/Cache/SimpleDiskCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,7 @@ async Task WaitForPendingWriteIfExists(string key)

string SanitizeKey(string key)
{
return new string(key
.Where(c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
.ToArray());
return key.ToSanitizedKey();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public UrlDataResolver(TaskParameter parameter, IDownloadCache downloadCache)

public async Task<WithLoadingResult<Stream>> GetStream(string identifier, CancellationToken token)
{
var cachedStream = await DownloadCache.GetStreamAsync(identifier, token, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);
var cachedStream = await DownloadCache.GetStreamAsync(identifier, token, Parameters.OnDownloadStarted, Parameters.CacheDuration, Parameters.CustomCacheKey, Parameters.CacheType).ConfigureAwait(false);

var imageInformation = new ImageInformation();
imageInformation.SetPath(identifier);
Expand Down

0 comments on commit 8bbb1d8

Please sign in to comment.