htlib 0.1.0
htlib: ^0.1.0 copied to clipboard
A versatile and lightweight Flutter toolkit for state management, shell routing, dependency injection, responsive UI, MVVM, and form validation to speed up development.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:htlib/htlib.dart';
// 1. Dependency Injection Setup
final injection = Injection();
class ApiService {
String greet() => 'Hello from ApiService!';
}
void setupDependencies() {
injection.addSingleton<ApiService>(() => ApiService());
}
// 2. State Management Setup
final counter = Observable(0);
final greeting =
Computed(() => '${injection<ApiService>().greet()} Count: $counter');
void main() {
// Setup dependencies before running the app
setupDependencies();
// Set the global app name for the page title
PageTitle.appName = 'htlib Example';
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// 3. Router Setup
final router = ShellRouter(
// The main shell of the app
container: (context) => const AppShell(),
routes: [
ShellRoute(
path: 'home',
builder: (context, params) => const HomePage(),
),
ShellRoute(
path: 'responsive',
builder: (context, params) => const ResponsiveDemoPage(),
),
],
// Redirect root path to /home
redirect: (uri) {
if (uri.path == '/') return '/home';
return null;
},
);
return MaterialApp.router(
title: 'htlib Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
routerConfig: router,
);
}
}
/// The main app shell with BottomNavigationBar
class AppShell extends StatelessWidget {
const AppShell({super.key});
@override
Widget build(BuildContext context) {
// Get the current location to set the active tab
final location = ShellRouter.locationOf(context);
final router = Router.of(context).routerDelegate as ShellRouter;
int currentIndex = 0;
if (location.startsWith('/responsive')) {
currentIndex = 1;
}
return Scaffold(
body: const ShellOutlet(), // Renders the matched child route
bottomNavigationBar: BottomNavigationBar(
currentIndex: currentIndex,
onTap: (index) {
if (index == 0) router.navigate(Uri.parse('/home'));
if (index == 1) router.navigate(Uri.parse('/responsive'));
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(Icons.important_devices), label: 'Responsive'),
],
),
);
}
}
/// Home page demonstrating state management and page title
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return PageTitle(
title: 'Home',
child: Scaffold(
appBar: AppBar(title: const Text('State Management')),
body: Center(
// 4. Observer rebuilds when 'greeting' computed value changes
child: Observer(
builder: (_) => Text(
greeting.value,
style: Theme.of(context).textTheme.headlineSmall,
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => counter.value++,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
/// Page demonstrating the ResponsiveGrid
class ResponsiveDemoPage extends StatelessWidget {
const ResponsiveDemoPage({super.key});
@override
Widget build(BuildContext context) {
return PageTitle(
title: 'Responsive Demo',
child: Scaffold(
appBar: AppBar(title: const Text('Responsive Grid')),
// 5. Responsive Grid Layout
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: ResponsiveGrid(
columnSpacing: 16,
rowSpacing: 16,
children: List.generate(
6,
(index) => ResponsiveItem.span(
mobile: 12,
tablet: 6,
desktop: 4,
child: Card(
child: Center(
child: Text('Item ${index + 1}',
style: const TextStyle(fontSize: 24))))),
),
),
),
),
);
}
}