import 'package:flutter/widgets.dart'; const double desktopBreakpoint = 1200; const double tabletBreakpoint = 960; enum DeviceBreakpoint { mobile, tablet, desktop } DeviceBreakpoint breakpointForWidth(double width) { if (width >= desktopBreakpoint) { return DeviceBreakpoint.desktop; } if (width >= tabletBreakpoint) { return DeviceBreakpoint.tablet; } return DeviceBreakpoint.mobile; } bool isDesktop(double width) => width >= desktopBreakpoint; bool isTablet(double width) => width >= tabletBreakpoint && width < desktopBreakpoint; bool isMobile(double width) => width < tabletBreakpoint; bool isDesktopContext(BuildContext context) => isDesktop(MediaQuery.of(context).size.width); bool isTabletContext(BuildContext context) => isTablet(MediaQuery.of(context).size.width); bool isMobileContext(BuildContext context) => isMobile(MediaQuery.of(context).size.width); class ResponsiveBreakpoints { ResponsiveBreakpoints._(this.width) : breakpoint = breakpointForWidth(width); final double width; final DeviceBreakpoint breakpoint; bool get isMobile => breakpoint == DeviceBreakpoint.mobile; bool get isTablet => breakpoint == DeviceBreakpoint.tablet; bool get isDesktop => breakpoint == DeviceBreakpoint.desktop; static ResponsiveBreakpoints of(BuildContext context) { final size = MediaQuery.of(context).size; return ResponsiveBreakpoints._(size.width); } } class ResponsiveLayoutBuilder extends StatelessWidget { const ResponsiveLayoutBuilder({ super.key, required this.mobile, this.tablet, required this.desktop, }); final WidgetBuilder mobile; final WidgetBuilder? tablet; final WidgetBuilder desktop; @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final breakpoint = breakpointForWidth(constraints.maxWidth); switch (breakpoint) { case DeviceBreakpoint.mobile: return mobile(context); case DeviceBreakpoint.tablet: final tabletBuilder = tablet ?? desktop; return tabletBuilder(context); case DeviceBreakpoint.desktop: return desktop(context); } }, ); } } class ResponsiveVisibility extends StatelessWidget { const ResponsiveVisibility({ super.key, required this.child, this.replacement = const SizedBox.shrink(), this.visibleOn = const { DeviceBreakpoint.mobile, DeviceBreakpoint.tablet, DeviceBreakpoint.desktop, }, }); final Widget child; final Widget replacement; final Set visibleOn; @override Widget build(BuildContext context) { final breakpoint = ResponsiveBreakpoints.of(context).breakpoint; return visibleOn.contains(breakpoint) ? child : replacement; } }