Xamarin file picker file types for IOS - xamarin.essentials

I have an xamarin app and I am using Essential File Picker for selecting files from library. I am trying to find a way to define doc and docx files for IOS which I am not getting it right.
for Android I got it going.
Below is the code I have used.
`
private List<string> androidAcceptableList = new List<string> { "application/pdf", "image/*" }; //TODO:Read from configuration
private List<string> iOsAcceptableList = new List<string> { "application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"image/*"}; //TODO:Read from configuration
var customFileTypes = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>> {
{ DevicePlatform.iOS,iOsAcceptableList },
{ DevicePlatform.Android, androidAcceptableList}
});
var resp = FilePicker.PickAsync(new PickOptions { FileTypes = FileTypesList() });
`

How to open the Document files e.g(.pdf,.doc,.docx) in ios mobile when a button action using swift3.0?
"com.microsoft.word.doc","org.openxmlformats.wordprocessingml.document" for Doc and Docx respectively,

Related

How do I create a CSharpCompilation using Roslyn in Blazor WebAssembly?

I am trying to write a Blazor WebAssembly (WASM) app that accepts some code (from some text input field) and compiles the code using Roslyn.
I'm using Roslyn's CSharpCompilation class to create the compilation. Its Create method takes four parameters, one of which is a list of MetadataReferences (aka assembly references). In other (non-blazor) type applications, like a C# console app, you could get these MetadataReferences based on Asssembly Location, like this:
var locatedAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => !string.IsNullOrEmpty(a.Location)).ToArray();
foreach (var assembly in locatedAssemblies)
{
MetadataReference reference = MetadataReference.CreateFromFile(assembly.Location);
}
This unfortunately no longer works in Blazor WASM, because the Locations of the assemblies are empty.
I had tried getting assemblies in different ways, like AppDomain.CurrentDomain.GetAssemblies() and Assembly.GetEntryAssembly().GetReferencedAssemblies(), but all had empty Locations. I also tried calling Assembly.Load(), but to no avail.
Does anyone know how to get MetadataReferences in Blazor WASM, or how I would otherwise create a compilation in Blazor WASM?
(I'm also aware of MetadataReference.CreateFromStream() that I'll probably need to use, but it still requires the assembly location).
Thanks in advance.
I also wanted to compile C# inside a Blazor WASM app and found your question without an answer. After some digging I was able to create a working demo (repo link below.) Basically get the bytes for each assembly with HttpClient and use MetadataReference.CreateFromImage(bytes).
Full basic example repo I created: https://github.com/LostBeard/BlazorWASMScriptLoader
ScriptLoaderService.cs source:
using Microsoft.AspNetCore.Components;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Reflection;
namespace BlazorWASMScriptLoader
{
// requires "Microsoft.CodeAnalysis.CSharp"
// can be added via nuget
public class ScriptLoaderService
{
HttpClient _httpClient = new HttpClient();
public ScriptLoaderService(NavigationManager navigationManager)
{
_httpClient.BaseAddress = new Uri(navigationManager.BaseUri);
}
async Task<MetadataReference?> GetAssemblyMetadataReference(Assembly assembly)
{
MetadataReference? ret = null;
var assmeblyName = assembly.GetName().Name;
var assemblyUrl = $"./_framework/{assmeblyName}.dll";
try
{
var tmp = await _httpClient.GetAsync(assemblyUrl);
if (tmp.IsSuccessStatusCode)
{
var bytes = await tmp.Content.ReadAsByteArrayAsync();
ret = MetadataReference.CreateFromImage(bytes);
}
}
catch { }
return ret;
}
public async Task<Assembly?> CompileToDLLAssembly(string sourceCode, string assemblyName = "")
{
if (string.IsNullOrEmpty(assemblyName)) assemblyName = Path.GetRandomFileName();
var codeString = SourceText.From(sourceCode);
var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp11);
var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(codeString, options);
var appAssemblies = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().Select(o => Assembly.Load(o)).ToList();
appAssemblies.Add(typeof(object).Assembly);
var references = new List<MetadataReference>();
foreach (var assembly in appAssemblies)
{
var metadataReference = await GetAssemblyMetadataReference(assembly);
if (metadataReference == null)
{
// assembly may be located elsewhere ... handle if needed
continue;
}
var metadataReferene = metadataReference;
references.Add(metadataReferene);
}
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { parsedSyntaxTree },
references: references,
options: new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
concurrentBuild: false,
optimizationLevel: OptimizationLevel.Debug
)
);
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
return null;
}
else
{
ms.Seek(0, SeekOrigin.Begin);
var assembly = Assembly.Load(ms.ToArray());
return assembly;
}
}
}
}
}

