From cc-mobile-flutter
Dart 3 idioms and conventions for this project — null safety, sealed classes and pattern matching, records, async cleanup, equality via freezed, and when to use each keyword. Load whenever writing or reviewing Dart.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cc-mobile-flutter:dart-styleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Opinionated defaults for this codebase. These complement the analyzer rules, not replace them.
Opinionated defaults for this codebase. These complement the analyzer rules, not replace them.
snake_case.dart. One public type per file is the default.UpperCamelCase. Variables & functions: lowerCamelCase. Constants: lowerCamelCase (Dart doesn't use SCREAMING_CASE)._ (Dart's only access modifier).Dto suffix on wire types; entities use the plain noun (User, not UserEntity).final everywhere you can. const on constructors whenever values allow.freezed — it generates ==, hashCode, copyWith, toString, and pattern-match-friendly unions.const [] / const {} — avoid null for "empty".== by hand. Either use freezed, or — for pure value types that don't need unions — a record.Equatable is legacy here. If you see it, it predates freezed adoption.required on all non-defaulted named parameters.! is a smell. Use switch with a null pattern, or if (x case final value?), or x ?? fallback. One ! per small function is okay; two is a code review comment.late is only for lazy init where non-null is guaranteed by construction (e.g., late final controller = TextEditingController();).sealed class LoadResult<T> {}
final class LoadInitial<T> extends LoadResult<T> { const LoadInitial(); }
final class LoadSuccess<T> extends LoadResult<T> { const LoadSuccess(this.value); final T value; }
final class LoadError<T> extends LoadResult<T> { const LoadError(this.failure); final Failure failure; }
String describe(LoadResult<User> r) => switch (r) {
LoadInitial() => 'idle',
LoadSuccess(:final value) => 'got ${value.name}',
LoadError(:final failure) => 'error: ${failure.message}',
};
switch on sealed types is exhaustive — no default: needed. Add one only when you want a catch-all.:final value) to avoid intermediate variables.({String id, int count}). Don't let them leak across layers — prefer a named type.factory OrderId.parse(String raw).Future<T> or Stream<T>. No Completer unless bridging from a callback API.unawaited(foo()) when you deliberately fire-and-forget. Analysis flags bare foo();.BuildContext across await:
await repo.submit(...);
if (!context.mounted) return;
context.go(const NextRoute().location);
close() / dispose(). Close sinks. Analysis enforces it.catch without typing, at least on DioException / on SomeException.Failure, return Left.Either flow.rethrow cancellation: if (e is DioException && e.type == DioExceptionType.cancel) return Left(const CancelledFailure());.Dart doesn't have Kotlin's scope functions. The usual replacements:
| Kotlin | Dart |
|---|---|
let { ... } on nullable | if (x case final v?) { ... } |
apply { ... } | cascade .. |
also { ... } | just use the variable |
run { ... } | IIFE (() { ... })() (rare) |
with(x) { ... } | extension methods |
Cascades are idiomatic:
final query = SelectQuery(table)
..where((t) => t.userId.equals(id))
..orderBy([(t) => OrderingTerm.asc(t.createdAt)])
..limit(20);
List.of, Map.of for shallow copies. .unmodifiable when you hand out references.Iterable.whereType<T>() over .where((x) => x is T).cast<T>().first / last without a fallback — use firstOrNull.(String, int) for a parse result.final (name, age) = parseLine(input);.enum Flavor {
dev(apiBaseUrl: 'https://dev.example.com'),
prod(apiBaseUrl: 'https://api.example.com');
const Flavor({required this.apiBaseUrl});
final String apiBaseUrl;
}
sealed class + freezed.print. Use the injected ILogger.new keyword (redundant).var in production code. final for locals, explicit types on fields and public APIs.dynamic unless you're reaching into JSON you haven't typed yet. Type it and move on.npx claudepluginhub dimitriremoiville/cc-mobile --plugin cc-mobile-flutterProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.