Alex-Dobrynin / Xamarin.Controls.ImageCropper

Cross platform Xamarin library to crop and rotate images
MIT License
8 stars 2 forks source link

[IOS >= 15] Issue with getting GetDefaultWindow() #8

Open amahera opened 1 week ago

amahera commented 1 week ago

By using the current version of GetDefaultWindow() we have to add a delay after such call - await MediaPicker.PickPhotoAsync();

I believe that this can be fixed in such way: for iOS>=15

UIApplication.SharedApplication.ConnectedScenes .OfType() .SelectMany(s => s.Windows) .First(w => w.IsKeyWindow);

Alex-Dobrynin commented 1 week ago

what is the difference between current implementaion and your suggestion?

amahera commented 1 week ago

@Alex-Dobrynin Sorry, it was not the only change that I've tried, so I believe that the actual problem is this part of code while (topVC.PresentedViewController != null) { topVC = topVC.PresentedViewController; } and if we use await Task.Delay before calling crop we wait till PresentedViewController becomes null (from the previous UIController with image picker for example)

amahera commented 1 week ago

In case if it's needed for modal navigation - maybe here we can check if PresentedViewController is Microsoft.Maui.Platform.ModalWrapper(but it's internal, so maybe check by type name). And allow such assigning if that our modal navigation.

amahera commented 1 week ago

I would like to propose something like this

public static UIViewController GetRootViewController(this UIApplication application)
 {
     var window =  OperatingSystem.IsIOSVersionAtLeast(15)
         ? application.ConnectedScenes
             .OfType<UIWindowScene>()
             .SelectMany(s => s.Windows)
             .First(w => w.IsKeyWindow)
         : UIApplication.SharedApplication.Windows.Last();

     var top = window.RootViewController!;

     if (top.PresentedViewController != null && top.PresentedViewController.GetType().Name.Contains("ModalWrapper", StringComparison.InvariantCultureIgnoreCase))
     {
         top = top.PresentedViewController;
     }

     return top;
 }
Alex-Dobrynin commented 1 week ago

From my point of view there is bug in MediaPicker, not in this lib. as they setting the result and then closing activity.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent? data)
{
    base.OnActivityResult(requestCode, resultCode, data);

    // we have a valid GUID, so handle the task
    if (GetIntermediateTask(guid, true) is IntermediateTask task)
    {
        if (resultCode == Result.Canceled)
        {
            task.TaskCompletionSource.TrySetCanceled();
        }
        else
        {
            try
            {
                data ??= new Intent();

                task.OnResult?.Invoke(data);

                task.TaskCompletionSource.TrySetResult(data);
            }
            catch (Exception ex)
            {
                task.TaskCompletionSource.TrySetException(ex);
            }
        }
    }

    // close the intermediate activity
    Finish();
}

you may create an issue in MAUI's github and describe your case. or even PR, just change the order of calls.

amahera commented 1 week ago

yeah, seems like that

Alex-Dobrynin commented 1 week ago

Same in ios

picker.Delegate = new PhotoPickerDelegate
{
    CompletedHandler = async info =>
    {
        GetFileResult(info, tcs);
        await vc.DismissViewControllerAsync(true);
    }
};