seatlayer 0.6.3 copy "seatlayer: ^0.6.3" to clipboard
seatlayer: ^0.6.3 copied to clipboard

Flutter seat map SDK: a native seating chart and seat picker for iOS and Android ticketing apps, with live availability, best available, seat holds, 3D views and secure checkout.

example/lib/main.dart

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

const _eventKey = String.fromEnvironment('SEATLAYER_EVENT');
const _publicKey = String.fromEnvironment('SEATLAYER_PUBLIC_KEY');
const _runtimeUrl = String.fromEnvironment('SEATLAYER_RUNTIME_URL');
const _apiBase = String.fromEnvironment('SEATLAYER_API_BASE');
const _themeModeName = String.fromEnvironment(
  'SEATLAYER_THEME_MODE',
  defaultValue: 'auto',
);

/// The theme mode named by `--dart-define=SEATLAYER_THEME_MODE=…`.
///
/// Unknown names fall back to [SeatLayerThemeMode.auto] so a typo opens the
/// picker rather than failing the run.
SeatLayerThemeMode get _themeMode => switch (_themeModeName) {
  'light' => SeatLayerThemeMode.light,
  'dark' => SeatLayerThemeMode.dark,
  _ => SeatLayerThemeMode.auto,
};

void main() => runApp(const DemoApp());

/// The example app.
///
/// It opens on the live picker, which is the product. Pass no event key and it
/// says so rather than quietly showing something else; the raw protocol-1
/// fixture lives in `offline_fixture_demo.dart` for bridge work.
class DemoApp extends StatelessWidget {
  /// Creates the example app.
  const DemoApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'SeatLayer Flutter seat picker',
    debugShowCheckedModeBanner: false,
    theme: ThemeData(useMaterial3: true),
    darkTheme: ThemeData.dark(useMaterial3: true),
    themeMode: switch (_themeMode) {
      SeatLayerThemeMode.light => ThemeMode.light,
      SeatLayerThemeMode.dark => ThemeMode.dark,
      SeatLayerThemeMode.auto => ThemeMode.system,
    },
    home: _eventKey.isEmpty ? const _MissingEventKey() : const LivePickerDemo(),
  );
}

class _MissingEventKey extends StatelessWidget {
  const _MissingEventKey();

  @override
  Widget build(BuildContext context) => const Scaffold(
    body: Center(
      child: Padding(
        padding: EdgeInsets.all(28),
        child: Text(
          'Run with --dart-define=SEATLAYER_EVENT=ev_… and '
          '--dart-define=SEATLAYER_PUBLIC_KEY=pk_test_… to open the '
          'picker.\n\nFor bridge work without a key, run '
          'lib/offline_fixture_demo.dart.',
          textAlign: TextAlign.center,
        ),
      ),
    ),
  );
}

/// The complete native picker used for live protocol-v2 validation.
///
/// Run with:
///
///   flutter run \
///     --dart-define=SEATLAYER_EVENT=ev_your_test_event \
///     --dart-define=SEATLAYER_PUBLIC_KEY=pk_test_your_public_key
///
/// Optional: `SEATLAYER_API_BASE` points the session at another API origin, and
/// `SEATLAYER_THEME_MODE=auto|light|dark` pins the picker's appearance.
///
/// While validating a pre-release renderer, also point the SDK at it:
///
///   --dart-define=SEATLAYER_RUNTIME_URL=https://…
class LivePickerDemo extends StatefulWidget {
  const LivePickerDemo({super.key});

  @override
  State<LivePickerDemo> createState() => _LivePickerDemoState();
}

class _LivePickerDemoState extends State<LivePickerDemo> {
  late final SeatLayerConfiguration _configuration = SeatLayerConfiguration(
    event: _eventKey,
    publicKey: _publicKey.isEmpty ? null : _publicKey,
    apiBase: _apiBase.isEmpty ? null : _apiBase,
    hostInfo: const {'app': 'SeatLayerFlutterPickerExample/0.3-dev'},
    assetPath: _runtimeUrl.isEmpty
        ? SeatLayerConfiguration.defaultAssetPath
        : _runtimeUrl,
  );

  Future<void> _openCheckout(SeatLayerCheckoutHandoff handoff) async {
    if (!mounted) return;
    await showModalBottomSheet<void>(
      context: context,
      showDragHandle: true,
      builder: (context) => SafeArea(
        child: Padding(
          padding: const EdgeInsets.fromLTRB(24, 4, 24, 24),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Text(
                'Checkout handoff received',
                style: Theme.of(context).textTheme.titleLarge,
              ),
              const SizedBox(height: 12),
              Text(
                '${handoff.lineItems.length} line item(s) · '
                '${handoff.currency} ${handoff.total.toStringAsFixed(2)}',
              ),
              const SizedBox(height: 12),
              const Text(
                'The hold is now host-owned. Send handoff.holdId to your '
                'trusted backend, inspect the hold there, then take payment '
                'and book with an idempotent order reference.',
              ),
              const SizedBox(height: 20),
              FilledButton(
                onPressed: () => Navigator.of(context).pop(),
                child: const Text('Done'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SeatLayerPicker(
        configuration: _configuration,
        themeMode: _themeMode,
        callbacks: SeatLayerPickerCallbacks(
          onReady: (info) {
            final helloToReadyMs = info.timeToHelloMs == null ||
                    info.timeToReadyMs == null
                ? null
                : info.timeToReadyMs! - info.timeToHelloMs!;
            debugPrint(
              '[SeatLayerPickerExample] ready '
              'protocol=${info.protocolRevision} '
              'mode=${info.mode.raw} '
              'event=${info.eventKey ?? "-"} '
              'timeToHelloMs=${info.timeToHelloMs} '
              'helloToReadyMs=$helloToReadyMs '
              'timeToReadyMs=${info.timeToReadyMs}',
            );
          },
          onChartLoad: (load) {
            final trace = load.trace;
            debugPrint(
              '[SeatLayerPickerPerf] '
              'tapToReadyMs=${load.tapToReadyMs} '
              'hostMs=${load.hostMs} '
              'bootMs=${trace.bootMs} '
              'documentMs=${trace.documentMs} '
              'handshakeMs=${trace.handshakeMs} '
              'renderMs=${trace.ms} '
              'paintMs=${trace.paint} '
              'availabilityMs=${trace.availabilityMs} '
              'load=${trace.load} '
              'chartCache=${trace.chartCache} '
              'host=${trace.host} '
              'platform=${trace.platform} '
              'bundle=${trace.bundle}',
            );
          },
          onError: (error) {
            debugPrint('[SeatLayerPickerExample] error=${error.code}');
          },
        ),
        onCheckout: _openCheckout,
      ),
    );
  }
}
1
likes
0
points
1.07k
downloads

Documentation

Documentation

Publisher

verified publisherseatlayer.io

Weekly Downloads

Flutter seat map SDK: a native seating chart and seat picker for iOS and Android ticketing apps, with live availability, best available, seat holds, 3D views and secure checkout.

Homepage
Repository (GitHub)
View/report issues

Topics

#seat-map #seating-chart #seat-picker #reserved-seating #event-ticketing

License

unknown (license)

Dependencies

flutter, meta, webview_flutter

More

Packages that depend on seatlayer