Local Image not displayed in Skia.WPF Uno Platform project

I save images relative to the workingdirectory and then want to display them in a uno Skia.WPF app.
However they never appear.
This is how I create the ImageSource:
public static async Task<ImageSource> GenerateSource()
{
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.FileTypeFilter.Add(".png");
var pickerResult = await picker.PickSingleFileAsync("tileset");
if (pickerResult is null)
return null;
using var stream = await pickerResult.OpenReadAsync();
string imagePath = Path.GetFullPath(Path.Combine("cache", "image.png"));
Directory.CreateDirectory(Path.GetDirectoryName(imagePath));
using (var bitmapImageStream = File.Open(imagePath,
FileMode.Create,
FileAccess.Write,
FileShare.None))
{
await stream.AsStreamForRead().CopyToAsync(bitmapImageStream);
bitmapImageStream.Flush(true);
}
var imgSrc = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
imgSrc.UriSource = new Uri($"file://{imagePath}");
var width = imgSrc.PixelHeight;
return imgSrc;
}
But when I use the path directly in the Xaml it also not working.
<Image Source="file://cache/image.png" Width="32" Height="32" />
Using an image from the Internet using an http url works.
Sample Repo
file: URIs are currently not supported in Uno, however, you can still show local images by copying to the appropriate folder using ms-appdata scheme. If you copy the file into ApplicationData.Current.TemporaryFolder, you will the be able to reference that path by ms-appdata:///temp/{imageName} URI.

Download multiple files (50mb) blazor server-side

i can't really find a way to download a 100mb zip file from the server to the client and also show the progress while downloading. So how will this look for a normal api controller i can add to my server-side project? if lets say i have 3 files i want to download at 50mb each.
i have tried using JSInterop like this, but this is not showing the progress of the file download, and how will i do if i want to download 3 seperate files at the same time?
try
{
//converting file into bytes array
var dataBytes = System.IO.File.ReadAllBytes(file);
await JSRuntime.InvokeVoidAsync(
"downloadFromByteArray",
new
{
ByteArray = dataBytes,
FileName = "download.zip",
ContentType = "application/force-download"
});
}
catch (Exception)
{
//throw;
}
JS:
function downloadFromByteArray(options: {
byteArray: string,
fileName: string,
contentType: string
}): void {
// Convert base64 string to numbers array.
const numArray = atob(options.byteArray).split('').map(c => c.charCodeAt(0));
// Convert numbers array to Uint8Array object.
const uint8Array = new Uint8Array(numArray);
// Wrap it by Blob object.
const blob = new Blob([uint8Array], { type: options.contentType });
// Create "object URL" that is linked to the Blob object.
const url = URL.createObjectURL(blob);
// Invoke download helper function that implemented in
// the earlier section of this article.
downloadFromUrl({ url: url, fileName: options.fileName });
// At last, release unused resources.
URL.revokeObjectURL(url);
}
UPDATE:
if im using this code, it will show me the progress of the file. But how can i trigger it from my code? This way does not do it. But typing the url does.
await Http.GetAsync($"Download/Model/{JobId}");
Controller
[HttpGet("download/model/{JobId}")]
public IActionResult DownloadFile([FromRoute] string JobId)
{
if (JobId == null)
{
return BadRequest();
}
var FolderPath = $"xxxx";
var FileName = $"Model_{JobId}.zip";
var filePath = Path.Combine(environment.WebRootPath, FolderPath, FileName);
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/force-download", FileName);
}
UPDATE 2!
i have got it download with progress and click with using JSInterop.
public async void DownloadFiles()
{
//download all selectedFiles
foreach (var file in selectedFiles)
{
//download these files
await JSRuntime.InvokeAsync<object>("open", $"Download/Model/{JobId}/{file.Name}", "_blank");
}
}
Now the only problem left is.. it only downloads the first file out of 3.

