veneer 0.7.2 copy "veneer: ^0.7.2" to clipboard
veneer: ^0.7.2 copied to clipboard

Real native iOS 26 UI for Flutter: Liquid Glass, UIKit tab and navigation bars, composers and sheets driven by Flutter layout, with matching Flutter UI on Android.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:veneer/veneer.dart';

import 'pages/assistant_page.dart';
import 'pages/chat_page.dart';
import 'pages/clip_page.dart';
import 'pages/diagnostics_page.dart';
import 'pages/morph_page.dart';
import 'pages/sync_test_page.dart';
import 'app_icons.dart';

/// Launch arguments (see ios/Runner/AppDelegate.swift) let
/// `tool/measure_sync.py` runs be scripted:
///   -VENEER_TRANSPORT ffi|channel|delayedChannel
///   -VENEER_MEASURE 1   → Sync page starts in measure mode, auto-scrolling
bool launchMeasureMode = false;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  try {
    final config = await const MethodChannel('example/launch_config').invokeMapMethod<String, String?>('get');
    final transport = config?['transport'];
    if (transport != null) VeneerBridge.instance.transport = VeneerTransport.values.byName(transport);
    launchMeasureMode = config?['measure'] == '1';
    // -VENEER_FALLBACK 1: preview the Android / iOS 15–25 UI on iOS 26.
    Veneer.debugForceFallback = config?['fallback'] == '1';
  } on MissingPluginException {
    // Not running the example's iOS runner.
  }
  runApp(const ExampleApp());
}

/// The assistant sheet's own engine (see `openAssistant`): on iOS 26 the
/// sheet is a real UIKit sheet, and its Flutter content starts here.
@pragma('vm:entry-point')
void assistantSheet() => runNativeSheet(
  MaterialApp(
    debugShowCheckedModeBanner: false,
    theme: exampleTheme(Brightness.light),
    darkTheme: exampleTheme(Brightness.dark),
    home: const AssistantPage(),
  ),
);

ThemeData exampleTheme(Brightness brightness) => ThemeData(colorSchemeSeed: Colors.indigo, brightness: brightness);

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Veneer',
      debugShowCheckedModeBanner: false,
      theme: exampleTheme(Brightness.light),
      darkTheme: exampleTheme(Brightness.dark),
      navigatorObservers: [VeneerNavigatorObserver()],
      home: const HomePage(),
    );
  }
}

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

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

/// Which icon type the tab bar's trailing button uses; switchable from the
/// Diagnostics page to compare SF Symbol, IconData and SVG side by side.
enum TrailingIconKind { symbol, iconData, svg }

final ValueNotifier<TrailingIconKind> trailingIconKind = ValueNotifier(TrailingIconKind.svg);

class _HomePageState extends State<HomePage> {
  int _index = 0;

  @override
  void initState() {
    super.initState();
    // The assistant sheet's engine starts now, so the sheet opens with content.
    NativeSheet.prewarm('assistantSheet');
    // Scripted measurement runs (tool/measure_sync.py) open the sync test directly.
    if (launchMeasureMode) {
      WidgetsBinding.instance.addPostFrameCallback((_) => openSyncTest(context));
    }
  }

  // The AI button: a gradient SVG in its own colours by default.
  static const _trailingIcons = {
    TrailingIconKind.symbol: NativeIcon.symbol('sparkles'),
    TrailingIconKind.iconData: NativeIcon.icon(AppIcons.sparkleFill),
    TrailingIconKind.svg: NativeIcon.svgAsset('assets/icons/ai_sparkle.svg', tinted: false),
  };

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: trailingIconKind,
      builder: (context, kind, _) => NativeChromeScope(
        // One of each icon type: SF Symbol, Material IconData (with a selected
        // variant), an SVG asset, and Cupertino IconData from a package font.
        tabs: const [
          NativeTabItem(
            title: 'Chat',
            icon: NativeIcon.icon(AppIcons.chatsCircle),
            selectedIcon: NativeIcon.icon(AppIcons.chatsCircleFill),
          ),
          NativeTabItem(
            title: 'Morph',
            icon: NativeIcon.icon(AppIcons.drop),
            selectedIcon: NativeIcon.icon(AppIcons.dropFill),
          ),
          NativeTabItem(title: 'Clip', icon: NativeIcon.svgAsset('assets/icons/scissors.svg')),
          NativeTabItem(title: 'Lab', icon: NativeIcon.icon(AppIcons.gauge), badge: '3'),
        ],
        scrollEdgeEffect: NativeScrollEdgeEffect.soft,
        trailingAction: NativeTabAction(
          icon: _trailingIcons[kind]!,
          title: 'Assistant',
          onPressed: () => openAssistant(context),
        ),
        selectedIndex: _index,
        onTabSelected: (i) => setState(() => _index = i),
        child: IndexedStack(index: _index, children: const [ChatPage(), MorphPage(), ClipPage(), DiagnosticsPage()]),
      ),
    );
  }
}

/// Pushes the glass sync-lag test (see tool/measure_sync.py).
void openSyncTest(BuildContext context) {
  Navigator.of(context).push(MaterialPageRoute<void>(builder: (_) => const SyncTestPage()));
}
2
likes
0
points
1.94k
downloads

Publisher

unverified uploader

Weekly Downloads

Real native iOS 26 UI for Flutter: Liquid Glass, UIKit tab and navigation bars, composers and sheets driven by Flutter layout, with matching Flutter UI on Android.

Repository (GitHub)
View/report issues

Topics

#ios #liquid-glass #uikit #native #ui

License

unknown (license)

Dependencies

flutter, flutter_svg

More

Packages that depend on veneer

Packages that implement veneer