Browse Source

Make browser GetItemsAsync trully async and lazy

pull/10603/head
Max Katz 4 years ago
parent
commit
2fd5e6b9d9
  1. 16
      src/Browser/Avalonia.Browser/Interop/GeneralHelpers.cs
  2. 6
      src/Browser/Avalonia.Browser/Interop/StorageHelper.cs
  3. 47
      src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs
  4. 7
      src/Browser/Avalonia.Browser/webapp/modules/avalonia/generalHelpers.ts
  5. 10
      src/Browser/Avalonia.Browser/webapp/modules/storage/storageItem.ts

16
src/Browser/Avalonia.Browser/Interop/GeneralHelpers.cs

@ -1,4 +1,5 @@
using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks;
namespace Avalonia.Browser.Interop;
@ -8,15 +9,22 @@ internal static partial class GeneralHelpers
public static partial JSObject[] ItemsArrayAt(JSObject jsObject, string key);
public static JSObject[] GetPropertyAsJSObjectArray(this JSObject jsObject, string key) => ItemsArrayAt(jsObject, key);
[JSImport("GeneralHelpers.itemAt", AvaloniaModule.MainModuleName)]
public static partial JSObject ItemAtInt(JSObject jsObject, int key);
public static JSObject GetArrayItem(this JSObject jsObject, int key) => ItemAtInt(jsObject, key);
[JSImport("GeneralHelpers.itemsArrayAt", AvaloniaModule.MainModuleName)]
public static partial string[] ItemsArrayAtAsStrings(JSObject jsObject, string key);
public static string[] GetPropertyAsStringArray(this JSObject jsObject, string key) => ItemsArrayAtAsStrings(jsObject, key);
[JSImport("GeneralHelpers.callMethod", AvaloniaModule.MainModuleName)]
public static partial string IntCallMethodString(JSObject jsObject, string name);
public static partial string IntCallMethodStr(JSObject jsObject, string name);
[JSImport("GeneralHelpers.callMethod", AvaloniaModule.MainModuleName)]
public static partial string IntCallMethodStrStr(JSObject jsObject, string name, string arg1);
[JSImport("GeneralHelpers.callMethod", AvaloniaModule.MainModuleName)]
public static partial string IntCallMethodStringString(JSObject jsObject, string name, string arg1);
public static partial Task<JSObject?> IntCallMethodPromiseObj(JSObject jsObject, string name);
public static string CallMethodString(this JSObject jsObject, string name) => IntCallMethodString(jsObject, name);
public static string CallMethodString(this JSObject jsObject, string name, string arg1) => IntCallMethodStringString(jsObject, name, arg1);
public static string CallMethodString(this JSObject jsObject, string name) => IntCallMethodStr(jsObject, name);
public static string CallMethodString(this JSObject jsObject, string name, string arg1) => IntCallMethodStrStr(jsObject, name, arg1);
public static Task<JSObject?> CallMethodObjectAsync(this JSObject jsObject, string name) => IntCallMethodPromiseObj(jsObject, name);
}

6
src/Browser/Avalonia.Browser/Interop/StorageHelper.cs

@ -40,9 +40,9 @@ internal static partial class StorageHelper
[JSImport("StorageItem.openRead", AvaloniaModule.StorageModuleName)]
public static partial Task<JSObject> OpenRead(JSObject item);
[JSImport("StorageItem.getItems", AvaloniaModule.StorageModuleName)]
[return: JSMarshalAs<JSType.Promise<JSType.Object>>]
public static partial Task<JSObject?> GetItems(JSObject item);
[JSImport("StorageItem.getItemsIterator", AvaloniaModule.StorageModuleName)]
[return: JSMarshalAs<JSType.Object>]
public static partial JSObject? GetItemsIterator(JSObject item);
[JSImport("StorageItems.itemsArray", AvaloniaModule.StorageModuleName)]
public static partial JSObject[] ItemsArray(JSObject item);

47
src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs

@ -258,24 +258,45 @@ internal class JSStorageFolder : JSStorageItem, IStorageBookmarkFolder
{
}
public async Task<IReadOnlyList<IStorageItem>> GetItemsAsync()
public async IAsyncEnumerable<IStorageItem> GetItemsAsync()
{
using var items = await StorageHelper.GetItems(FileHandle);
if (items is null)
using var itemsIterator = StorageHelper.GetItemsIterator(FileHandle);
if (itemsIterator is null)
{
return Array.Empty<IStorageItem>();
yield break;
}
var itemsArray = StorageHelper.ItemsArray(items);
while (true)
{
var nextResult = await itemsIterator.CallMethodObjectAsync("next");
if (nextResult is null)
{
yield break;
}
var isDone = nextResult.GetPropertyAsBoolean("done");
if (isDone)
{
yield break;
}
return itemsArray
.Select(reference => reference.GetPropertyAsString("kind") switch
var valArray = nextResult.GetPropertyAsJSObject("value");
var storageItem = valArray?.GetArrayItem(1); // 0 - item name, 1 - item instance
if (storageItem is null)
{
"directory" => (IStorageItem)new JSStorageFolder(reference),
"file" => new JSStorageFile(reference),
_ => null
})
.Where(i => i is not null)
.ToArray()!;
yield break;
}
var kind = storageItem.GetPropertyAsString("kind");
switch (kind)
{
case "directory":
yield return new JSStorageFolder(storageItem);
break;
case "file":
yield return new JSStorageFile(storageItem);
break;
}
}
}
}

7
src/Browser/Avalonia.Browser/webapp/modules/avalonia/generalHelpers.ts

@ -1,5 +1,5 @@
export class GeneralHelpers {
public static itemsArrayAt(instance: any, key: string): any[] {
public static itemsArrayAt(instance: any, key: any): any[] {
const items = instance[key];
if (!items) {
return [];
@ -12,6 +12,11 @@ export class GeneralHelpers {
return retItems;
}
public static itemAt(instance: any, key: any): any {
const item = instance[key];
return item;
}
public static callMethod(instance: any, name: string /*, args */): any {
const args = Array.prototype.slice.call(arguments, 2);
return instance[name].apply(instance, args);

10
src/Browser/Avalonia.Browser/webapp/modules/storage/storageItem.ts

@ -89,16 +89,12 @@ export class StorageItem {
}
}
public static async getItems(item: StorageItem): Promise<StorageItems> {
public static getItemsIterator(item: StorageItem): any | null {
if (item.kind !== "directory" || !item.handle) {
return new StorageItems([]);
return null;
}
const items: StorageItem[] = [];
for await (const [, value] of (item.handle as any).entries()) {
items.push(new StorageItem(value));
}
return new StorageItems(items);
return (item.handle as any).entries();
}
private async verityPermissions(mode: "read" | "readwrite"): Promise<void | never> {

Loading…
Cancel
Save