đ flx gen feature
flx gen feature
āĻšāϞ FLX CLI-āϰ āϏāĻŦāĻā§āϝāĻŧā§ powerful command āϝāĻž āĻāĻāĻāĻŋ complete Clean Architecture feature structure āϤā§āϰāĻŋ āĻāϰā§āĨ¤
đ¯ Command Overviewâ
flx gen feature <feature_name>
đ Descriptionâ
āĻāĻ command āĻāĻāĻāĻŋ complete feature āϤā§āϰāĻŋ āĻāϰ⧠āϝāĻžāϤ⧠āĻĨāĻžāĻā§:
- Domain Layer: Entities, Use Cases, Repository Interfaces
- Data Layer: Models, Data Sources, Repository Implementations
- Presentation Layer: Pages, Controllers/BLoC, Bindings
đ¨ Basic Usageâ
Simple Feature Generationâ
# Authentication feature āϤā§āϰāĻŋ āĻāϰā§āύ
flx gen feature auth
# â
Output:
# â
Generated feature "auth" with files:
# - lib/features/auth/domain/entities/auth_entity.dart
# - lib/features/auth/data/models/auth_model.dart
# - lib/features/auth/data/datasources/auth_remote_data_source.dart
# - lib/features/auth/data/repositories/auth_repository_impl.dart
# - lib/features/auth/domain/repositories/auth_repository.dart
# - lib/features/auth/domain/usecases/auth_usecase.dart
# - lib/features/auth/presentation/pages/auth_page.dart
# - lib/features/auth/presentation/bindings/auth_binding.dart
# - lib/features/auth/presentation/controllers/auth_controller.dart (GetX)
# OR
# - lib/features/auth/presentation/bloc/auth_bloc.dart (BLoC)
# - lib/features/auth/presentation/bloc/auth_event.dart (BLoC)
# - lib/features/auth/presentation/bloc/auth_state.dart (BLoC)
Multiple Featuresâ
# āĻāĻāĻžāϧāĻŋāĻ features āϤā§āϰāĻŋ āĻāϰā§āύ
flx gen feature auth
flx gen feature dashboard
flx gen feature profile
flx gen feature settings
# â
Result: 4āĻāĻŋ complete features ready!
đ Generated Structureâ
đ¯ GetX Configurationâ
flx config --state getx
flx gen feature auth
Generated Files:
lib/features/auth/
âââ data/
â âââ datasources/
â â âââ auth_remote_data_source.dart
â âââ models/
â â âââ auth_model.dart
â âââ repositories/
â âââ auth_repository_impl.dart
âââ domain/
â âââ entities/
â â âââ auth_entity.dart
â âââ repositories/
â â âââ auth_repository.dart
â âââ usecases/
â âââ auth_usecase.dart
âââ presentation/
âââ bindings/
â âââ auth_binding.dart
âââ controllers/
â âââ auth_controller.dart
âââ pages/
âââ auth_page.dart
đ§ą BLoC Configurationâ
flx config --state bloc
flx gen feature auth
Generated Files:
lib/features/auth/
âââ data/
â âââ ... (same as GetX)
âââ domain/
â âââ ... (same as GetX)
âââ presentation/
âââ bindings/
â âââ auth_binding.dart
âââ bloc/
â âââ auth_bloc.dart
â âââ auth_event.dart
â âââ auth_state.dart
âââ pages/
âââ auth_page.dart
đ Generated Code Examplesâ
1. đˇ Domain Entityâ
File: lib/features/auth/domain/entities/auth_entity.dart
import 'package:freezed_annotation/freezed_annotation.dart';
part 'auth_entity.freezed.dart';
class AuthEntity with _$AuthEntity {
const factory AuthEntity({
required String id,
// Add your entity properties here
}) = _AuthEntity;
}
2. đ Repository Interfaceâ
File: lib/features/auth/domain/repositories/auth_repository.dart
import '../entities/auth_entity.dart';
abstract class AuthRepository {
Future<List<AuthEntity>> getAll();
Future<AuthEntity?> getById(String id);
Future<AuthEntity> create(AuthEntity entity);
Future<AuthEntity> update(AuthEntity entity);
Future<void> delete(String id);
}
3. đ¯ Use Caseâ
File: lib/features/auth/domain/usecases/auth_usecase.dart
import '../entities/auth_entity.dart';
import '../repositories/auth_repository.dart';
class AuthUseCase {
const AuthUseCase(this._repository);
final AuthRepository _repository;
Future<List<AuthEntity>> call() async {
return await _repository.getAll();
}
}
4. đ Data Modelâ
File: lib/features/auth/data/models/auth_model.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/entities/auth_entity.dart';
part 'auth_model.freezed.dart';
part 'auth_model.g.dart';
class AuthModel with _$AuthModel {
const factory AuthModel({
required String id,
// Add your model properties here
}) = _AuthModel;
factory AuthModel.fromJson(Map<String, dynamic> json) =>
_$AuthModelFromJson(json);
}
extension AuthModelX on AuthModel {
AuthEntity toEntity() {
return AuthEntity(
id: id,
// Map your properties here
);
}
}
5. đ Data Sourceâ
File: lib/features/auth/data/datasources/auth_remote_data_source.dart
import '../models/auth_model.dart';
abstract class AuthRemoteDataSource {
Future<List<AuthModel>> getAll();
Future<AuthModel?> getById(String id);
Future<AuthModel> create(AuthModel model);
Future<AuthModel> update(AuthModel model);
Future<void> delete(String id);
}
class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
const AuthRemoteDataSourceImpl();
Future<List<AuthModel>> getAll() async {
// TODO: Implement API call
throw UnimplementedError('getAll() not implemented');
}
Future<AuthModel?> getById(String id) async {
// TODO: Implement API call
throw UnimplementedError('getById() not implemented');
}
// ... other methods
}
6. đ Repository Implementationâ
File: lib/features/auth/data/repositories/auth_repository_impl.dart
import '../../domain/entities/auth_entity.dart';
import '../../domain/repositories/auth_repository.dart';
import '../datasources/auth_remote_data_source.dart';
import '../models/auth_model.dart';
class AuthRepositoryImpl implements AuthRepository {
const AuthRepositoryImpl(this._remoteDataSource);
final AuthRemoteDataSource _remoteDataSource;
Future<List<AuthEntity>> getAll() async {
final models = await _remoteDataSource.getAll();
return models.map((model) => model.toEntity()).toList();
}
Future<AuthEntity?> getById(String id) async {
final model = await _remoteDataSource.getById(id);
return model?.toEntity();
}
// ... other methods
}
7. đŽ GetX Controllerâ
File: lib/features/auth/presentation/controllers/auth_controller.dart
import 'package:get/get.dart';
import '../../domain/entities/auth_entity.dart';
import '../../domain/usecases/auth_usecase.dart';
class AuthController extends GetxController {
AuthController(this._authUseCase);
final AuthUseCase _authUseCase;
final _isLoading = false.obs;
final _authList = <AuthEntity>[].obs;
bool get isLoading => _isLoading.value;
List<AuthEntity> get authList => _authList;
void onInit() {
super.onInit();
loadAuths();
}
Future<void> loadAuths() async {
try {
_isLoading.value = true;
final result = await _authUseCase();
_authList.value = result;
} catch (e) {
Get.snackbar('Error', 'Failed to load auths: $e');
} finally {
_isLoading.value = false;
}
}
Future<void> refresh() async {
await loadAuths();
}
}
8. đ§ą BLoC Filesâ
auth_bloc.dart:
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import '../../domain/entities/auth_entity.dart';
import '../../domain/usecases/auth_usecase.dart';
part 'auth_event.dart';
part 'auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc(this._authUseCase) : super(AuthInitial()) {
on<LoadAuths>(_onLoadAuths);
on<RefreshAuths>(_onRefreshAuths);
}
final AuthUseCase _authUseCase;
Future<void> _onLoadAuths(
LoadAuths event,
Emitter<AuthState> emit,
) async {
emit(AuthLoading());
try {
final result = await _authUseCase();
emit(AuthLoaded(result));
} catch (e) {
emit(AuthError(e.toString()));
}
}
// ... other event handlers
}
auth_event.dart:
part of 'auth_bloc.dart';
abstract class AuthEvent extends Equatable {
const AuthEvent();
List<Object> get props => [];
}
class LoadAuths extends AuthEvent {
const LoadAuths();
}
class RefreshAuths extends AuthEvent {
const RefreshAuths();
}
auth_state.dart:
part of 'auth_bloc.dart';
abstract class AuthState extends Equatable {
const AuthState();
List<Object> get props => [];
}
class AuthInitial extends AuthState {
const AuthInitial();
}
class AuthLoading extends AuthState {
const AuthLoading();
}
class AuthLoaded extends AuthState {
const AuthLoaded(this.authList);
final List<AuthEntity> authList;
List<Object> get props => [authList];
}
class AuthError extends AuthState {
const AuthError(this.message);
final String message;
List<Object> get props => [message];
}
9. đą UI Pageâ
File: lib/features/auth/presentation/pages/auth_page.dart
GetX Version:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';
class AuthPage extends GetView<AuthController> {
const AuthPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Auth'),
),
body: Obx(() {
if (controller.isLoading) {
return const Center(child: CircularProgressIndicator());
}
return RefreshIndicator(
onRefresh: controller.refresh,
child: ListView.builder(
itemCount: controller.authList.length,
itemBuilder: (context, index) {
final item = controller.authList[index];
return ListTile(
title: Text(item.id),
// Add more UI components here
);
},
),
);
}),
);
}
}
BLoC Version:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../bloc/auth_bloc.dart';
class AuthPage extends StatelessWidget {
const AuthPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Auth'),
),
body: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthLoading) {
return const Center(child: CircularProgressIndicator());
}
if (state is AuthError) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Error: ${state.message}'),
ElevatedButton(
onPressed: () => context.read<AuthBloc>().add(const RefreshAuths()),
child: const Text('Retry'),
),
],
),
);
}
if (state is AuthLoaded) {
return RefreshIndicator(
onRefresh: () async {
context.read<AuthBloc>().add(const RefreshAuths());
},
child: ListView.builder(
itemCount: state.authList.length,
itemBuilder: (context, index) {
final item = state.authList[index];
return ListTile(
title: Text(item.id),
// Add more UI components here
);
},
),
);
}
return const Center(child: Text('No data available'));
},
),
);
}
}
10. đ Dependency Injectionâ
GetX Binding:
import 'package:get/get.dart';
import '../../data/datasources/auth_remote_data_source.dart';
import '../../data/repositories/auth_repository_impl.dart';
import '../../domain/repositories/auth_repository.dart';
import '../../domain/usecases/auth_usecase.dart';
import '../controllers/auth_controller.dart';
class AuthBinding extends Bindings {
void dependencies() {
Get.lazyPut<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImpl(),
);
Get.lazyPut<AuthRepository>(
() => AuthRepositoryImpl(Get.find()),
);
Get.lazyPut<AuthUseCase>(
() => AuthUseCase(Get.find()),
);
Get.lazyPut<AuthController>(
() => AuthController(Get.find()),
);
}
}
BLoC Provider:
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import '../../data/datasources/auth_remote_data_source.dart';
import '../../data/repositories/auth_repository_impl.dart';
import '../../domain/repositories/auth_repository.dart';
import '../../domain/usecases/auth_usecase.dart';
import '../bloc/auth_bloc.dart';
class AuthProvider {
static void init() {
final getIt = GetIt.instance;
// Data Sources
getIt.registerLazySingleton<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImpl(),
);
// Repositories
getIt.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(getIt()),
);
// Use Cases
getIt.registerLazySingleton<AuthUseCase>(
() => AuthUseCase(getIt()),
);
// BLoC
getIt.registerFactory<AuthBloc>(
() => AuthBloc(getIt()),
);
}
static BlocProvider<AuthBloc> provide({
required Widget child,
}) {
return BlocProvider<AuthBloc>(
create: (context) => GetIt.instance<AuthBloc>()..add(const LoadAuths()),
child: child,
);
}
}
đ¯ Naming Conventionsâ
Feature Namesâ
# â
Good names (snake_case)
flx gen feature user_profile
flx gen feature order_management
flx gen feature payment_gateway
# â Avoid these
flx gen feature UserProfile # PascalCase
flx gen feature user-profile # kebab-case
flx gen feature userProfile # camelCase
Generated Class Namesâ
// Feature: user_profile
UserProfileEntity // Entity
UserProfileModel // Model
UserProfileUseCase // Use Case
UserProfileController // Controller
UserProfileBloc // BLoC
UserProfilePage // Page
đ Real-World Examplesâ
E-commerce Featuresâ
# Core features
flx gen feature auth
flx gen feature product_catalog
flx gen feature shopping_cart
flx gen feature order_management
flx gen feature payment_processing
flx gen feature user_profile
# Admin features
flx gen feature admin_dashboard
flx gen feature inventory_management
flx gen feature customer_support
Social Media Featuresâ
# User features
flx gen feature user_registration
flx gen feature user_profile
flx gen feature friend_management
flx gen feature post_creation
flx gen feature news_feed
flx gen feature messaging
flx gen feature notifications
đ Next Stepsâ
After Generationâ
- Customize Entities: Add your specific properties
- Implement Data Sources: Add actual API calls
- Update Use Cases: Add business logic
- Style UI Pages: Design your user interface
- Add Navigation: Connect pages with routing
Example Customizationâ
// Customize auth_entity.dart
class AuthEntity with _$AuthEntity {
const factory AuthEntity({
required String id,
required String email,
required String name,
required String token,
required DateTime createdAt,
required bool isVerified,
}) = _AuthEntity;
}
// Update auth_model.dart accordingly
// Implement actual API calls in auth_remote_data_source.dart
// Add business validation in auth_usecase.dart
đ Best Practicesâ
â DOâ
- Feature Planning: Generate āĻāϰāĻžāϰ āĻāĻā§ feature requirements clear āĻāϰā§āύ
- Consistent Naming: snake_case āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§āύ
- Immediate Customization: Generate āĻāϰāĻžāϰ āĻĒāϰ immediately customize āĻāϰā§āύ
- Version Control: Generated files commit āĻāϰā§āύ
â DON'Tâ
- Mixed Naming: Different naming conventions mix āĻāϰāĻŦā§āύ āύāĻž
- Mass Generation: āϏāĻŦ features āĻāĻāϏāĻžāĻĨā§ generate āĻāϰ⧠customize āύāĻž āĻāϰāĻž
- Template Dependency: Generated templates-āĻāϰ āĻāĻĒāϰ completely āύāĻŋāϰā§āĻāϰ āĻāϰāĻž
Ready to create your first feature? đ Installation complete āĻāϰā§āύ āĻāĻŦāĻ flx gen feature auth
āĻĻāĻŋāϝāĻŧā§ āĻļā§āϰ⧠āĻāϰā§āύ!