gmana_flutter 0.0.8
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
gmanafor pure Dart extensions, functional helpers, and validators. - Use
gmana_flutterfor Flutter UI and app convenience APIs. - Use
gmana_value_objectsfor typed domain values when that package is part of your project.