document-picker/windows/ReactNativeDocumentPicker/RCTDocumentPickerModule.cs
Ahab 39fad8fd67
feat(windows): store directory for later access (#639)
Co-authored-by: mackenzie <mackenzie@yourmoms>
2023-03-21 22:00:14 +01:00

277 lines
8.6 KiB
C#

using Microsoft.ReactNative.Managed;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI.Core;
namespace RNDocumentPicker
{
[ReactModule("RNDocumentPicker")]
internal sealed class RCTDocumentPickerModule
{
private static readonly string OPTION_TYPE = "type";
private static readonly string CACHE_TYPE = "cache";
private static readonly string OPTION_MULTIPLE = "allowMultiSelection";
private static readonly string OPTION_READ_CONTENT = "readContent";
private static readonly string FIELD_URI = "uri";
private static readonly string FIELD_FILE_COPY_URI = "fileCopyUri";
private static readonly string FIELD_NAME = "name";
private static readonly string FIELD_TYPE = "type";
private static readonly string FIELD_SIZE = "size";
private static readonly string FIELD_CONTENT = "content";
[ReactMethod("pick")]
public async Task<List<JSValueObject>> Pick(JSValue options)
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
// Get file type array options
var fileTypes = options.AsObject()[OPTION_TYPE].AsArray();
//var fileTypeArray = options.AsObject()[OPTION_TYPE][0].AsString();
bool cache = false;
if (options.AsObject().ContainsKey(CACHE_TYPE))
{
cache = options.AsObject()[CACHE_TYPE][0].AsBoolean();
}
var isMultiple = options.AsObject()[OPTION_MULTIPLE].AsBoolean();
bool readContent = false;
if (options.AsObject().ContainsKey(OPTION_READ_CONTENT))
{
readContent = options.AsObject()[OPTION_READ_CONTENT].AsBoolean();
}
//if pick called to launch folder picker.
bool isFolderPicker = false;
// Init file type filter
if (fileTypes != null)
{
if (fileTypes.Contains("folder"))
{
isFolderPicker = true;
}
foreach (var type in fileTypes)
{
var item = type.AsString();
var list = item.Split(" ");
foreach (var extension in list)
{
if (Regex.Match(extension, "(^[.]+[A-Za-z0-9]*$)|(^[*]$)").Success)
{
openPicker.FileTypeFilter.Add(extension);
}
}
}
}
else
{
openPicker.FileTypeFilter.Add("*");
}
List<JSValueObject> result;
if (isFolderPicker)
{
var openFolderPicker = new FolderPicker();
openFolderPicker.ViewMode = PickerViewMode.List;
openFolderPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
openFolderPicker.FileTypeFilter.Add("*");
result = await PickFolderAsync(openFolderPicker, cache, readContent);
}
else
{
if (isMultiple)
{
result = await PickMultipleFileAsync(openPicker, cache, readContent);
}
else
{
result = await PickSingleFileAsync(openPicker, cache, readContent);
}
}
return result;
}
[ReactMethod("pickDirectory")]
public async Task<JSValueObject> PickDirectory()
{
TaskCompletionSource<JSValueObject> tcs = new TaskCompletionSource<JSValueObject>();
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var openFolderPicker = new FolderPicker();
openFolderPicker.ViewMode = PickerViewMode.List;
openFolderPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
openFolderPicker.FileTypeFilter.Add("*");
var folder = await openFolderPicker.PickSingleFolderAsync();
if (folder != null)
{
JSValueObject obj = new JSValueObject
{
{ "uri", folder.Path }
};
tcs.SetResult(obj);
// TODO: Replace with a more principled solution
Windows.Storage.AccessCache.StorageApplicationPermissions.
FutureAccessList.AddOrReplace("pickedFolderToken", folder);
}
else
{
tcs.SetResult(new JSValueObject());
}
});
var result = await tcs.Task;
return result;
}
private async Task<JSValueObject> PrepareFile(StorageFile file, bool cache, bool readContent)
{
string base64Content = null;
if (readContent)
{
var fileStream = await file.OpenReadAsync();
using (StreamReader reader = new StreamReader(fileStream.AsStream()))
{
using (var memstream = new MemoryStream())
{
await reader.BaseStream.CopyToAsync(memstream);
var bytes = memstream.ToArray();
base64Content = Convert.ToBase64String(bytes);
}
}
}
if (cache == true)
{
var fileInCache = await file.CopyAsync(ApplicationData.Current.TemporaryFolder, file.Name.ToString(), NameCollisionOption.ReplaceExisting);
var basicProperties = await fileInCache.GetBasicPropertiesAsync();
JSValueObject result = new JSValueObject
{
{ FIELD_URI, file.Path },
{ FIELD_FILE_COPY_URI, file.Path },
{ FIELD_TYPE, file.ContentType },
{ FIELD_NAME, file.Name },
{ FIELD_SIZE, basicProperties.Size},
{ FIELD_CONTENT, base64Content }
};
return result;
}
else
{
var basicProperties = await file.GetBasicPropertiesAsync();
JSValueObject result = new JSValueObject
{
{ FIELD_URI, file.Path },
{ FIELD_FILE_COPY_URI, file.Path },
{ FIELD_TYPE, file.ContentType },
{ FIELD_NAME, file.Name },
{ FIELD_SIZE, basicProperties.Size},
{ FIELD_CONTENT, base64Content }
};
return result;
}
}
private async Task<List<JSValueObject>> PickMultipleFileAsync(FileOpenPicker picker, bool cache, bool readContent)
{
TaskCompletionSource<List<JSValueObject>> tcs = new TaskCompletionSource<List<JSValueObject>>();
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
IReadOnlyList<StorageFile> files = await picker.PickMultipleFilesAsync();
if (files.Count > 0)
{
List<JSValueObject> jarrayObj = new List<JSValueObject>();
foreach (var file in files)
{
var processedFile = await PrepareFile(file, cache, readContent);
jarrayObj.Add(processedFile);
}
tcs.SetResult(jarrayObj);
}
else
{
tcs.SetResult(new List<JSValueObject>());
}
});
var result = await tcs.Task;
return result;
}
private async Task<List<JSValueObject>> PickSingleFileAsync(FileOpenPicker picker, bool cache, bool readContent)
{
TaskCompletionSource<JSValueObject> tcs = new TaskCompletionSource<JSValueObject>();
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var file = await picker.PickSingleFileAsync();
if (file != null)
{
var processedFile = await PrepareFile(file, cache, readContent);
tcs.SetResult(processedFile);
}
else
{
tcs.SetResult(new JSValueObject());
}
});
var result = await tcs.Task;
List<JSValueObject> list = new List<JSValueObject>() { result };
return list;
}
private async Task<List<JSValueObject>> PickFolderAsync(FolderPicker picker, bool cache, bool readContent)
{
TaskCompletionSource<List<JSValueObject>> tcs = new TaskCompletionSource<List<JSValueObject>>();
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var folder = await picker.PickSingleFolderAsync();
if (folder != null)
{
List<JSValueObject> jarrayObj = new List<JSValueObject>();
var files = await folder.GetFilesAsync();
foreach (var file in files)
{
var preparedFile = await PrepareFile(file, cache, readContent);
jarrayObj.Add(preparedFile);
}
tcs.SetResult(jarrayObj);
}
});
var result = await tcs.Task;
return result;
}
}
}