yaru.dart Documentation

repository·main·Indexed 18 days ago

https://github.com/ubuntu/yaru.dart

Official Flutter implementation of the Yaru theme for desktop and web applications, designed for the Ubuntu 22.04+ aesthetic. It provides a suite of Yaru widgets, a theme engine (YaruTheme), and a complete Yaru icon set. Key features include responsive master-detail layouts via YaruMasterDetailPage, semantic color palettes through YaruColors, and themed containers like YaruBorderContainer and YaruTranslucentContainer.

Tokens
10.4K
Snippets
29
Records
41
Agent score
62%

What's inside yaru.dart

  1. Overview of Yaru Theme and Widgets Suite

    main

    The yaru.dart package provides a suite of tools for building Flutter applications that follow the Yaru design language used in Ubuntu 22.04+. It includes:

    • Yaru Widgets: Flutter widgets designed for desktop and web applications.
    • Yaru Theme: A theme implementation that applies to both standard material.dart widgets and custom Yaru widgets.
    • Yaru Icon Set: A complete set of icons following the Yaru design language.

    You can view a live demo of the suite at https://ubuntu.github.io/yaru.dart/.

  2. How to contribute new gtk<->Flutter theme mappings

    main

    To extend the theme mapping between GTK and Flutter, follow these two steps:

    1. Define a new YaruVariant in variant.dart.
    2. Add the corresponding mapping within the resolveVariant method located in inherited_theme.dart.
  3. Use YaruColors for semantic color palettes

    main

    The YaruColors class provides two main ways to access colors:

    1. Semantic Colors: These change based on the brightness of the theme.

      • YaruColors.from(Brightness brightness): Create a palette manually for a specific brightness.
      • YaruColors.of(BuildContext context): Retrieve the palette matching the current theme.
    2. Static Brand Colors: Constant colors that do not change with brightness, such as Ubuntu Orange, various greys, and specific flavor colors (e.g., kubuntuBlue, ubuntuMateGreen).

    // Accessing semantic colors via brightness
    final lightColors = YaruColors.from(Brightness.light);
    final darkColors = YaruColors.from(Brightness.dark);
    
    // Accessing static brand colors
    final orange = YaruColors.orange;
    final coolGrey = YaruColors.coolGrey;
  4. Configure YaruChoiceChipBarStyle layouts

    main

    The style property of YaruChoiceChipBar determines how the chips are laid out and how navigation behaves:

    • YaruChoiceChipBarStyle.wrap: Chips are laid out using a Wrap widget. This is ideal for a collection of chips that should flow onto multiple lines. Navigation buttons are not provided in this mode.
    • YaruChoiceChipBarStyle.row: Chips are laid in a single horizontal row with navigation buttons (previous/next) placed at the ends of the row. This uses a ListView for scrolling.
    • YaruChoiceChipBarStyle.stack: Chips are laid in a single horizontal row using a ListView, but the navigation buttons are overlaid on top of the list using a Stack. The list is clipped to create a fade-out effect near the buttons.
    // Example of using the wrap style
    YaruChoiceChipBar(
      labels: myLabels,
      isSelected: mySelectionStates,
      onSelected: myOnSelectedCallback,
      style: YaruChoiceChipBarStyle.wrap,
      spacing: 8.0,
      wrapAlignment: WrapAlignment.center,
    )```
  5. Use YaruDialogTitleBar for themed dialogs

    main
    YaruDialogTitleBar makes Flutter dialogs feel like top-level windows. It allows dragging the dialog to move the parent window and provides access to the window context menu. It is a subclass of YaruWindowTitleBar with default behaviors optimized for dialogs (e.g., the close button calls Navigator.maybePop).
  6. Use YaruPageIndicator for responsive page tracking

    main

    The YaruPageIndicator is a responsive widget used to visually track the current page in a sequence (like a carousel).

    It automatically adapts its layout based on available horizontal space:

    1. Dot Mode: If there is sufficient width, it renders a row of dots (or custom items).
    2. Text Mode: If space is constrained, it falls back to a text-based indicator (e.g., "2/12").

    You can use the default constructor for simple dot indicators or the .builder constructor for full customization of item sizes, item widgets, and text representation.

    YaruPageIndicator(
      length: 10,
      page: 2,
      onTap: (index) => print('Tapped page $index'),
    );
  7. Initialize YaruWindowTitleBar in your application

    main

    Before using YaruWindowTitleBar, you must call YaruWindowTitleBar.ensureInitialized() during application startup. This hides the native window title bar and configures the window content area for the underlying platform.

    Future<void> main() async {
      await YaruWindowTitleBar.ensureInitialized();
    
      runApp(...);
    }
  8. Apply the Yaru theme using YaruTheme

    main

    The YaruTheme widget applies the Yaru theme to its descendants. It automatically detects system settings (like accent color and dark mode) on Linux and rebuilds widgets when these settings change. There are two primary ways to use it:

    1. As a Child Widget

    Wrap your MaterialApp or a specific part of your widget tree. Note that YaruTheme must be a descendant of MaterialApp to prevent MaterialApp from overriding the theme.

    MaterialApp(
      home: YaruTheme(
        child: MyWidget(),
      ),
    )

    2. As a Builder

    Use the builder property to pass the resolved YaruThemeData directly into MaterialApp. This is the recommended approach because it allows all widgets created by MaterialApp (like the Navigator) to inherit the Yaru theme correctly.

    YaruTheme(
      builder: (context, yaru, child) {
        return MaterialApp(
          theme: yaru.theme,
          darkTheme: yaru.darkTheme,
          home: MyWidget(),
        );
      },
    )
    YaruTheme(
      builder: (context, yaru, child) {
        return MaterialApp(
          theme: yaru.theme,
          darkTheme: yaru.darkTheme,
          home: ...
        );
      },
    )
  9. Configure the debug banner when using YaruWindowTitleBar

    main

    The default MaterialApp debug banner can overlap with the in-scene window title bar. It is recommended to disable the built-in banner and use CheckedModeBanner within the content area instead.

    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: YaruWindowTitleBar(),
        body: CheckedModeBanner(
          child: ...
        ),
      ),
    )
  10. Avoid modal barrier issues with YaruWindowTitleBar

    main

    When YaruWindowTitleBar is placed inside a page route, a modal dialog will prevent interaction with the title bar because the modal barrier covers it. To avoid this, you can:

    1. Use YaruDialogTitleBar instead, which allows dragging the window from the dialog title bar.
    2. Use MaterialApp.builder to place the window title bar outside of the page route.

    Example using MaterialApp.builder:

    MaterialApp(
      builder: (context, child) => Scaffold(
        appBar: const YaruWindowTitleBar(
          title: Text('YaruWindowTitleBar'),
        ),
        body: child,
      ),
      home: ...
    )
  11. Use YaruMasterDetailPage for responsive master-detail layouts

    main

    The YaruMasterDetailPage widget implements a responsive master-detail pattern that automatically switches between portrait and landscape layouts based on a breakpoint.

    • In landscape mode, it displays a side pane (master) and a main content area (detail).
    • In portrait mode, it uses a navigation-based approach (typically a list that navigates to a detail view).

    To use it, you must provide a tileBuilder for the master list items and a pageBuilder for the detail content. It is highly recommended to use YaruMasterTile within your tileBuilder and YaruDetailPage within your pageBuilder to ensure consistent Yaru styling and layout.

    Key configuration options:

    • length: The total number of pages (if not using a controller).
    • tileBuilder: A builder for the master list items. Receives context, index, selected status, and availableWidth.
    • pageBuilder: A builder for the detail view. Receives context and index.
    • breakpoint: The width threshold for switching layouts. Defaults to the value in YaruMasterDetailTheme. Set to 0 for forced landscape or double.infinity for forced portrait.
    • controller: A YaruPageController to programmatically navigate pages.
    • onSelected: A callback triggered when a user selects a page.
    YaruMasterDetailPage(
      length: 8,
      appBar: AppBar(title: const Text('Master')),
      tileBuilder: (context, index, selected) => YaruMasterTile(
        leading: const Icon(YaruIcons.menu),
        title: Text('Master $index'),
      ),
      pageBuilder: (context, index) => YaruDetailPage(
        appBar: AppBar(
          title: Text('Detail $index'),
        ),
        body: Center(child: Text('Detail $index')),
      ),
    )