I am creating a class for notifications that is outside of context using bot_toast, which will be called on API errors and such. I need to leave a margin that is relative to the screen width, but I don't have the context here. I could pass the context around, it doesn't seem like the best option.

So I am ending up with something like this

Function CustomToast (message) {
  return BotToast.showAttachedWidget(
      attachedBuilder: (_) => Align(
        alignment: Alignment.topRight,
        child: Container(
          margin: new EdgeInsets.only(top: 25, right: 25.0),
          color: Colors.blue,
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(
              message,              
            ),
          ),
        ),
      ),
      duration: Duration(seconds: 20),
      target: Offset(520, 520));
}

I need to set the righ margin as a percentage. How would I access the screen width here? is it possible without context? Any suggestion is welcome, even a change of toast library


Solution 1: JonnyH

Perhaps an app level model. Once you have a context, you can set the screen resolution for later retrieval of calculated percentage. I use this approach frequently.

  class ScreenInfoViewModel {
  List<String> _setupCompleted = [];

  String appName;
  String packageName;
  String version;
  String buildNumber;
  double screenWidth;

  ScreenInfoViewModel() {
    init();
  }

  init() async {
    var packageInfo = await PackageInfo.fromPlatform();
    appName = packageInfo.appName;
    packageName = packageInfo.packageName;
    version = packageInfo.version;
    buildNumber = packageInfo.buildNumber;
  }

  bool _smallScreen = false;
  bool _mediumScreen = false;
  bool _largeScreen = false;

  void setScreenSize(double this.screenWidth, double diagonalInches) {
    _smallScreen = diagonalInches < 5.11;
    _mediumScreen = !_smallScreen && diagonalInches <= 5.6;
    _largeScreen = diagonalInches > 5.6;
  }

  bool get isSmallScreen => _smallScreen;
  bool get isMediumScreen => _mediumScreen;
  bool get isLargeScreen => _largeScreen;

  String get screenSize {
    String size = 'S';
    if (_mediumScreen) size = 'M';
    if (_largeScreen) size = 'L';
    return size;
  }
}

I use it this way:

class SetupScreenInfo extends HookWidget {
  // Use GetIt package to retrieve the model
  final ScreenInfoViewModel _s = locator(); 

  final _scaffoldKey = new GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {

    ///  This is the first 'context' with a MediaQuery, therefore,
    ///  this is the first opportunity to set these values.
    ///  widthPx and diagonalInches are from sized_context package.
    _s.setScreenSize(context.widthPx, context.diagonalInches);

    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (context == null) return;
      Navigator.pushReplacementNamed(context, splashRoute);
    });

    return SafeArea(
      child: Scaffold(
        key: _scaffoldKey,
        body: Material(color: Colors.yellow[300]),
      ),
    );
  }
}

Finally, SetupScreenInfo is my initial route from my MaterialApp.

This code is an edit of my production code and has not been tested and is not a runnable example.

Hope this help generate some thought.