gmana_flutter 0.0.8 copy "gmana_flutter: ^0.0.8" to clipboard
gmana_flutter: ^0.0.8 copied to clipboard

A comprehensive Flutter UI library providing curated widgets, form helpers, theme services, and extensions to accelerate and standardize development.

gmana_flutter #

Flutter UI utilities for production apps: form fields, loading indicators, theme helpers, color tools, responsive extensions, and small design-system tokens.

For a full API guide covering every exported helper, widget, and function, see doc/api.md.

gmana_flutter is the Flutter-facing package in the Gmana ecosystem. Use it when you want a practical set of app UI helpers that work from one import:

import 'package:gmana_flutter/gmana_flutter.dart';

Requirements #

  • Dart SDK ^3.7.2
  • Flutter >=3.29.0

Installation #

flutter pub add gmana_flutter

If you use validator configuration classes such as PasswordValidationConfig, add the core package too:

flutter pub add gmana

Manual pubspec.yaml setup:

dependencies:
  gmana: ^0.1.5
  gmana_flutter: ^0.0.8

Quick Start #

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Gmana Flutter Demo',
      theme: GColors.lightTheme,
      darkTheme: GColors.darkTheme,
      themeMode: 'system'.toThemeMode(),
      home: const HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const GAppBar(title: 'Home'),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const GSpinnerWaveDot(size: 28, color: GColors.primary),
            const SizedBoxHeight(),
            Text(
              'Ready',
              style: TextStyle(color: GColors.primary.contrastText),
            ),
          ],
        ),
      ),
    );
  }
}

What You Can Use #

Area APIs
Widgets GAppBar, GListTile, SizedBoxHeight, StarRatingBar
Forms GEmailField, GPasswordField, GNumberField, GTextField, GConfirmPasswordField, GElevatedButton
Loading GCircularSpinner, GLinearSpinner, GSpinnerDot, GWaveSpinner, GSpinnerWaveDot
Theme GColors, GFontWeight, ThemeModeExt, ThemeModeService
Color ColorExt, StringColorExtension, ColorService
Layout Breakpoint, Breakpoints, BreakpointUtils, ResponsiveContext, ContextExt
Utilities IconDataExt, IconDataSerialization, fromLocale, toLocale, registerErrorHandlers

Theme Setup #

Use the built-in themes directly:

MaterialApp(
  theme: GColors.lightTheme,
  darkTheme: GColors.darkTheme,
  themeMode: ThemeMode.system,
  home: const HomePage(),
);

Or keep the selected theme mode as a string:

final savedTheme = 'dark';

MaterialApp(
  themeMode: savedTheme.toThemeMode(),
  theme: GColors.lightTheme,
  darkTheme: GColors.darkTheme,
  home: const HomePage(),
);

Useful theme helpers:

final service = ThemeModeService();
final key = service.getKey(ThemeMode.dark); // 'dark'
final label = ThemeMode.dark.toLabel(); // 'Dark Mode'
final icon = ThemeMode.dark.toIcon(); // Icons.dark_mode

final mode = service.fromKey('light');
final labels = service.getThemeKeys().map(service.getLabelFromKey).toList();

Forms #

The field widgets wrap TextFormField with consistent defaults and validators from the core gmana package.

import 'package:flutter/material.dart';
import 'package:gmana/validation.dart';
import 'package:gmana_flutter/gmana_flutter.dart';

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

  @override
  State<AccountForm> createState() => _AccountFormState();
}

class _AccountFormState extends State<AccountForm> {
  final formKey = GlobalKey<FormState>();
  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  final confirmPasswordController = TextEditingController();

  @override
  void dispose() {
    emailController.dispose();
    passwordController.dispose();
    confirmPasswordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Column(
        children: [
          GEmailField(
            controller: emailController,
            labelText: 'Email',
          ),
          const SizedBoxHeight(),
          GPasswordField(
            controller: passwordController,
            validationConfig: PasswordValidationConfig.strong(),
          ),
          const SizedBoxHeight(),
          GConfirmPasswordField(
            controller: confirmPasswordController,
            passwordController: passwordController,
          ),
          const SizedBoxHeight(spacing: 24),
          GElevatedButton(
            text: 'Create account',
            isLoading: false,
            onPressed: () {
              if (formKey.currentState?.validate() ?? false) {
                context.showSuccessSnackBar(message: 'Account form is valid');
              }
            },
          ),
        ],
      ),
    );
  }
}

