esys-flutter-share icon indicating copy to clipboard operation
esys-flutter-share copied to clipboard

Wrong Share modal position on tablet (iPad OS)

Open divan opened this issue 6 years ago • 3 comments

Describe the bug When I click on the button that triggers share action, on iPad OS (and, perhaps, on Android tablets?) the Share modal window appears, but it's located far from the actual button, and there is no way to specify position.

To Reproduce Create Scaffold with action button that triggers Share action with this plugin. Run on iPad. Click on the button (which is on the top right side), and observe Share modal window appear in the top left corner.

Expected behavior Share modal window appears close to the button that triggered the action.

Screenshots IMG_5B0498EF26B0-1

Additional context In the official Share plugin they have parameter for specifying the origin. It worked fine for me, when I was using that plugin: https://github.com/flutter/plugins/blob/master/packages/share/example/lib/main.dart#L69

Builder(
                  builder: (BuildContext context) {
                    return RaisedButton(
                      child: const Text('Share'),
                      onPressed: text.isEmpty
                          ? null
                          : () {
                              // A builder is used to retrieve the context immediately
                              // surrounding the RaisedButton.
                              //
                              // The context's `findRenderObject` returns the first
                              // RenderObject in its descendent tree when it's not
                              // a RenderObjectWidget. The RaisedButton's RenderObject
                              // has its position and size after it's built.
                              final RenderBox box = context.findRenderObject();
                              Share.share(text,
                                  subject: subject,
                                  sharePositionOrigin:
                                      box.localToGlobal(Offset.zero) &
                                          box.size);
                            },
                    );
                  },

divan avatar Oct 07 '19 15:10 divan

I believe iOS 13.2+ also messes up the placement of this, on iPad this share popover view is off of the screen completely. All of my new apps are being rejected because of this new placement issue.

ghost avatar Dec 09 '19 17:12 ghost

See https://github.com/esysberlin/esys-flutter-share/issues/46 which is the same bug.

As a crude workaround, I've modified the iOS source code like this:

        ....

        // set up activity view controller
        setupAndShow(activityItems)
    }

    private func setupAndShow(_ activityItems: [Any]) {
        let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        let controller = UIApplication.shared.keyWindow!.rootViewController as! FlutterViewController
        if let popover = activityViewController.popoverPresentationController {
            popover.sourceView = controller.view
            let bounds = controller.view.bounds
            popover.sourceRect = CGRect(x: bounds.width - 96, y: 20, width: 48, height: 48)
        }
        controller.show(activityViewController, sender: self)
    }

For a real fix, the Flutter part of the plugin would need to compute the screen position of the triggering button and pass this position to the native part.

sma avatar Dec 11 '19 12:12 sma

i made a pull request: #54

It works on my iPad (i don't have an iPhone).

While it is not merge you can use my repo if it works for you: pubsec.yaml:

  esys_flutter_share:
    git:
      url: git://github.com/neckaros/esys-flutter-share.git

Look it example to see how to set point of origin (@ sma i reused your points if we are on iPad and origin is not set so that it at least appear on screen (top right corner)) https://github.com/neckaros/esys-flutter-share/blob/master/example/lib/main.dart

 children: <Widget>[
                Builder(
                  builder: (BuildContext context) => MaterialButton(
                    child: Text('Share text'),
                    onPressed: () async => await _shareText(context),
                  ),
                ),...

...

  Rect rect(BuildContext context) {
    final RenderBox box = context.findRenderObject();
    return box.localToGlobal(Offset.zero) & box.size;
  }

  Future<void> _shareText(BuildContext context) async {
    try {
      Share.text('my text title',
          'This is my text to share with other applications.', 'text/plain',  sharePositionOrigin: rect(context),);
    } catch (e) {
      print('error: $e');
    }
  }

neckaros avatar Feb 18 '20 23:02 neckaros