sound_fonts

sound_fonts is a build_runner package generating Fonts class to encapsulate all the fonts your Flutter application uses with the easy and understandable namings.

Getting started

Simply add the package to your pubspec.yaml:

dependencies:
  sound_fonts: ^0.1.2

or from GitHub directly:

dependencies:
  sound_fonts:
    git: https://github.com/lapuske/sound_fonts

Usage

Detailed example is placed under /example directory.

Fonts

Basically you define the annotation and run the build_runner:

import 'package:flutter/rendering.dart';
import 'package:sound_fonts/sound_fonts.dart';

part 'main.g.dart';

@SoundFonts({
  'largest': {
    'bold': ['onBackground', 'primary'],
    'regular': ['onBackground', 'primary'],
  },
  'large': {
    'bold': ['onBackground', 'primary', 'secondary'],
    'regular': ['onBackground', 'onPrimary'],
  },
})
class AnnotatedFonts {}

This generates a file with the following class (getters and lerp omitted):

class Fonts {
  Fonts({
    required TextStyle style,
    required double largest,
    required double large,
    required FontWeight bold,
    required FontWeight regular,
    required Color onBackground,
    required Color primary,
    required Color secondary,
    required Color onPrimary,
  })  : largest = Largest(
          style: style.copyWith(fontSize: largest),
          bold: bold,
          regular: regular,
          onBackground: onBackground,
          primary: primary,
        ),
        large = Large(
          style: style.copyWith(fontSize: large),
          bold: bold,
          regular: regular,
          onBackground: onBackground,
          primary: primary,
          secondary: secondary,
          onPrimary: onPrimary,
        );

  final Largest largest;
  final Large large;
}

Your application is expected to construct it with the parameters it requires:

final fonts = Fonts(
  style: TextStyle(fontFamily: '123'),
  largest: 27,
  large: 24,
  bold: FontWeight.bold,
  regular: FontWeight.regular,
  onBackground: Colors.white,
  primary: Colors.blue,
  secondary: Colors.grey,
  onPrimary: Colors.black,
);

The generated class may even be included to your Theme.of in the ThemeExtension form:

class FontsExtension extends ThemeExtension<Fonts> {
  // ...
}

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData.light().copyWith(
        extensions: [FontsExtension()],
      ),
    ),
  );
}

Then, throughout the application you may use the fonts in the following manner:

@override
Widget build(BuildContext context) {
  final fonts = Theme.of(context).extension<FontsExtension>()!;

  return Text('Hello', style: fonts.medium.regular.onBackground);
}

Colors

Package is capable of generating the colors palette in the same manner as the fonts. To accomplish this, use the SoundColors annotation:

import 'package:flutter/rendering.dart';
import 'package:sound_fonts/sound_fonts.dart';

part 'main.g.dart';

@SoundColors(['onBackground', 'primary', 'secondary', 'secondary50'])
class AnnotatedColors {}

This generates a file with the following class (lerp omitted):

class Palette {
  Palette({
    required this.onBackground,
    required this.primary,
    required this.secondary,
    Color? secondary50,
  })  : secondary50 = secondary50 ?? secondary.withValues(alpha: 0.5);

  final Color onBackground;
  final Color primary;
  final Color secondary;
  final Color secondary50;
}

Your application is expected to construct it with the parameters it requires:

final colors = Palette(
  onBackground: Colors.white,
  primary: Colors.blue,
  secondary: Colors.grey,
);

The generated class may even be included to your Theme.of in the ThemeExtension form:

class ColorsExtension extends ThemeExtension<Palette> {
  // ...
}

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData.light().copyWith(
        extensions: [ColorsExtension()],
      ),
    ),
  );
}

Then, throughout the application you may use the colors in the following manner:

@override
Widget build(BuildContext context) {
  final colors = Theme.of(context).extension<ColorsExtension>()!;
  
  return ColoredBox(color: colors.onBackground);
}

Both

It is recommended to unite the Fonts and Palette classes generated so that your styles are in one place.

To do that, create a Style class and include both into it:

class Style {
  const Style({
    this.fonts,
    this.colors,
  });

  final Fonts fonts;
  final Palette colors;
}

Then, create a theme.dart file, and add the following:

class Themes {
  /// Returns a light theme.
  static ThemeData light() {
    final Palette colors = Palette(
      /* */
    );

    final Fonts fonts = Fonts(
      /* */
    );

    return ThemeData.light().copyWith(
      extensions: [
        Style(
          fonts: fonts,
          colors: colors,
        )
      ],
      /* Customize the Flutter's theme using the values above */
    );
  }
}

Additionally the following extensions is recommended to have in the theme.dart file:

/// Extension adding [Style] handy getter from the [ThemeData].
extension ThemeStylesExtension on ThemeData {
  /// Returns the [Style] of this [ThemeData].
  Style get style => extension<Style>()!;
}

Now you can access any values you're adding with a easy single call of the getter above:

@override
Widget build(BuildContext context) {
  final style = Theme.of(context).style;

  return ColoredBox(
    color: style.colors.primary,
    child: Text(
      'Hello',
      style: style.fonts.medium.regular.onBackground,
    ),
  );
}

Libraries

sound_fonts