66 lines
2.4 KiB
Dart
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,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|