maui icon indicating copy to clipboard operation
maui copied to clipboard

[regression/8.0.3] Disabling RefreshView disables the keyboard

Open kanadaj opened this issue 1 year ago • 11 comments

Description

This might be related to a change in the Android SDK or maybe in the MAUI keyboard/View implementation, but disabling a RefreshView with refreshView.IsEnabled = false disables keyboard entry into textareas (and probably inputs too) in MAUI Blazor. Haven't had the chance to try if native inputs were affected yet.

Steps to Reproduce

  1. Create a new MAUI Blazor Hybrid project
  2. Wrap the BlazorWebView in a RefreshView
  3. Set IsEnabled on the RefreshView to false
  4. Add a textarea to the Razor view
  5. Run the application, tap into the textarea and start typing
  6. Caret doesn't appear, input is ignored

Link to public reproduction project repository

No response

Version with bug

8.0.3

Is this a regression from previous behavior?

Yes, this used to work in .NET MAUI

Last version that worked well

7.0.101

Affected platforms

Android

Affected platform versions

Android 11 and Android 14 confirmed

Did you find any workaround?

Yes, we're currently using the following workaround:

// Platforms/Android/CustomDisableSwipeRefreshLayout.cs
public class CustomDisableSwipeRefreshLayout : MauiSwipeRefreshLayout
{
    public bool DisableRefresh { get; set; }

    public CustomDisableSwipeRefreshLayout(Context context) : base(context)
    {
    }

    public override bool CanChildScrollUp()
    {
        if (DisableRefresh)
            return true;

        return base.CanChildScrollUp();
    }
}

with a custom ViewHandler, we are abusing CanChildScrollUp to disable refresh without disabling the Control itself, and then setting it directly:

// Platforms/Android/ViewHandlers/RefreshViewHandler.cs
public class RefreshViewHandler : Microsoft.Maui.Handlers.RefreshViewHandler
{
    protected override MauiSwipeRefreshLayout CreatePlatformView()
    {
        return new CustomDisableSwipeRefreshLayout(Context);
    }
}
// MauiProgram.cs
handlers.AddHandler<RefreshView, RefreshViewHandler>();
// Usage
#if ANDROID
    if (RefreshViewInstance.Handler?.PlatformView is CustomDisableSwipeRefreshLayout platformView)
    {
        platformView.DisableRefresh = !isReloadable;   
    }
    else
    {
        RefreshViewInstance.IsEnabled = isReloadable;
    }
#else
    RefreshViewInstance.IsEnabled = isReloadable;
#endif

Obviously, it would be nicer to inherit from RefreshView and fully implement this in the MAUI view itself, but this works as a quick and dirty patch.

Relevant log output

No response

kanadaj avatar Nov 28 '23 21:11 kanadaj

I think disabling a control/layout also disables all the children. So this feels expected. If it worked in net7 that sounds like a bug. @PureWeen thoughts?

Also, pull to refresh a blazor webview will refresh and reload the whole app? @Eilon ?

Maybe you are needing a refresh view in the blazor view, not wrapping it.

mattleibow avatar Nov 29 '23 12:11 mattleibow

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

ghost avatar Nov 29 '23 12:11 ghost

@mattleibow pull to refresh doesn't really work properly inside the browser to be honest. JavaScript implementations are extremely buggy. Using the RefreshView as a wrapper works much better - it doesn't reload the browser, but we have tied our own logic inside the Blazor views to the event.

Disabling the RefreshView doesn't actually disable the browser either, just text input inside it. This wasn't the case previously either, so I'm not sure what changed to cause this. Couldn't find any relevant code changes.

kanadaj avatar Nov 29 '23 13:11 kanadaj

@mattleibow indeed, I'm also surprised this ever worked. But probably not many people tried. I would normally expect that if a container is disabled, then everything inside it should all be disabled unconditionally. And if it isn't, that would be a bug.

@kanadaj indeed, I think pull-to-refresh is more of a 'web browser' thing and not a 'webview' thing, so it wouldn't work in a BlazorWebView by default (please correct me if I am wrong).

Eilon avatar Nov 29 '23 19:11 Eilon

@kanadaj indeed, I think pull-to-refresh is more of a 'web browser' thing and not a 'webview' thing, so it wouldn't work in a BlazorWebView by default (please correct me if I am wrong).

Browsers typically implement it just like we did - by wrapping a native RefreshView around the WebView. The issue is that we only need the mechanism selectively. Until now, IsEnabled has actually worked for this and there are actually a number of posts and articles online suggesting to do this to disable refresh.