For custom TextFormField configuration, use GConfiguredTextFormField:

GConfiguredTextFormField(
  config: GFieldConfig(
    controller: controller,
    labelText: 'Display name',
    hintText: 'Enter your name',
    prefixIcon: Icons.person,
    validator: (value) => value == null || value.isEmpty ? 'Required' : null,
  ),
);

Loading Indicators #

Use the lightweight indicators anywhere a normal widget is accepted:

const GCircularSpinner();
const GLinearSpinner();
const GSpinnerDot(color: Colors.blue);
const GSpinnerWaveDot(size: 24, color: Colors.blue);

Use GWaveSpinner with explicit bounds:

const SizedBox(
  width: 48,
  height: 48,
  child: GWaveSpinner(color: GColors.primary),
);

GElevatedButton can show a spinner while work is running:

GElevatedButton(
  text: 'Save',
  isLoading: saving,
  onPressed: saving ? null : save,
);

Color Utilities #

Color extensions cover common UI operations:

const brand = Color(0xFFF57224);

final rgb = brand.toHexRGB(); // '#F57224'
final argb = brand.toHexARGB(); // '#FFF57224'
final textColor = brand.contrastText;
final hover = brand.lighten(0.08);
final pressed = brand.darken(0.12);
final muted = brand.desaturate(0.2);
final complementary = brand.complementary;
final materialSwatch = brand.toMaterialColor();

Parse colors from strings:

final fromFullHex = '#F57224'.toColor();
final fromShortHex = '#F50'.toColor();
final optionalColor = ColorService.tryParseHex('#80F57224');

Check contrast:

final passesAA = Colors.white.meetsWcagAA(GColors.primary);
final ratio = Colors.white.contrastRatio(GColors.primary);

Responsive Layout #

Resolve values from BoxConstraints:

LayoutBuilder(
  builder: (context, constraints) {
    final columns = constraints.resolve(
      mobile: 1,
      tablet: 2,
      desktop: 3,
      widescreen: 4,
    );

    return GridView.count(
      crossAxisCount: columns,
      children: const [],
    );
  },
);

Resolve values from BuildContext:

final padding = context.responsive(
  mobile: 16.0,
  tablet: 24.0,
  desktop: 32.0,
  widescreen: 40.0,
);

final isCompact = context.isMobile;
final size = context.screenSize;

Snackbars, Navigation, And Dialogs #

ContextExt gives short helpers for common app actions:

context.showSuccessSnackBar(message: 'Saved');
context.showErrorSnackBar(message: 'Unable to save');
context.unfocus();

final confirmed = await context.showConfirmDialog(
  title: 'Delete item?',
  message: 'This action cannot be undone.',
  destructive: true,
);

if (confirmed) {
  context.pop();
}

Icon Serialization #

Store Flutter IconData values as JSON strings:

final json = Icons.home.toJsonString();
final icon = IconDataExt.tryParse(json) ?? Icons.broken_image;

Use a fallback when parsing required values:

final icon = IconDataExt.parse(
  savedIconJson,
  fallback: Icons.help_outline,
);

Locale Helpers #

Convert between Locale and underscore-separated locale tags:

final tag = fromLocale(const Locale('en', 'US')); // 'en_US'
final locale = toLocale('km_KH'); // Locale('km', 'KH')

Error Handler Setup #

Call registerErrorHandlers() once in main() when you want Flutter framework errors forwarded through the package's handler setup:

void main() {
  registerErrorHandlers();
  runApp(const App());
}

Example App #

The package includes a Flutter showcase under example/.

cd example
flutter pub get
flutter run

The example demonstrates theme switching, color utilities, layout polish, and the package's UI components.

Package Relationship #

  • Use gmana for pure Dart extensions, functional helpers, and validators.
  • Use gmana_flutter for Flutter UI and app convenience APIs.
  • Use gmana_value_objects for typed domain values when that package is part of your project.
1
likes
160
points
344
downloads

Documentation

API reference

Publisher

verified publishergmana.co

Weekly Downloads

A comprehensive Flutter UI library providing curated widgets, form helpers, theme services, and extensions to accelerate and standardize development.

Repository (GitHub)
View/report issues

Topics

#flutter #ui #widget #form #utilities

License

BSD-3-Clause (license)

Dependencies

flutter, gmana

More

Packages that depend on gmana_flutter