feat: add flutter-dev skill
Add comprehensive Flutter cross-platform development guide covering: - Widget patterns and const optimization - Riverpod/Bloc state management - GoRouter navigation - Performance optimization - Testing strategies - Platform-specific implementations Made-with: Cursor
This commit is contained in:
274
skills/flutter-dev/references/project-structure.md
Normal file
274
skills/flutter-dev/references/project-structure.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# Project Structure
|
||||
|
||||
Flutter project architecture guide covering feature-based structure, dependencies, and entry point setup.
|
||||
|
||||
## Feature-Based Structure
|
||||
|
||||
```
|
||||
lib/
|
||||
├── main.dart # Entry point
|
||||
├── app.dart # App widget, MaterialApp.router
|
||||
├── core/
|
||||
│ ├── constants/
|
||||
│ │ ├── app_colors.dart
|
||||
│ │ ├── app_strings.dart
|
||||
│ │ └── app_sizes.dart
|
||||
│ ├── theme/
|
||||
│ │ ├── app_theme.dart
|
||||
│ │ └── text_styles.dart
|
||||
│ ├── utils/
|
||||
│ │ ├── extensions.dart
|
||||
│ │ └── validators.dart
|
||||
│ └── errors/
|
||||
│ └── failures.dart
|
||||
├── features/
|
||||
│ ├── auth/
|
||||
│ │ ├── data/
|
||||
│ │ │ ├── repositories/
|
||||
│ │ │ │ └── auth_repository_impl.dart
|
||||
│ │ │ └── datasources/
|
||||
│ │ │ ├── auth_remote_datasource.dart
|
||||
│ │ │ └── auth_local_datasource.dart
|
||||
│ │ ├── domain/
|
||||
│ │ │ ├── entities/
|
||||
│ │ │ │ └── user.dart
|
||||
│ │ │ ├── repositories/
|
||||
│ │ │ │ └── auth_repository.dart
|
||||
│ │ │ └── usecases/
|
||||
│ │ │ ├── login.dart
|
||||
│ │ │ └── logout.dart
|
||||
│ │ ├── presentation/
|
||||
│ │ │ ├── screens/
|
||||
│ │ │ │ ├── login_screen.dart
|
||||
│ │ │ │ └── register_screen.dart
|
||||
│ │ │ └── widgets/
|
||||
│ │ │ └── auth_form.dart
|
||||
│ │ └── providers/
|
||||
│ │ └── auth_provider.dart
|
||||
│ └── home/
|
||||
│ ├── data/
|
||||
│ ├── domain/
|
||||
│ ├── presentation/
|
||||
│ └── providers/
|
||||
├── shared/
|
||||
│ ├── widgets/
|
||||
│ │ ├── buttons/
|
||||
│ │ │ └── primary_button.dart
|
||||
│ │ ├── inputs/
|
||||
│ │ │ └── text_input.dart
|
||||
│ │ └── cards/
|
||||
│ │ └── info_card.dart
|
||||
│ ├── services/
|
||||
│ │ ├── api_service.dart
|
||||
│ │ └── storage_service.dart
|
||||
│ └── models/
|
||||
│ └── api_response.dart
|
||||
└── routes/
|
||||
└── app_router.dart
|
||||
```
|
||||
|
||||
## Feature Layer Responsibilities
|
||||
|
||||
| Layer | Responsibility |
|
||||
|-------|----------------|
|
||||
| **data/** | API calls, local storage, DTOs, repository implementations |
|
||||
| **domain/** | Business logic, entities, abstract repositories, use cases |
|
||||
| **presentation/** | UI screens, widgets, view logic |
|
||||
| **providers/** | Riverpod providers or Bloc definitions |
|
||||
|
||||
## pubspec.yaml Essentials
|
||||
|
||||
```yaml
|
||||
name: my_app
|
||||
description: A Flutter application.
|
||||
version: 1.0.0+1
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
sdk: '>=3.3.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
# State Management (choose one)
|
||||
flutter_riverpod: ^2.5.0
|
||||
riverpod_annotation: ^2.3.0
|
||||
# OR
|
||||
flutter_bloc: ^8.1.0
|
||||
|
||||
# Navigation
|
||||
go_router: ^14.0.0
|
||||
|
||||
# Networking
|
||||
dio: ^5.4.0
|
||||
|
||||
# Code Generation
|
||||
freezed_annotation: ^2.4.0
|
||||
json_annotation: ^4.9.0
|
||||
|
||||
# Storage
|
||||
shared_preferences: ^2.2.0
|
||||
hive_flutter: ^1.1.0
|
||||
|
||||
# Utilities
|
||||
flutter_hooks: ^0.20.0
|
||||
cached_network_image: ^3.3.0
|
||||
intl: ^0.19.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
# Code Generation
|
||||
build_runner: ^2.4.0
|
||||
riverpod_generator: ^2.4.0
|
||||
freezed: ^2.5.0
|
||||
json_serializable: ^6.8.0
|
||||
|
||||
# Linting
|
||||
flutter_lints: ^4.0.0
|
||||
|
||||
# Testing
|
||||
bloc_test: ^9.1.0
|
||||
mocktail: ^1.0.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
```
|
||||
|
||||
## Main Entry Point
|
||||
|
||||
```dart
|
||||
// main.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
// Initialize services
|
||||
await Hive.initFlutter();
|
||||
|
||||
runApp(
|
||||
const ProviderScope(
|
||||
child: MyApp(),
|
||||
),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```dart
|
||||
// app.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class MyApp extends ConsumerWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final router = ref.watch(routerProvider);
|
||||
|
||||
return MaterialApp.router(
|
||||
title: 'My App',
|
||||
routerConfig: router,
|
||||
theme: AppTheme.light,
|
||||
darkTheme: AppTheme.dark,
|
||||
themeMode: ThemeMode.system,
|
||||
debugShowCheckedModeBanner: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Router Provider
|
||||
|
||||
```dart
|
||||
// routes/app_router.dart
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
final routerProvider = Provider<GoRouter>((ref) {
|
||||
return GoRouter(
|
||||
initialLocation: '/',
|
||||
debugLogDiagnostics: true,
|
||||
redirect: (context, state) {
|
||||
// Auth guard logic
|
||||
return null;
|
||||
},
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
name: 'home',
|
||||
builder: (context, state) => const HomeScreen(),
|
||||
),
|
||||
// Add more routes
|
||||
],
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
```dart
|
||||
// core/constants/environment.dart
|
||||
enum Environment { dev, staging, prod }
|
||||
|
||||
class EnvConfig {
|
||||
static Environment current = Environment.dev;
|
||||
|
||||
static String get baseUrl {
|
||||
switch (current) {
|
||||
case Environment.dev:
|
||||
return 'https://dev-api.example.com';
|
||||
case Environment.staging:
|
||||
return 'https://staging-api.example.com';
|
||||
case Environment.prod:
|
||||
return 'https://api.example.com';
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Dependency Injection with Riverpod
|
||||
|
||||
```dart
|
||||
// shared/services/api_service.dart
|
||||
final apiServiceProvider = Provider<ApiService>((ref) {
|
||||
final dio = Dio(BaseOptions(
|
||||
baseUrl: EnvConfig.baseUrl,
|
||||
connectTimeout: const Duration(seconds: 10),
|
||||
receiveTimeout: const Duration(seconds: 10),
|
||||
));
|
||||
|
||||
// Add interceptors
|
||||
dio.interceptors.add(AuthInterceptor(ref));
|
||||
dio.interceptors.add(LogInterceptor(responseBody: true));
|
||||
|
||||
return ApiService(dio);
|
||||
});
|
||||
|
||||
// features/auth/providers/auth_provider.dart
|
||||
final authRepositoryProvider = Provider<AuthRepository>((ref) {
|
||||
final api = ref.watch(apiServiceProvider);
|
||||
final storage = ref.watch(storageServiceProvider);
|
||||
return AuthRepositoryImpl(api: api, storage: storage);
|
||||
});
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
| Practice | Description |
|
||||
|----------|-------------|
|
||||
| Feature isolation | Each feature is self-contained |
|
||||
| Dependency inversion | Domain depends on abstractions |
|
||||
| Single responsibility | One class, one purpose |
|
||||
| Naming conventions | Clear, descriptive names |
|
||||
| Barrel exports | One index.dart per folder |
|
||||
|
||||
---
|
||||
|
||||
*Flutter is a trademark of Google LLC.*
|
||||
|
||||
Reference in New Issue
Block a user