xamarin.forms Sharing Image AND text (body, not title)

I am using this sharing function:
public static async void ShareImageAndText(string text, string image)
{
var fn = "pic.png";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllBytes(file, Convert.FromBase64String(image));
await Share.RequestAsync(new ShareFileRequest()
{
Title = text,
File = new ShareFile(file)
});
}
This shares an image to whereever I please, but the text "title" only appears if I share to email. If I share to whatsapp for instance, it will only give the image. But since I also want to share a text with an uri in it, this option doesnt work.
Who knows how to share a file AND a text in the same request?
Thanks
Having the same problem, I was unable of resolving it using the Xamaring.Essentials.Share. So, I created in my Xamarin Forms App a Page with the Image and Text that I need to send, and take a screenshot of it using Screenshot https://learn.microsoft.com/en-us/xamarin/essentials/screenshot and saving it to File. Then just send it.
//Take a screenshot from this page to a file
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var File_Path = System.IO.Path.Combine(path, "Screenshot.png");
var screenshot = await Screenshot.CaptureAsync();
var stream = await screenshot.OpenReadAsync(ScreenshotFormat.Png);
using (var fileStream = System.IO.File.Create(File_Path))
{
stream.Seek(0, System.IO.SeekOrigin.Begin);
stream.CopyTo(fileStream);
}
await Share.RequestAsync(new ShareFileRequest
{
Title = "Some Title",
File = new ShareFile(File_Path)
});

"Save Photos in Photo albums of iPhone or iPad using Xamarin Forms" However PCL is Deprecated

I am trying do to the thing that is the question in this Stack Overflow Post "https://stackoverflow.com/questions/49291495/save-photos-in-photo-albums-of-iphone-or-ipad-using-xamarin-forms". However in the answer for the post PCL is deprecated. What is a more updated answer? Thank you.
However in the answer for the post PCL is deprecated.
Actually , you just need to do the same thing in Share Projects . DependencyService is available in Xamarin.Forms , which you can refer https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction .
in Forms
public interface ISavePhotosToAlbum
{
void SavePhotosWithStream(string name, Stream data);
}
in iOS
[assembly: Dependency(typeof(SaveToAlbum))]
namespace xxx.iOS
{
public class SaveToAlbum : ISavePhotosToAlbum
{
public void SavePhotosWithStream(string name,Stream stream)
{
var imageData = NSData.FromStream(stream);
var image = UIImage.LoadFromData(imageData);
image.SaveToPhotosAlbum((img, error) =>
{
});
}
}
}
And add the following code in info.plist
<key>NSCameraUsageDescription</key>
<string>App need to access your camera</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>App need to access your albums</string> // new in iOS 11 and later
<key>NSPhotoLibraryUsageDescription</key>
<string>App need to access your albums</string>
In addition , if you want to implement it in Android
in Android
[assembly: Dependency(typeof(SaveToAlbum))]
namespace xxx.Droid
{
public class SaveToAlbum : ISavePhotosToAlbum
{
public void SavePhotosWithStream(string name,Stream stream)
{
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
documentsPath = Path.Combine(documentsPath, "Orders", temp);
Directory.CreateDirectory(documentsPath);
string filePath = Path.Combine(documentsPath, name);
byte[] bArray = new byte[data.Length];
using (FileStream fs = new FileStream(filePath , FileMode.OpenOrCreate))
{
using (data)
{
data.Read(bArray, 0, (int)data.Length);
}
int length = bArray.Length;
fs.Write(bArray, 0, length);
}
}
}
}

Resources