import 'dart:math' as math; import 'package:flutter/material.dart'; import '../core/theme.dart'; /// Holds the app to phone proportions on anything wider than a phone. /// /// This is a worker app: every screen is laid out for a thumb, and stretched /// across a laptop the same screens read as a broken website rather than an /// app. On a wide window the app is pinned to a phone-sized panel in the /// middle and the surrounding space is filled with a flat backdrop, so a /// worker who opens the link on a desktop gets the same interface a phone /// would show them. class PhoneFrame extends StatelessWidget { const PhoneFrame({super.key, required this.child}); final Widget child; /// Below this the window is a phone already, so it is left alone. 600 is /// the usual Material breakpoint: narrow tablets in portrait sit above it /// and get the panel, which is the point — a tablet stretches the layout /// just as badly as a laptop does. static const double breakpoint = 600; /// A large phone, roughly a Pixel's logical size. static const Size panel = Size(420, 900); @override Widget build(BuildContext context) { final media = MediaQuery.of(context); if (media.size.width < breakpoint) return child; // Short windows give the panel everything they have rather than cropping // it, so the app is never taller than the space it is drawn into. final height = math.min(panel.height, media.size.height); final size = Size(panel.width, height); final rounded = height < media.size.height; return ColoredBox( color: KrowPalette.ink, child: Center( child: SizedBox.fromSize( size: size, child: ClipRRect( borderRadius: BorderRadius.circular(rounded ? 28 : 0), child: MediaQuery( // The app measures itself against the panel, not the window: // sheets sized as a fraction of the screen height and anything // reading the width would otherwise use the desktop's numbers. // Window padding goes too — the browser's safe areas belong to // the edges of the page, which the panel no longer touches. data: media.copyWith( size: size, padding: EdgeInsets.zero, viewPadding: EdgeInsets.zero, ), child: child, ), ), ), ), ); } }