flight_check 1.1.0 copy "flight_check: ^1.1.0" to clipboard
flight_check: ^1.1.0 copied to clipboard

A Flutter debug-mode tool for previewing your app against popular mobile device profiles while running on desktop.

example/lib/main.dart

import 'package:flight_check/flight_check.dart';
import 'package:flutter/material.dart';

const List<(IconData, String, String)> _discoveries = [
  (Icons.whatshot, 'Betelgeuse', 'Red supergiant · 700 solar radii'),
  (Icons.brightness_7, 'Sirius', 'Brightest star in the night sky'),
  (Icons.blur_on, 'Andromeda', 'Nearest major galaxy · 2.5 Mly'),
  (Icons.grain, 'Orion Nebula', 'Stellar nursery · 1,344 light-years'),
  (Icons.circle, 'Proxima Centauri', 'Closest star · 4.24 light-years'),
  (Icons.nights_stay, 'Pleiades', 'Open cluster · Seven Sisters'),
  (Icons.tornado, 'Pillars of Creation', 'Eagle Nebula · 6,500 light-years'),
  (Icons.air, 'Sagittarius A*', 'Milky Way central black hole'),
  (Icons.flare, 'Eta Carinae', 'Hypergiant · 5 million solar luminosities'),
];

void main() {
  FlightCheck.configure();

  runApp(const FlightCheckExampleApp());
}

class FlightCheckExampleApp extends StatefulWidget {
  const FlightCheckExampleApp({super.key});

  @override
  State<FlightCheckExampleApp> createState() => _FlightCheckExampleAppState();
}

class _FlightCheckExampleAppState extends State<FlightCheckExampleApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Stellar',
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: ThemeMode.system,
      debugShowCheckedModeBanner: false,
      home: const _HomePage(),
    );
  }
}

class _HomePage extends StatefulWidget {
  const _HomePage();

  @override
  State<_HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<_HomePage> {
  int _selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Stellar'),
        centerTitle: true,
        actions: [
          IconButton(icon: Icon(Icons.adaptive.more), onPressed: () {}),
        ],
        actionsPadding: const EdgeInsets.symmetric(horizontal: 8),
      ),
      drawer: const _DeviceInfoDrawer(),
      body: const _DiscoverPage(),
      bottomNavigationBar: NavigationBar(
        selectedIndex: _selectedIndex,
        onDestinationSelected: (i) => setState(() => _selectedIndex = i),
        destinations: const [
          NavigationDestination(icon: Icon(Icons.explore), label: 'Discover'),
          NavigationDestination(icon: Icon(Icons.star), label: 'Favourites'),
          NavigationDestination(icon: Icon(Icons.person), label: 'Profile'),
        ],
      ),
    );
  }
}

class _DeviceInfoDrawer extends StatelessWidget {
  const _DeviceInfoDrawer();

  @override
  Widget build(BuildContext context) {
    final platform = Theme.of(context).platform;
    final mq = MediaQuery.of(context);

    final size = mq.size;
    final dpr = mq.devicePixelRatio;
    final padding = mq.padding;

    return Drawer(
      child: ListView(
        padding: EdgeInsets.zero,
        children: [
          DrawerHeader(
            child: Text(
              'Device info',
              style: Theme.of(context).textTheme.titleLarge,
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            child: Column(
              children: [
                _InfoRow('Platform', platform.name),
                _InfoRow(
                  'Screen size',
                  '${size.width.toStringAsFixed(0)} x '
                      '${size.height.toStringAsFixed(0)} pt',
                ),
                _InfoRow('Device pixel ratio', dpr.toStringAsFixed(3)),
                _InfoRow(
                  'Safe area (LTRB)',
                  '${padding.left.toStringAsFixed(0)}, '
                      '${padding.top.toStringAsFixed(0)}, '
                      '${padding.right.toStringAsFixed(0)}, '
                      '${padding.bottom.toStringAsFixed(0)}',
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _InfoRow extends StatelessWidget {
  const _InfoRow(this.label, this.value);

  final String label;
  final String value;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 6),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            width: 120,
            child: Text(
              label,
              style: theme.textTheme.bodySmall?.copyWith(
                color: theme.colorScheme.onSurfaceVariant,
              ),
            ),
          ),
          Expanded(child: Text(value, style: theme.textTheme.bodyMedium)),
        ],
      ),
    );
  }
}

class _DiscoverPage extends StatelessWidget {
  const _DiscoverPage();

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        for (final item in _discoveries)
          Card(
            clipBehavior: Clip.antiAlias,
            child: ListTile(
              leading: Icon(
                size: 48,
                item.$1,
                color: theme.colorScheme.primary,
              ),
              title: Text(item.$2),
              subtitle: Text(item.$3),
              trailing: const Icon(Icons.chevron_right),
              onTap: () => Navigator.of(context).push(
                MaterialPageRoute<void>(
                  builder: (_) => _DetailPage(item: item),
                ),
              ),
            ),
          ),
      ],
    );
  }
}

class _DetailPage extends StatelessWidget {
  const _DetailPage({required this.item});

  final (IconData, String, String) item;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final (icon, name, description) = item;
    return Scaffold(
      appBar: AppBar(
        // Flutter's AppBar automatically inserts a BackButton here, which uses
        // Icons.adaptive.arrow_back — a left-chevron on iOS and a left-arrow on
        // Android — so the back affordance matches the emulated platform.
        title: Text(name),
        centerTitle: true,
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          spacing: 24,
          children: [
            Icon(icon, size: 96, color: theme.colorScheme.primary),
            Text(name, style: theme.textTheme.headlineSmall),
            Text(
              description,
              style: theme.textTheme.bodyLarge?.copyWith(
                color: theme.colorScheme.onSurfaceVariant,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
150
points
81
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter debug-mode tool for previewing your app against popular mobile device profiles while running on desktop.

Repository (GitHub)
View/report issues
Contributing

License

BSD-3-Clause (license)

Dependencies

flutter, window_manager

More

Packages that depend on flight_check