Skip to content

Commit

Permalink
feat: Initial implementation of FileOpenPicker for Skia.Gtk
Browse files Browse the repository at this point in the history
Add PickerHelpers to Skia.Gtk

Update docs for pickers

Use strongly typed extension registration

Change test description to include Gtk
  • Loading branch information
lukeblevins committed Jun 12, 2021
1 parent f838557 commit 4cd398a
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 2 deletions.
2 changes: 1 addition & 1 deletion doc/articles/features/windows-storage-pickers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Legend

| Picker | UWP | WebAssembly | Android | iOS | macOS | WPF | GTK |
|----------------|-----|-------------|---------|-----|-------|-----|-----|
| FileOpenPicker || ✅ (1) ||||| 🚫 |
| FileOpenPicker || ✅ (1) ||||| |
| FileSavePicker || ✅ (1) ||||| 🚫 |
| FolderPicker |||| ⏸️ (2)|| 🚫 | 🚫 |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace UITests.Shared.Windows_Storage.Pickers
{
[Sample("Windows.Storage", ViewModelType = typeof(FileOpenPickerTestsViewModel), IsManualTest = true,
Description = "Allows testing all features of FileOpenPicker. Currently not supported on Android, iOS, macOS and GTK. Not selecting a file should not cause an exception")]
Description = "Allows testing all features of FileOpenPicker. Currently not supported on Android, iOS, and macOS. Not selecting a file should not cause an exception")]
public sealed partial class FileOpenPickerTests : Page
{
public FileOpenPickerTests()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#nullable enable

using Gtk;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Uno.UI.Runtime.Skia;
using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.Storage.Pickers;

namespace Uno.Extensions.Storage.Pickers
{
internal class FileOpenPickerExtension : IFileOpenPickerExtension
{
private readonly FileOpenPicker _picker;

public FileOpenPickerExtension(FileOpenPicker owner)
{
_picker = owner ?? throw new ArgumentNullException(nameof(owner));
}

public async Task<StorageFile?> PickSingleFileAsync(CancellationToken token)
{
var files = await OpenPickerAsync(false);
return files.FirstOrDefault();
}

public async Task<IReadOnlyList<StorageFile>> PickMultipleFilesAsync(CancellationToken token)
{
var files = await OpenPickerAsync(true);
return new FilePickerSelectedFilesArray(files);
}

private async Task<StorageFile[]> OpenPickerAsync(bool multiple)
{
string commitText = "Open";
if (!string.IsNullOrWhiteSpace(_picker.CommitButtonText))
{
commitText = _picker.CommitButtonText;
}

FileChooserDialog dialog = new FileChooserDialog(
"Open",
GtkHost.Window,
FileChooserAction.Open,
"Cancel", ResponseType.Cancel,
commitText, ResponseType.Accept);

dialog.SelectMultiple = multiple;

if (!_picker.FileTypeFilter.Contains("*"))
{
FileFilter filter = new FileFilter();

foreach (string pattern in _picker.FileTypeFilter)
{
// Pattern is already validated to start with a period, so prepend star
filter.AddPattern("*" + pattern);
}

if (_picker.FileTypeFilter.Count > 0)
{
dialog.AddFilter(filter);
}
}

dialog.SetCurrentFolder(PickerHelpers.GetInitialDirectory(_picker.SuggestedStartLocation));

var files = new List<StorageFile>();
if (dialog.Run() == (int)ResponseType.Accept)
{
foreach (var fileName in dialog.Filenames)
{
files.Add(await StorageFile.GetFileFromPathAsync(fileName));
}
}

dialog.Destroy();
return files.ToArray();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#nullable enable

using Windows.Storage.Pickers;
using static System.Environment;

namespace Uno.Extensions.Storage.Pickers
{
internal static class PickerHelpers
{
public static string GetInitialDirectory(PickerLocationId location)
{
switch (location)
{
case PickerLocationId.DocumentsLibrary:
return GetFolderPath(SpecialFolder.MyDocuments);
case PickerLocationId.ComputerFolder:
return @"/";
case PickerLocationId.Desktop:
return GetFolderPath(SpecialFolder.Desktop);
case PickerLocationId.MusicLibrary:
return GetFolderPath(SpecialFolder.MyMusic);
case PickerLocationId.PicturesLibrary:
return GetFolderPath(SpecialFolder.MyPictures);
case PickerLocationId.VideosLibrary:
return GetFolderPath(SpecialFolder.MyVideos);
default:
return string.Empty;
}
}
}
}
3 changes: 3 additions & 0 deletions src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
using Uno.Extensions.System;
using Uno.UI.Runtime.Skia.GTK.Extensions.System;
using Uno.UI.Runtime.Skia.GTK.UI.Core;
using Uno.Extensions.Storage.Pickers;
using Windows.Storage.Pickers;

namespace Uno.UI.Runtime.Skia
{
Expand Down Expand Up @@ -55,6 +57,7 @@ public void Run()
ApiExtensibility.Register(typeof(Windows.Graphics.Display.IDisplayInformationExtension), o => _displayInformationExtension ??= new GtkDisplayInformationExtension(o, _window));
ApiExtensibility.Register<TextBoxView>(typeof(ITextBoxViewExtension), o => new TextBoxViewExtension(o, _window));
ApiExtensibility.Register(typeof(ILauncherExtension), o => new LauncherExtension(o));
ApiExtensibility.Register<FileOpenPicker>(typeof(IFileOpenPickerExtension), o => new FileOpenPickerExtension(o));

_isDispatcherThread = true;
_window = new Gtk.Window("Uno Host");
Expand Down

0 comments on commit 4cd398a

Please sign in to comment.