Skip to content

Commit

Permalink
feat(dragdrop): Fix DataPackage on WASM
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed Oct 16, 2020
1 parent 991e885 commit 4ec12d1
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 18 deletions.
45 changes: 36 additions & 9 deletions src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.wasm.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using System;
#nullable enable

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.UI.Core;
using Uno.Extensions.Specialized;
using Uno.Foundation;

namespace Windows.ApplicationModel.DataTransfer
Expand All @@ -11,23 +15,46 @@ public static partial class Clipboard

public static void Clear() => SetClipboardText(string.Empty);

public static void SetContent(DataPackage content)
public static void SetContent(DataPackage? content)
{
if (content?.Text != null)
var data = content?.GetView(); // Freezes the DataPackage
if (data?.AvailableFormats.Contains(StandardDataFormats.Text) ?? false)
{
SetClipboardText(content.Text);
CoreDispatcher.Main.RunAsync(
CoreDispatcherPriority.High,
async () =>
{
var text = await data.GetTextAsync();
SetClipboardText(text);
});
}
}

public static DataPackageView GetContent()
{
var dataPackageView = new DataPackageView();
var dataPackage = new DataPackage();

dataPackage.SetDataProvider(
StandardDataFormats.Text,
async ct =>
{
var text = string.Empty;
await CoreDispatcher.Main.RunAsync(
CoreDispatcherPriority.High,
async _ => text = await GetClipboardText());
var command = $"{JsType}.getText()";
var getTextTask = WebAssemblyRuntime.InvokeAsync(command);
dataPackageView.SetFormatTask(StandardDataFormats.Text, getTextTask);
return text;
});

return dataPackageView;
return dataPackage.GetView();
}

private static async Task<string> GetClipboardText()
{
var command = $"{JsType}.getText();";
var text = await WebAssemblyRuntime.InvokeAsync(command);

return text;
}

private static void SetClipboardText(string text)
Expand Down
27 changes: 27 additions & 0 deletions src/Uno.UWP/ApplicationModel/DataTransfer/DataPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Uno;
using Uno.Extensions;
using Uno.Logging;

namespace Windows.ApplicationModel.DataTransfer
{
Expand All @@ -28,6 +33,28 @@ public void SetData(string formatId, object value)
=> current.SetItem(arg.id, arg.v);
}

internal void SetDataProvider(string formatId, FuncAsync<object> delayRenderer)
{
SetData(formatId, new DataProviderHandler(SetDataCore));

async void SetDataCore(DataProviderRequest request)
{
var deferral = request.GetDeferral();
try
{
await delayRenderer(request.CancellationToken);
}
catch (Exception e)
{
this.Log().Error($"Failed to asynchronously retrieve the data for od '{formatId}'", e);
}
finally
{
deferral.Complete();
}
}
}

public void SetDataProvider(string formatId, DataProviderHandler delayRenderer)
=> SetData(formatId, delayRenderer);

Expand Down
18 changes: 11 additions & 7 deletions src/Uno.UWP/ApplicationModel/DataTransfer/DataPackageView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,24 @@ private IAsyncOperation<TResult> GetData<TResult>(string format)
}
}

private static async Task<TResult> GetDataAsync<TResult>(string format, DataProviderHandler asyncData)
private async Task<TResult> GetDataAsync<TResult>(string format, DataProviderHandler asyncData)
{
var timeout = TimeSpan.FromSeconds(30); // Arbitrary value that should be validated against UWP
var request = new DataProviderRequest(format, DateTimeOffset.Now + timeout); // We create teh request before the ct, so we ensure that Deadline will be before the actual timeout

using var ct = new CancellationTokenSource(timeout);
using (ct.Token.Register(request.Abort))
var request = new DataProviderRequest(format);
try
{
asyncData(request);

var data = await request.GetData();

return (TResult)data;
}
catch (Exception e)
{
throw new InvalidOperationException($"Failed to asynchronously load the data of id '{format}'", e);
}
finally
{
request.Dispose();
}
}

public void ReportOperationCompleted(DataPackageOperation value)
Expand Down
21 changes: 19 additions & 2 deletions src/Uno.UWP/ApplicationModel/DataTransfer/DataProviderRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,37 @@

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Uno.Disposables;

namespace Windows.ApplicationModel.DataTransfer
{
public partial class DataProviderRequest
{
private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(30); // Arbitrary value that should be validated against UWP

private readonly TaskCompletionSource<object> _asyncData = new TaskCompletionSource<object>();
private readonly CancellationTokenSource _ct;
private readonly IDisposable _autoAbort;
private object? _data;
private DataProviderDeferral? _deferral;

internal DataProviderRequest(string formatId, DateTimeOffset deadline)
internal DataProviderRequest(string formatId)
{
FormatId = formatId;
Deadline = deadline;
Deadline = DateTimeOffset.Now + _timeout; // We create the Deadline the ct, so we ensure that it will be before the actual timeout

_ct = new CancellationTokenSource(_timeout);
_autoAbort = _ct.Token.Register(Abort);
}

public string FormatId { get; }

public DateTimeOffset Deadline { get; }

internal CancellationToken CancellationToken => _ct.Token;

public DataProviderDeferral GetDeferral()
=> _deferral ??= new DataProviderDeferral(Complete);

Expand Down Expand Up @@ -51,5 +62,11 @@ private void Complete()
_asyncData.TrySetResult(_data);
}
}

internal void Dispose() // We do not implement IDisposable as it would defer with the UWP contract, and we don't want the app to dispose this request.
{
_autoAbort.Dispose();
_ct.Dispose();
}
}
}

0 comments on commit 4ec12d1

Please sign in to comment.