See: https://stackoverflow.com/a/30328196 https://stackoverflow.com/a/34092085

And from the Android docs: https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout

To disable the gesture and progress animation, call setEnabled(false) on the view.

So I'm reasonably sure that disabling the RefreshView isn't meant to disable its children. Which would mean that the IsEnabled flag being propagated to its children is the bug here.

kanadaj avatar Nov 29 '23 19:11 kanadaj

Hmm interesting. I'm not sure if I was trying the exact same thing with the WindowsAppSDK (WinUI3) RefreshContainer (which is what .NET MAUI uses on Windows), but setting RefreshContainer.IsEnabled = false seems to disable elements currently in the refresh container, but if more items are added to the container, they don't seem to inherit being disabled.

I'm not quite sure what to make of that, but it seems already inconsistent between platforms (at least Android and Windows).

I've updated the labels on this issue to indicate it's likely a problem with the .NET MAUI RefreshView and not with the BlazorWebView. The BlazorWebView doesn't enable/disable itself or even listen to such events - it's presumably up to either the developer to set such a thing, or that it 'inherits' it from a parent container, such as a RefreshView.

Eilon avatar Dec 01 '23 23:12 Eilon

This is causing major issues for our app at the moment, it's also worth noting that it prevents SwipeViews from functioning as well as the Entries. The CollectionView functionality bugs really could do with some attention.

We're in the process of figuring out whether it's worth writing a workaround that just picks up and hides the refresh functionality, but I also feel as though this shouldn't be an issue that we have to bodge to fix.

BPriceKB avatar Jan 18 '24 14:01 BPriceKB

It also seems to have an effect on the system back button on android. We have both the problems. The one with the keyboard not working and navigationlock which no longer work on .net 8, and just closes the app. image

It does no longer react when disabling refreshview.

noahgabel avatar Feb 11 '24 13:02 noahgabel

Hello @kanadaj ,

I hope this message finds you well. I recently came across the issue you reported.

Could you possibly share more details on how you implemented this workaround? I'm particularly interested in your "Usage" example.

To manage which pages utilize the RefreshView in my application, I control it through a bound boolean, managed by the following code snippet:

public class RefreshViewState : INotifyPropertyChanged
{
    public bool IsRefreshing { get; private set; }
    public bool IsEnabled { get; private set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public void SetIsRefreshing(bool isRefreshing)
    {
        IsRefreshing = isRefreshing;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsRefreshing)));
    }

    public void SetIsEnabled(bool isEnabled)
    {
        IsEnabled = isEnabled;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEnabled)));
    }
}

This RefreshViewState class is injected as a service into my pages to dynamically control the RefreshView's state. Could you elaborate on how I might integrate your "Usage" example in your workaround please ?

Rebrandsoft avatar Feb 23 '24 04:02 Rebrandsoft

@Rebrandsoft To be honest your usage is likely better. We reference the RefreshView directly in a singleton service and set the property on it. But your method should also work and it's honestly a bit better if we're being honest. The goal is to get the variable to a custom implementation which overrides CanChildScrollUp either way.

kanadaj avatar Feb 23 '24 17:02 kanadaj

Has there been any progress on resolving this issue with the actual component. It does seem to be fundamentally broken that when you set is IsEnabled to false it disables all child components.

RickFrankel avatar May 04 '24 08:05 RickFrankel

I am working on a mobile app using Blazor Hybrid and have implemented the pull to refresh. In Android it works without any issues when I set it to "IsEnabled = false", but running as a desktop application it does not. My workaround is to set a "IsWindows" field and if it's windows don't do anything with the refresh and keep it enabled.

abivelj avatar May 16 '24 17:05 abivelj

It also seems to have an effect on the system back button on android. We have both the problems. The one with the keyboard not working and navigationlock which no longer work on .net 8, and just closes the app. image

It does no longer react when disabling refreshview.

Just noticed this as part of an issue in my application when trying to implement the RefreshView it stopped my NavigationLock from working.

samanson123 avatar Jul 20 '24 23:07 samanson123

I have the same issue :(

FeschenkoAlex avatar Aug 20 '24 10:08 FeschenkoAlex

I can repro this issue at Windows platform on the latest 17.12.0 Preview 1.0(8.0.80 & 8.0.3), but it worked on vs 17.11.0 for.NET 7. MauiApp43.zip

ninachen03 avatar Aug 23 '24 10:08 ninachen03

I have encountered the same issue using MAUI hybrid blazor with MudBlazor library. Whenever I disable RefreshView this also disables MudBlazor's inputs.

Any chance this will be fixed soon?

Vielire avatar Sep 20 '24 18:09 Vielire