MyNihongo / MudBlazor.Markdown

Markdown component based on the MudBlazor environment
https://mudblazor.com/
MIT License
132 stars 13 forks source link

Code block copy to clipboard breaks on Android #205

Closed Jeffcole1 closed 10 months ago

Jeffcole1 commented 1 year ago

I am using Mudblazor.Markdown in a .NET MAUI application intended to be used on Android, among other platforms. When running the app in an Android emulator (Pixel 5 - API 28), clicking the Copy button on a Markdown fenced code block generates the following error message in the console:

null
   at Microsoft.JSInterop.JSRuntime.<InvokeAsync>d__16`1[[Microsoft.JSInterop.Infrastructure.IJSVoidResult, Microsoft.JSInterop, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext()
   at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args)
   at MudBlazor.MudCodeHighlight.CopyTextToClipboardAsync(MouseEventArgs args)
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at MudBlazor.MudBaseButton.OnClickHandler(MouseEventArgs ev)
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

From what I can tell, it appears the issue lies with the invocation of 'navigator.clipboard.writeText'. I attempted to invoke this function directly in my own code, and the same error occurred. When I run the app on Windows, everything works fine.

MihailsKuzmins commented 1 year ago

It might be related to permissions as it is specified here: Interact with the clipboard. Could you try to run navigator.permissions.query({ name: "clipboard-write" }) directly and see what happens?

Alternatively, it might be a problem with the browser you used on mobile as it is stated here: Copy to clipboard is worked fine on PC but not works on Android device

and the same error occurred

By the way, what was the same error? Was null just printed in the browser console after you had executed the clipboard command directly?

Jeffcole1 commented 1 year ago

I'm not using an actual browser. This is a .NET MAUI Blazor app written in Visual Studio and deployed to an Android emulator for testing. I used chrome://inspect#devices to open a dev tools page on the running app in the emulator.

When I click the copy button on the code block, this message appears: blazorErrorMessage

Running the query command gave me a TypeError; polling the navigator.permissions property returned undefined, and polling navigator by itself returned this: appClipboardWrite

For comparison, here is the message I got when I opened Chrome on the emulator and ran the same command: chromeClipboardWrite

MihailsKuzmins commented 1 year ago

I see, so probably more work will be needed - like trying to create a workaround for this issue in the JS section of the code. Something like

const element = document.createElement("textarea");
element.value = clipboardData;
document.body.appendChild(element)
element.select();
document.execCommand("copy");
document.body.removeChild(element);

But could you provide a sample solution where the error can be reproduced easily. I have neither MAUI nor android emulators installed on my PC, so it will take me some time to analyse this issue, sorry for trouble, but if it is possible could you provide a link to a GitHub repo where this issue can be reproduced?

Maybe some instructions about "deploying it to the Android enulator" would also come in handy

Jeffcole1 commented 1 year ago

Link to sample repository: https://github.com/Jeffcole1/MudblazorMarkdownAndroidTest

Instructions to set up and run Android Emulator:

  1. In Visual Studio (I'm using Community 2022), ensure that the ".NET Multi-Platform App UI Development" workload is installed.
  2. With the solution open, select Tools -> Android -> Android Device Manager.
  3. Check that at least one virtual device is shown in the table. If there are none, click New. If there are any, skip to step 6.
  4. Give the virtual device a name and select a base device and Android API to use (I used Pixel 5 with Android 9.0 - API 28).
  5. Click Create to create the virtual device.
  6. The virtual device should appear in the table. Click the Start button to start the virtual device and ensure it runs properly.
  7. In Visual Studio, select the virtual device in the device list (next to the Configuration dropdowns), then click the Start button to start debugging. If you did it properly, the app should begin running in the virtual device. It may take a couple of minutes for the app to build and deploy to the virtual device.
MihailsKuzmins commented 1 year ago

Thanks, I will try to take a look as soon as I can. It will take some time so please understand it 🙇

amtdev commented 1 year ago

Thanks, I will try to take a look as soon as I can. It will take some time so please understand it 🙇

Any update on this? I am having the same issue.

MihailsKuzmins commented 1 year ago

@amtdev Sorry, not so much time I can devote to this project lately :( Maybe this weekend I will have time...

MihailsKuzmins commented 10 months ago

@Jeffcole1 cc @amtdev

I've been working on this issue today and copying to clibboard in maui does not work as expected (well, it does not work even with document.execCommand('copy') which works in a browser, e.g. Chrome). I have come across this issue - https://github.com/dotnet/maui/issues/6846. Does it make sense to you?

I have only found out that it is possible to use the following in MainPage.cs, but I have no idea how to grant copy permissions in this callback. MAUI documentation (or the afore cited issue) does not provide any details how to do it. In any case I can try to open the same issue and hopefully someone will give an example how to do it.

blazorWebView.BlazorWebViewInitialized += BlazorWebView_BlazorWebViewInitialized;
MihailsKuzmins commented 10 months ago

@Jeffcole1 cc @amtdev

Well I have a solution for this case. You will need to provide a custom clipboard service when adding services in MauiProgram.cs as it is shown down below:

builder.Services.AddMudMarkdownClipboardService<ClipboardService>();

// Implementation
public class ClipboardService : IMudMarkdownClipboardService
{
    public async ValueTask CopyToClipboardAsync(string text)
    {
        await Clipboard.Default.SetTextAsync(text)
            .ConfigureAwait(false);
    }
}

I will finalise the MR and make a new NuGet version a bit later today.