From c68b53f38ff4e9eb2ff6d80d933e47127172b0c8 Mon Sep 17 00:00:00 2001 From: Omid Mafakher Date: Thu, 6 Jul 2023 22:17:57 +0200 Subject: [PATCH] #6110 Implementation of storage provider for tizen --- .../ControlCatalog.Tizen/tizen-manifest.xml | 8 + .../Avalonia.Tizen/TizenStorageProvider.cs | 184 ++++++++++++++++++ src/Tizen/Avalonia.Tizen/TopLevelImpl.cs | 12 +- 3 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 src/Tizen/Avalonia.Tizen/TizenStorageProvider.cs diff --git a/samples/ControlCatalog.Tizen/tizen-manifest.xml b/samples/ControlCatalog.Tizen/tizen-manifest.xml index c0044d07c95..a1429449906 100644 --- a/samples/ControlCatalog.Tizen/tizen-manifest.xml +++ b/samples/ControlCatalog.Tizen/tizen-manifest.xml @@ -13,4 +13,12 @@ ControlCatalog.Avalonia.png + + http://tizen.org/privilege/appdir.shareddata + http://tizen.org/privilege/appmanager.launch + http://tizen.org/privilege/externalstorage + http://tizen.org/privilege/externalstorage.appdata + http://tizen.org/privilege/internet + http://tizen.org/privilege/network.get + diff --git a/src/Tizen/Avalonia.Tizen/TizenStorageProvider.cs b/src/Tizen/Avalonia.Tizen/TizenStorageProvider.cs new file mode 100644 index 00000000000..293fa628cca --- /dev/null +++ b/src/Tizen/Avalonia.Tizen/TizenStorageProvider.cs @@ -0,0 +1,184 @@ +using System.Security; +using Avalonia.Platform.Storage; +using Avalonia.Platform.Storage.FileIO; +using Avalonia.Tizen.Platform; +using Tizen.Applications; + +namespace Avalonia.Tizen; +internal class TizenStorageProvider : IStorageProvider +{ + public bool CanOpen => true; + + public bool CanSave => false; + + public bool CanPickFolder => true; + + public Task OpenFileBookmarkAsync(string bookmark) + { + throw new NotImplementedException(); + } + + private static async Task CheckPermission() + { + Permissions.EnsureDeclared(Permissions.AppManagerLaunchPrivilege); + if (await Permissions.RequestPrivilegeAsync(Permissions.MediaStoragePrivilege) == false) + { + throw new SecurityException("Application doesn't have storage permission."); + } + } + + public async Task> OpenFilePickerAsync(FilePickerOpenOptions options) + { + await CheckPermission(); + + var tcs = new TaskCompletionSource>(); + +#pragma warning disable CS8603 // Possible null reference return. + var fileType = options.FileTypeFilter? + .Where(w => w.MimeTypes != null) + .SelectMany(s => s.MimeTypes); +#pragma warning restore CS8603 // Possible null reference return. + + var appControl = new AppControl + { + Operation = AppControlOperations.Pick, + Mime = fileType?.Any() == true + ? fileType.Aggregate((o, n) => o + ";" + n) + : "*/*" + }; + appControl.ExtraData.Add(AppControlData.SectionMode, options.AllowMultiple ? "multiple" : "single"); + if (options.SuggestedStartLocation?.Path is { } startupPath) + appControl.ExtraData.Add(AppControlData.Path, startupPath.ToString()); + appControl.LaunchMode = AppControlLaunchMode.Single; + + var fileResults = new List(); + + AppControl.SendLaunchRequest(appControl, (request, reply, result) => + { + if (result == AppControlReplyResult.Succeeded) + { + if (reply.ExtraData.Count() > 0) + { + var selectedFiles = reply.ExtraData.Get>(AppControlData.Selected).ToList(); + fileResults.AddRange(selectedFiles.Select(f => new BclStorageFile(new(f)))); + } + } + + tcs.TrySetResult(fileResults); + }); + + return await tcs.Task; + } + + public async Task> OpenFolderPickerAsync(FolderPickerOpenOptions options) + { + Permissions.EnsureDeclared(Permissions.AppManagerLaunchPrivilege); + if (await Permissions.RequestPrivilegeAsync(Permissions.MediaStoragePrivilege) == false) + { + throw new SecurityException("Application doesn't have storage permission."); + } + + var tcs = new TaskCompletionSource>(); + + var appControl = new AppControl + { + Operation = AppControlOperations.Pick, + Mime = "inode/directory" + }; + appControl.ExtraData.Add(AppControlData.SectionMode, options.AllowMultiple ? "multiple" : "single"); + if (options.SuggestedStartLocation?.Path is { } startupPath) + appControl.ExtraData.Add(AppControlData.Path, startupPath.ToString()); + appControl.LaunchMode = AppControlLaunchMode.Single; + + var fileResults = new List(); + + AppControl.SendLaunchRequest(appControl, (request, reply, result) => + { + if (result == AppControlReplyResult.Succeeded) + { + if (reply.ExtraData.Count() > 0) + { + var selectedFiles = reply.ExtraData.Get>(AppControlData.Selected).ToList(); + fileResults.AddRange(selectedFiles.Select(f => new BclStorageFolder(new System.IO.DirectoryInfo(f)))); + } + } + + tcs.TrySetResult(fileResults); + }); + + return await tcs.Task; + } + + public Task OpenFolderBookmarkAsync(string bookmark) + { + throw new NotImplementedException(); + } + + public Task SaveFilePickerAsync(FilePickerSaveOptions options) + { + throw new NotImplementedException(); + } + + public async Task TryGetFileFromPathAsync(Uri filePath) + { + await CheckPermission(); + + if (filePath is not { IsAbsoluteUri: true, Scheme: "file" }) + { + throw new ArgumentException("File path is expected to be an absolute link with \"file\" scheme."); + } + + var path = Path.Combine(global::Tizen.Applications.Application.Current.DirectoryInfo.Resource, filePath.AbsolutePath); + var file = new FileInfo(path); + if (!file.Exists) + { + return null; + } + + return new BclStorageFile(file); + } + + public async Task TryGetFolderFromPathAsync(Uri folderPath) + { + if (folderPath is null) + { + throw new ArgumentNullException(nameof(folderPath)); + } + + await CheckPermission(); + + if (folderPath is not { IsAbsoluteUri: true, Scheme: "file" }) + { + throw new ArgumentException("File path is expected to be an absolute link with \"file\" scheme."); + } + + var path = Path.Combine(global::Tizen.Applications.Application.Current.DirectoryInfo.Resource, folderPath.AbsolutePath); + var directory = new System.IO.DirectoryInfo(path); + if (!directory.Exists) + return null; + + return new BclStorageFolder(directory); + } + + public Task TryGetWellKnownFolderAsync(WellKnownFolder wellKnownFolder) + { + var folder = wellKnownFolder switch + { + WellKnownFolder.Desktop => null, + WellKnownFolder.Documents => global::Tizen.Applications.Application.Current.DirectoryInfo.Data, + WellKnownFolder.Downloads => global::Tizen.Applications.Application.Current.DirectoryInfo.SharedData, + WellKnownFolder.Music => null, + WellKnownFolder.Pictures => null, + WellKnownFolder.Videos => null, + _ => throw new ArgumentOutOfRangeException(nameof(wellKnownFolder), wellKnownFolder, null), + }; + + if (folder == null) + return Task.FromResult(null); + + var storageFolder = new BclStorageFolder(new System.IO.DirectoryInfo(folder)); + return Task.FromResult(storageFolder); + } + + +} diff --git a/src/Tizen/Avalonia.Tizen/TopLevelImpl.cs b/src/Tizen/Avalonia.Tizen/TopLevelImpl.cs index 77c2cd19825..49c1ebf4ec1 100644 --- a/src/Tizen/Avalonia.Tizen/TopLevelImpl.cs +++ b/src/Tizen/Avalonia.Tizen/TopLevelImpl.cs @@ -14,14 +14,14 @@ public class TopLevelImpl : ITopLevelImpl { private readonly ITizenView _view; private readonly NuiClipboardImpl _clipboard; - //private IStorageProvider _storageProvider; + private IStorageProvider _storageProvider; public TopLevelImpl(ITizenView view) { _view = view; //_nativeControlHost = new NativeControlHostImpl(view); - //_storageProvider = new TizenStorageProvider(); + _storageProvider = new TizenStorageProvider(); //_insetsManager = new InsetsManager(view); //_insetsManager.DisplayEdgeToEdgeChanged += (sender, b) => //{ @@ -88,10 +88,10 @@ public void SetTransparencyLevelHint(IReadOnlyList tran public object? TryGetFeature(Type featureType) { - //if (featureType == typeof(IStorageProvider)) - //{ - // return _storageProvider; - //} + if (featureType == typeof(IStorageProvider)) + { + return _storageProvider; + } if (featureType == typeof(ITextInputMethodImpl)) {