Files
krow-worker-app/lib/widgets/phone_frame.dart
2026-09-28 21:23:29 +05:30

66 lines
2.4 KiB
Dart

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,
),
),
),
),
);
}
}