moai-lang-flutter
Über
Diese Claude-Spezialisierung konzentriert sich auf die Entwicklung mit Flutter 3.24+ und Dart 3.5+, mit Schwerpunkt auf modernem State Management mit Riverpod und deklarativer Navigation mittels go_router. Sie ist für den Bau plattformübergreifender Anwendungen für Mobilgeräte, Desktop und Web konzipiert. Nutzen Sie diese Spezialisierung für Anleitungen zu adaptiven Layouts, den neuesten Sprachfunktionen von Dart und zur Integration plattformspezifischer Funktionalitäten.
Schnellinstallation
Claude Code
Empfohlennpx skills add modu-ai/moai-adk/plugin add https://github.com/modu-ai/moai-adkgit clone https://github.com/modu-ai/moai-adk.git ~/.claude/skills/moai-lang-flutterKopieren Sie diesen Befehl und fügen Sie ihn in Claude Code ein, um diese Fähigkeit zu installieren
Dokumentation
Quick Reference (30 seconds)
Flutter/Dart Development Expert - Dart 3.5+, Flutter 3.24+ with modern patterns.
Auto-Triggers: Flutter projects (.dart files, pubspec.yaml), cross-platform apps, widget development
Core Capabilities:
- Dart 3.5: Patterns, records, sealed classes, extension types
- Flutter 3.24: Widget tree, Material 3, adaptive layouts
- Riverpod: State management with code generation
- go_router: Declarative navigation and deep linking
- Platform Channels: Native iOS/Android integration
- Testing: flutter_test, widget_test, integration_test
Implementation Guide (5 minutes)
Dart 3.5 Language Features
Pattern Matching with Sealed Classes:
sealed class Result<T> {
const Result();
}
class Success<T> extends Result<T> {
final T data;
const Success(this.data);
}
class Failure<T> extends Result<T> {
final String error;
const Failure(this.error);
}
// Exhaustive switch expression
String handleResult(Result<User> result) => switch (result) {
Success(:final data) => 'User: ${data.name}',
Failure(:final error) => 'Error: $error',
};
// Guard clauses in patterns
String describeUser(User user) => switch (user) {
User(age: var a) when a < 18 => 'Minor',
User(age: var a) when a >= 65 => 'Senior',
User(name: var n, age: var a) => '$n, age $a',
};
Records and Destructuring:
typedef UserRecord = ({String name, int age, String email});
// Multiple return values
(String name, int age) parseUser(Map<String, dynamic> json) {
return (json['name'] as String, json['age'] as int);
}
// Destructuring
void processUser(Map<String, dynamic> json) {
final (name, age) = parseUser(json);
print('$name is $age years old');
}
// Record patterns in collections
void processUsers(List<UserRecord> users) {
for (final (:name, :age, :email) in users) {
print('$name ($age): $email');
}
}
Extension Types:
extension type UserId(String value) {
factory UserId.generate() => UserId(Uuid().v4());
bool get isValid => value.isNotEmpty;
}
extension type Email(String value) {
bool get isValid => value.contains('@') && value.contains('.');
String get domain => value.split('@').last;
}
Riverpod State Management
Provider Definitions:
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'providers.g.dart';
@riverpod
UserRepository userRepository(Ref ref) {
return UserRepository(ref.read(dioProvider));
}
@riverpod
Future<User> user(Ref ref, String userId) async {
return ref.watch(userRepositoryProvider).getUser(userId);
}
@riverpod
class UserNotifier extends _$UserNotifier {
@override
FutureOr<User?> build() => null;
Future<void> loadUser(String id) async {
state = const AsyncLoading();
state = await AsyncValue.guard(
() => ref.read(userRepositoryProvider).getUser(id),
);
}
Future<void> updateUser(User user) async {
state = const AsyncLoading();
state = await AsyncValue.guard(
() => ref.read(userRepositoryProvider).updateUser(user),
);
}
}
@riverpod
Stream<List<Message>> messages(Ref ref, String chatId) {
return ref.watch(chatRepositoryProvider).watchMessages(chatId);
}
Widget Integration:
class UserScreen extends ConsumerWidget {
final String userId;
const UserScreen({required this.userId, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userProvider(userId));
return Scaffold(
appBar: AppBar(title: const Text('User Profile')),
body: userAsync.when(
data: (user) => UserProfile(user: user),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Error: $error'),
ElevatedButton(
onPressed: () => ref.invalidate(userProvider(userId)),
child: const Text('Retry'),
),
],
),
),
),
);
}
}
StatefulWidget with Riverpod:
class EditUserScreen extends ConsumerStatefulWidget {
const EditUserScreen({super.key});
@override
ConsumerState<EditUserScreen> createState() => _EditUserScreenState();
}
class _EditUserScreenState extends ConsumerState<EditUserScreen> {
final _formKey = GlobalKey<FormState>();
late TextEditingController _nameController;
@override
void initState() {
super.initState();
_nameController = TextEditingController();
}
@override
void dispose() {
_nameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
ref.listen(userNotifierProvider, (prev, next) {
next.whenOrNull(
error: (e, _) => ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
),
);
});
final isLoading = ref.watch(userNotifierProvider).isLoading;
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _nameController,
validator: (v) => v?.isEmpty ?? true ? 'Required' : null,
),
ElevatedButton(
onPressed: isLoading ? null : () async {
if (_formKey.currentState!.validate()) {
await ref.read(userNotifierProvider.notifier)
.updateUser(User(name: _nameController.text));
}
},
child: isLoading
? const CircularProgressIndicator()
: const Text('Save'),
),
],
),
);
}
}
go_router Navigation
Router Configuration:
final router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
name: 'home',
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'user/:id',
name: 'user-detail',
builder: (context, state) => UserDetailScreen(
userId: state.pathParameters['id']!,
),
),
],
),
ShellRoute(
builder: (context, state, child) => MainShell(child: child),
routes: [
GoRoute(
path: '/feed',
pageBuilder: (_, __) => const NoTransitionPage(child: FeedScreen()),
),
GoRoute(
path: '/search',
pageBuilder: (_, __) => const NoTransitionPage(child: SearchScreen()),
),
GoRoute(
path: '/profile',
pageBuilder: (_, __) => const NoTransitionPage(child: ProfileScreen()),
),
],
),
],
redirect: (context, state) {
final isLoggedIn = authNotifier.isLoggedIn;
final isLoggingIn = state.matchedLocation == '/login';
if (!isLoggedIn && !isLoggingIn) return '/login';
if (isLoggedIn && isLoggingIn) return '/';
return null;
},
errorBuilder: (context, state) => ErrorScreen(error: state.error),
);
// Navigation methods
void navigateToUser(BuildContext context, String userId) {
context.go('/user/$userId');
}
void goBack(BuildContext context) {
if (context.canPop()) context.pop();
else context.go('/');
}
Platform Channels
Dart Implementation:
class NativeBridge {
static const _channel = MethodChannel('com.example.app/native');
static const _eventChannel = EventChannel('com.example.app/events');
Future<String> getPlatformVersion() async {
try {
final version = await _channel.invokeMethod<String>('getPlatformVersion');
return version ?? 'Unknown';
} on PlatformException catch (e) {
throw NativeBridgeException('Failed: ${e.message}');
}
}
Future<void> shareContent({required String text, String? title}) async {
await _channel.invokeMethod('share', {
'text': text,
if (title != null) 'title': title,
});
}
Stream<BatteryState> watchBatteryState() {
return _eventChannel.receiveBroadcastStream().map((event) {
final data = event as Map<dynamic, dynamic>;
return BatteryState(
level: data['level'] as int,
isCharging: data['isCharging'] as bool,
);
});
}
void setupMethodCallHandler() {
_channel.setMethodCallHandler((call) async {
switch (call.method) {
case 'onNativeEvent':
// Handle native event
return true;
default:
throw MissingPluginException('Not implemented: ${call.method}');
}
});
}
}
class BatteryState {
final int level;
final bool isCharging;
const BatteryState({required this.level, required this.isCharging});
}
Widget Patterns
Adaptive Layouts:
class AdaptiveScaffold extends StatelessWidget {
final Widget child;
final List<NavigationDestination> destinations;
final int selectedIndex;
final ValueChanged<int> onDestinationSelected;
const AdaptiveScaffold({
required this.child,
required this.destinations,
required this.selectedIndex,
required this.onDestinationSelected,
super.key,
});
@override
Widget build(BuildContext context) {
final width = MediaQuery.sizeOf(context).width;
if (width < 600) {
return Scaffold(
body: child,
bottomNavigationBar: NavigationBar(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
destinations: destinations,
),
);
}
if (width < 840) {
return Scaffold(
body: Row(children: [
NavigationRail(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
destinations: destinations.map((d) => NavigationRailDestination(
icon: d.icon, selectedIcon: d.selectedIcon, label: Text(d.label),
)).toList(),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(child: child),
]),
);
}
return Scaffold(
body: Row(children: [
NavigationDrawer(
selectedIndex: selectedIndex,
onDestinationSelected: onDestinationSelected,
children: destinations.map((d) => NavigationDrawerDestination(
icon: d.icon, selectedIcon: d.selectedIcon ?? d.icon, label: Text(d.label),
)).toList(),
),
const VerticalDivider(thickness: 1, width: 1),
Expanded(child: child),
]),
);
}
}
Testing
Widget Test Example:
void main() {
testWidgets('UserScreen displays data', (tester) async {
final container = ProviderContainer(overrides: [
userRepositoryProvider.overrideWithValue(MockUserRepository()),
]);
await tester.pumpWidget(
UncontrolledProviderScope(
container: container,
child: const MaterialApp(home: UserScreen(userId: '1')),
),
);
expect(find.byType(CircularProgressIndicator), findsOneWidget);
await tester.pumpAndSettle();
expect(find.text('Test User'), findsOneWidget);
});
}
For comprehensive testing patterns, see examples.md.
Advanced Patterns
For comprehensive coverage including:
- Clean Architecture with Riverpod
- Isolates for compute-heavy operations
- Custom render objects and painting
- FFI and platform-specific plugins
- Performance optimization and profiling
See: reference.md and examples.md
Context7 Library Mappings
Flutter/Dart Core:
/flutter/flutter- Flutter framework/dart-lang/sdk- Dart SDK
State Management:
/rrousselGit/riverpod- Riverpod state management/felangel/bloc- BLoC pattern
Navigation and Storage:
/flutter/packages- go_router and official packages/cfug/dio- HTTP client/isar/isar- NoSQL database
Works Well With
moai-lang-swift- iOS native integration for platform channelsmoai-lang-kotlin- Android native integration for platform channelsmoai-domain-backend- API integration and backend communicationmoai-quality-security- Mobile security best practicesmoai-essentials-debug- Flutter debugging and DevTools
Version: 1.0.0 Last Updated: 2025-12-07 Status: Production Ready
GitHub Repository
Verwandte Skills
mobile-testing
AndereThis Claude Skill provides comprehensive mobile testing for iOS and Android applications, covering gestures, sensors, permissions, and device fragmentation. Use it when testing native, hybrid, or mobile web apps to ensure quality across 1000+ device variants. It helps define device coverage matrices and test key platform differences.
moai-domain-mobile-app
TestenThis Claude Skill provides enterprise mobile development expertise for React Native 0.76+, Flutter 3.24+, and Capacitor 6.x cross-platform frameworks. It focuses on implementing robust patterns, comprehensive testing, and CI/CD automation for production-ready mobile applications. Use this skill for guidance on mobile architecture, performance optimization, and deployment strategies.
rust-desktop-applications
EntwicklungThis skill helps developers build cross-platform desktop applications using Rust, primarily through the Tauri framework or native GUI alternatives. It's ideal for creating performant apps requiring system integration, small bundle sizes, and high performance. The guidance covers project setup, IPC, state management, and cross-platform testing and deployment.
moai-domain-mobile-app
TestenThis Claude Skill provides enterprise mobile development expertise for React Native 0.76+, Flutter 3.24+, and Capacitor 6.x frameworks. It focuses on cross-platform patterns, testing strategies, and CI/CD automation for production-ready applications. Use this skill for guidance on modern mobile development workflows and deployment best practices.
