use-fllib/SKILL.md
Use fl_lib stores, widgets, utils, and extensions in Flutter apps. Use when requests mention fl_lib APIs or integration.
npx skillsauth add lollipopkit/cc-skills use-fllibInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
./export_all.dart in the fl_lib root.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
Before running runApp, you must initialize the Paths utility:
void main() async {
// Initialize fl_lib Paths
await Paths.init();
runApp(MyApp());
}
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();
}
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 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.
The core interface for all stores. Key features include:
get<T>, set<T>, remove, clear, keys.StoreFromObj and StoreToObj.getAll() stream support.lastUpdateTs automatically (optional).A wrapper around SharedPreferences for storing simple key-value pairs (settings, flags, etc.).
Must be initialized before use, typically in main.dart.
await PrefStore.shared.init(prefix: 'my_app_');
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');
},
);
bool, double, int, String, List<String>.Map<String, dynamic> is automatically JSON encoded/decoded.fromObj and toObj converters.Uses flutter_secure_storage to store sensitive data (passwords, tokens).
Includes built-in JSON support extensions.
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),
);
SecureStoreProps.bakPwd: Backup password.SecureStoreProps.hivePwd: Encryption key for HiveStore (managed automatically).A NoSQL-like store using hive_ce (Community Edition).
Key Feature: Automatic encryption management via SecureStore.
final myStore = HiveStore('my_box');
await myStore.init(); // Handles encryption key generation/retrieval automatically
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']);
HiveStore checks SecureStore for an existing encryption key.SecureStore (under SecureStoreProps.hivePwd).fl_lib provides a rich collection of production-ready widgets, focusing on responsiveness, adaptability, and common UI patterns.
A powerful, responsive multi-column reorderable list that adapts to screen width.
useMasonry: true (default): Waterfall/Masonry layout (minimizes vertical gaps).useMasonry: false (or rowMajor: true): Aligned row-major grid (preserves order).animationDuration: Insert/Remove animations.dropAnimationDuration: Drag-and-drop settle animations.insertCurve / removeCurve: Customizable curves.draggingChildOpacity).AdaptiveReorderableList.separated constructor.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,
)
A high-level wrapper around TextField designed to reduce boilerplate.
CardX for consistent styling. Use noWrap: true to disable.obscureText: true, automatically adds a visibility toggle icon.PrefProps.imeSuggestions.AdaptiveTextSelectionToolbar by default.Input(
label: 'Password',
obscureText: true,
icon: Icons.lock,
onChanged: (val) => print(val),
// Validators/Error text
errorText: _errorMsg,
// Custom actions
onSubmitted: (val) => _submit(),
)
Standardized loading indicators to ensure consistency across the app.
SizedLoading.small: 25x25 (e.g., inside buttons)SizedLoading.medium: 45x45 (e.g., card loading)SizedLoading.large: 65x65 (e.g., page loading)// Custom size with padding
SizedLoading(30, padding: 5)
// Custom builder (e.g., linear)
SizedLoading(
100,
builder: SizedLoading.linearBuilder
)
Card widget with better defaults for the design system.src/view/widget/btn).flutter_markdown with custom styling.fl_lib provides a robust set of utility classes for ID generation, cryptography, and UI/System integration.
A lightweight, high-performance ID generator based on the Snowflake algorithm (timestamp + sequence).
// Generate
final id = SnowflakeLite.generate();
// Decode
final (timestamp, seq) = SnowflakeLite.decode(id)!;
Generates shorter, URL-friendly IDs based on timestamp and randomness.
final shortId = ShortId.generate();
A secure encryption utility class designed for sensitive data storage.
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();
Helper for dynamic font loading.
// Load font from a local file path
await FontUtils.loadFrom('/path/to/font.ttf');
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 provides a comprehensive set of Dart extensions to reduce boilerplate and enhance developer productivity.
Found in src/core/ext/ctx/common.dart and dialog.dart.
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
Using responsive_framework:
context.responsiveBreakpoints; // Raw data
context.isMobile; // Phone or Mobile breakpoint
context.isDesktop; // Desktop or Tablet breakpoint
// 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,
);
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: ...)
Found in src/core/ext/string.dart.
'hello'.capitalize; // "Hello"
'#FF0000'.fromColorHex; // Color(0xFFFF0000)
'https://example.com'.isUrl;
'https://example.com'.launchUrl();
'/path/to'.joinPath('file.txt');
'/path/to/file.txt'.getFileName(); // "file.txt"
'/path/to/file.txt'.getFileName(withoutExtension: true); // "file"
'2023-01-01'.parseDateTime();
'1672531200000'.parseTimestamp();
'https://img.com/a.png'.imageProvider; // Handles Network, Asset, and File automatically
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
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
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
development
Clean Codex local history artifacts that can contain logs, prompts, user input text, command traces, and session transcripts while preserving memories and configuration. Use when the user asks to delete, purge, wipe, prune, reset, or preview Codex history/log/session/input records, especially `~/.codex/history.jsonl`, `~/.codex/sessions/`, `~/.codex/log/`, `~/.codex/logs_*.sqlite`, or shell snapshots, and explicitly not memories.
development
TrailBase project guide for installing and running the single-executable backend, configuring traildepot/config.textproto and migrations, exposing Record APIs, using auth and token flows, integrating first-party SDKs for TypeScript/JavaScript, Dart/Flutter, Rust, C#/.NET, Swift, Kotlin, Go, and Python, calling HTTP APIs directly, implementing WASM custom endpoints, and locating relevant source/docs in the trailbase repository. Use when Codex needs to answer or implement TrailBase setup, SDK, REST/HTTP API, auth, realtime, configuration, migration, deployment, or custom endpoint work.
development
Maintain an evolving linked documentation library for project wikis, ADRs, design notes, research notes, release notes, and decision logs. Use when asked to create, grow, repair, reorganize, or verify a wiki/ADR knowledge base with Markdown pages, YAML frontmatter, Obsidian-style [[wikilinks]], source-backed citations, llmwiki/llm-wiki-compiler projects, or a durable project memory that should compound over time instead of being rewritten from scratch.
testing
Create concise, evidence-based handoff notes for another AI coding agent. Use when the user asks for a handoff, continuity note, next-agent summary, progress transfer, "告诉别的 agent", "handoff skill", "交接", or wants the current state, completed work, remaining plan items, risks, and next steps captured for another agent without writing a verbose work log.