| name | use-fllib |
| description | Use fl_lib stores, widgets, utils, and extensions in Flutter apps. Use when requests mention fl_lib APIs or integration. |
Use fl_lib
When to use
- Use when the user asks about fl_lib setup, localization, or Paths init.
- Use when requests mention PrefStore, SecureStore, HiveStore, AdaptiveReorderableList, Input, SizedLoading, or fl_lib extensions/utils.
Instructions
- Setup: Follow the fl_lib Setup & Usage section below for dependency, Paths init, and localization wiring.
- Stores: Use the right store for the data type; see the fl_lib Stores section below. Prefer PrefStore for settings, SecureStore for secrets, HiveStore for structured caching.
- Widgets: Prefer fl_lib widgets for common UI patterns; see the fl_lib Widgets section below.
- Utils & extensions: Use provided helpers for IDs, crypto, UI/system, and convenience APIs; see the fl_lib Utils and fl_lib Extensions sections below.
- Library changes: If modifying fl_lib itself, run
./export_all.dartin the fl_lib root.
Requirements
fl_lib usage
- Foundation: Use fl_lib as the common library when it is already part of the project.
- Storage: Use PrefStore for key-value settings and SecureStore for sensitive data; use HiveStore for local structured caching.
fl_lib Setup & Usage
Installation
Add the dependency to your pubspec.yaml pointing to the GitHub repository:
dependencies:
fl_lib:
git:
url: https://github.com/lppcg/fl_lib.git
ref: main
Initialization
Before running runApp, you must initialize the Paths utility:
void main() async {
// Initialize fl_lib Paths
await Paths.init();
runApp(MyApp());
}
Localization
Configure localizationsDelegates in your MaterialApp to include LibLocalizations.delegate. This ensures fl_lib's internal widgets and utilities are properly localized.
MaterialApp(
localizationsDelegates: const [
LibLocalizations.delegate,
...AppLocalizations.localizationsDelegates,
],
supportedLocales: AppLocalizations.supportedLocales,
)
In your main app widget (e.g., in didChangeDependencies), call context.setLibL10n() only in root Widget to synchronize localization settings:
@override
void didChangeDependencies() {
super.didChangeDependencies();
context.setLibL10n();
}
Maintenance
If you are modifying fl_lib itself (e.g., adding new files), remember to run the ./export_all.dart script in the fl_lib root to update exports.
fl_lib Stores
fl_lib provides three types of stores for different persistence needs: PrefStore, SecureStore, and HiveStore.
All stores implement the Store interface, providing a unified API for data access.
Store Interface
The core interface for all stores. Key features include:
- Unified API:
get<T>,set<T>,remove,clear,keys. - Type Safety: Automatic conversion support via
StoreFromObjandStoreToObj. - Reactive:
getAll()stream support. - Metadata: Tracks
lastUpdateTsautomatically (optional).
PrefStore
A wrapper around SharedPreferences for storing simple key-value pairs (settings, flags, etc.).
Initialization
Must be initialized before use, typically in main.dart.
await PrefStore.shared.init(prefix: 'my_app_');
Usage
Define properties using PrefProp or PrefPropDefault for type safety.
Recommended pattern: Define all prefs in a static class or extension.
// Define properties
abstract class Prefs {
// Simple property, nullable
static const userToken = PrefProp<String>('user_token');
// Property with default value, non-nullable
static const isDarkMode = PrefPropDefault<bool>('is_dark_mode', false);
// Custom object with JSON serialization
static final userProfile = PrefProp<UserProfile>(
'user_profile',
fromObj: (json) => UserProfile.fromJson(json),
toObj: (obj) => obj.toJson(),
);
}
// Read
final isDark = Prefs.isDarkMode.get(); // Returns bool
final token = Prefs.userToken.get(); // Returns String?
// Write
await Prefs.isDarkMode.set(true);
await Prefs.userToken.set('xyz-123');
// Listen (Reactive)
return ValueListenableBuilder(
valueListenable: Prefs.isDarkMode.listenable(),
builder: (context, value, child) {
return Text('Dark Mode: $value');
},
);
Supported Types
- Native:
bool,double,int,String,List<String>. - JSON:
Map<String, dynamic>is automatically JSON encoded/decoded. - Custom: Use
fromObjandtoObjconverters.
SecureStore
Uses flutter_secure_storage to store sensitive data (passwords, tokens).
Includes built-in JSON support extensions.
Usage
Access via SecureStore static methods or SecureProp.
// Define secure property
static const apiToken = SecureProp('api_token');
// Read/Write
await apiToken.write('secret_token');
final token = await apiToken.read();
// Direct usage with JSON extensions
await SecureStore.storage.writeJson(
'user_creds',
credsObj,
(c) => c.toJson(),
);
final creds = await SecureStore.storage.readJson(
'user_creds',
(json) => Credentials.fromJson(json),
);
Built-in Props
SecureStoreProps.bakPwd: Backup password.SecureStoreProps.hivePwd: Encryption key for HiveStore (managed automatically).
HiveStore
A NoSQL-like store using hive_ce (Community Edition).
Key Feature: Automatic encryption management via SecureStore.
Initialization
final myStore = HiveStore('my_box');
await myStore.init(); // Handles encryption key generation/retrieval automatically
Usage
Use HiveProp or HivePropDefault.
final cacheProp = myStore.propertyDefault<int>('cache_count', 0);
// Read/Write
cacheProp.put(42);
final count = cacheProp.fetch(); // or .get()
// List Property
final logs = myStore.listProperty<String>('logs');
logs.put(['log1', 'log2']);
Encryption Logic
HiveStorechecksSecureStorefor an existing encryption key.- If missing, generates a new secure key.
- Saves the key to
SecureStore(underSecureStoreProps.hivePwd). - Opens the Hive box using this key.
- Auto-migrates from unencrypted to encrypted if an old unencrypted box exists.
fl_lib Widgets
fl_lib provides a rich collection of production-ready widgets, focusing on responsiveness, adaptability, and common UI patterns.
AdaptiveReorderableList
A powerful, responsive multi-column reorderable list that adapts to screen width.
Features
- Responsive Layout: Automatically calculates column count based on available width.
- Dual Layout Modes:
useMasonry: true(default): Waterfall/Masonry layout (minimizes vertical gaps).useMasonry: false(orrowMajor: true): Aligned row-major grid (preserves order).
- Animations:
animationDuration: Insert/Remove animations.dropAnimationDuration: Drag-and-drop settle animations.insertCurve/removeCurve: Customizable curves.
- Drag & Drop: Long-press to drag. Includes feedback opacity (
draggingChildOpacity). - Separators: Supports
AdaptiveReorderableList.separatedconstructor.
Usage
AdaptiveReorderableList.builder<String>(
items: myItems,
itemKey: (item) => item.id,
itemBuilder: (context, item, index, animation) {
return SizeTransition(
sizeFactor: animation,
child: MyCard(item),
);
},
onReorderComplete: (newItems) {
setState(() => myItems = newItems);
},
// Optional customizations
maxColumns: 4,
columnWidth: 300,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
)
Input
A high-level wrapper around TextField designed to reduce boilerplate.
Key Features
- Auto-Card Wrapping: By default, wraps input in a
CardXfor consistent styling. UsenoWrap: trueto disable. - Password Toggle: If
obscureText: true, automatically adds a visibility toggle icon. - Reactive IME: Respects global IME suggestions setting via
PrefProps.imeSuggestions. - Context Menu: Uses
AdaptiveTextSelectionToolbarby default.
Usage
Input(
label: 'Password',
obscureText: true,
icon: Icons.lock,
onChanged: (val) => print(val),
// Validators/Error text
errorText: _errorMsg,
// Custom actions
onSubmitted: (val) => _submit(),
)
SizedLoading
Standardized loading indicators to ensure consistency across the app.
Predefined Sizes
SizedLoading.small: 25x25 (e.g., inside buttons)SizedLoading.medium: 45x45 (e.g., card loading)SizedLoading.large: 65x65 (e.g., page loading)
Custom Usage
// Custom size with padding
SizedLoading(30, padding: 5)
// Custom builder (e.g., linear)
SizedLoading(
100,
builder: SizedLoading.linearBuilder
)
Other Notable Widgets
Layout & Containers
- AdaptiveList: Similar to reorderable list but static.
- CardX: An extended
Cardwidget with better defaults for the design system. - Split: A split-view widget for resizable panes.
- VirtualWindowFrame: For desktop apps, handles custom window frame rendering.
Interactive
- Btn: Standardized buttons (implementations in
src/view/widget/btn). - Choice: Chip-like selection widgets.
- ColorPicker: A simple color selection widget.
- SlideTrans: Slide transition wrapper.
Content
- Markdown: Wrapper for
flutter_markdownwith custom styling. - Tag: Tag/Badge component.
- Turnstile: Cloudflare Turnstile integration widget.
fl_lib Utils
fl_lib provides a robust set of utility classes for ID generation, cryptography, and UI/System integration.
ID Generation
SnowflakeLite
A lightweight, high-performance ID generator based on the Snowflake algorithm (timestamp + sequence).
- Structure: 66 bits (54 bit timestamp + 12 bit sequence).
- Format: Radix-36 string (alphanumeric).
- Use Case: Primary keys, sortable unique IDs.
// Generate
final id = SnowflakeLite.generate();
// Decode
final (timestamp, seq) = SnowflakeLite.decode(id)!;
ShortId
Generates shorter, URL-friendly IDs based on timestamp and randomness.
- Format: Custom base64-like string (a-Z, 0-9, -, +).
- Use Case: Public facing IDs, shareable links.
final shortId = ShortId.generate();
Cryptography
Cryptor
A secure encryption utility class designed for sensitive data storage.
- Algorithm: AES-GCM (Authenticated Encryption).
- Key Derivation: PBKDF2 (SHA-256, 100k iterations).
- Structure:
Header+Salt+Nonce+Ciphertext+AuthTag.
// Encrypt
final encrypted = Cryptor.encrypt('my_secret_data', 'my_password');
// Decrypt
final decrypted = Cryptor.decrypt(encrypted, 'my_password');
// Verification
final isEnc = Cryptor.isEncrypted(someString);
// Test Helper
final randPwd = Cryptor.generatePassword();
UI & System Utils
FontUtils
Helper for dynamic font loading.
// Load font from a local file path
await FontUtils.loadFrom('/path/to/font.ttf');
SystemUIs
Manages system UI overlays and window configurations for different platforms.
// Android: Transparent Navigation Bar (Edge-to-Edge)
SystemUIs.setTransparentNavigationBar(context);
// Toggle Status Bar
SystemUIs.switchStatusBar(hide: true); // Immersive Sticky
SystemUIs.switchStatusBar(hide: false); // Edge-to-Edge
// Desktop: Window Initialization
await SystemUIs.initDesktopWindow(
hideTitleBar: true,
size: Size(800, 600),
position: Offset.zero,
);
fl_lib Extensions
fl_lib provides a comprehensive set of Dart extensions to reduce boilerplate and enhance developer productivity.
BuildContext Extensions
Found in src/core/ext/ctx/common.dart and dialog.dart.
Navigation & Theme
context.pop(); // Safer Navigator.pop
context.canPop; // Check if can pop
context.theme; // Theme.of(context)
context.isDark; // Check brightness
context.mediaQuery; // MediaQuery.of(context)
context.windowSize; // MediaQuery.sizeOf(context) (Optimized)
context.libL10n; // Access library localization
Responsive Design
Using responsive_framework:
context.responsiveBreakpoints; // Raw data
context.isMobile; // Phone or Mobile breakpoint
context.isDesktop; // Desktop or Tablet breakpoint
Dialogs & Overlays
// Show a consistent rounded dialog
await context.showRoundDialog(
title: 'Hello',
child: Text('Content'),
actions: [TextButton(child: Text('OK'))], // Or use Btnx.cancelOks
);
// Show loading dialog with async task
await context.showLoadingDialog(
fn: () async => await doSomething(),
);
// Show password input dialog
final pwd = await context.showPwdDialog(title: 'Enter Password');
// Show pickers
final selected = await context.showPickDialog(
items: ['A', 'B', 'C'],
multi: true,
);
Widget Extensions
Found in src/core/ext/widget.dart. Use these for cleaner UI code.
Text('Hello')
.center() // Center(child: ...)
.paddingAll(8) // Padding(padding: EdgeInsets.all(8), child: ...)
.paddingSymmetric(horizontal: 16)
.expanded(flex: 2) // Expanded(flex: 2, child: ...)
.tap(onTap: () => print('tapped')); // InkWell wrapper with throttle
// Sliver conversion
Container().sliver(); // SliverToBoxAdapter(child: ...)
String Extensions
Found in src/core/ext/string.dart.
Manipulation & Validation
'hello'.capitalize; // "Hello"
'#FF0000'.fromColorHex; // Color(0xFFFF0000)
'https://example.com'.isUrl;
'https://example.com'.launchUrl();
Path & File
'/path/to'.joinPath('file.txt');
'/path/to/file.txt'.getFileName(); // "file.txt"
'/path/to/file.txt'.getFileName(withoutExtension: true); // "file"
DateTime Parsing
'2023-01-01'.parseDateTime();
'1672531200000'.parseTimestamp();
Image Provider
'https://img.com/a.png'.imageProvider; // Handles Network, Asset, and File automatically
Collection Extensions
Found in src/core/ext/iter.dart.
// List
[1, 2, 3].joinWith(0); // [1, 0, 2, 0, 3]
// Iterable Null Safety
list.firstOrNull;
list.firstWhereOrNull((e) => e > 5);
list.nullOrEmpty; // Checks if null or empty
DateTime Extensions
Found in src/core/ext/datetime.dart.
final now = DateTime.now();
now.hourMinute; // "14:30"
now.ymd(); // "2023-05-20"
now.hms(); // "14:30:45"
now.simple(); // Smart format: "14:30", "Yesterday 14:30", or "5-20"
DateTimeX.timestamp; // Current millis
Riverpod & State Extensions
Found in src/core/ext/ctx/common.dart.
// In ConsumerState
refSafe; // Returns ref only if mounted
contextSafe; // Returns context only if mounted
setStateSafe(() {}); // setState only if mounted
Example prompts
- "Wire fl_lib localization and Paths init in main.dart"
- "Store auth tokens using SecureStore and preferences using PrefStore"
- "Build a responsive grid with AdaptiveReorderableList"
- "Use fl_lib context extensions to show a loading dialog"
- "Generate IDs with SnowflakeLite and ShortId"