Clean architecture flutter folder structure details explain & example

  Flutter-এ Clean Architecture ব্যবহার করে একটি ফোল্ডার স্ট্রাকচার সাজানো হয় Dependency Inversion Principle (DIP) এবং Separation of Concerns (SoC) অনুসারে। এই স্ট্রাকচারটি অ্যাপ্লিকেশনের প্রতিটি লেয়ারকে নির্দিষ্ট দায়িত্ব দেয় এবং একে অপরের থেকে আলাদা রাখে।

Clean Architecture-এ প্রধানত তিনটি লেয়ার থাকে:

  1. Presentation Layer
  2. Domain Layer
  3. Data Layer

ফোল্ডার স্ট্রাকচার:

plaintext
lib/ ├── core/ │ ├── constants/ │ ├── errors/ │ ├── utils/ │ └── widgets/ ├── features/ │ ├── feature_name/ │ │ ├── data/ │ │ │ ├── models/ │ │ │ ├── datasources/ │ │ │ └── repositories/ │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ ├── repositories/ │ │ │ └── usecases/ │ │ ├── presentation/ │ │ │ ├── bloc/ (or cubit) │ │ │ ├── pages/ │ │ │ └── widgets/ ├── app/ │ ├── routes/ │ ├── theme/ │ └── app.dart └── main.dart

ফোল্ডার লেয়ার ব্যাখ্যা:

1. Core Folder

এখানে এমন কোড রাখা হয় যা অ্যাপ্লিকেশনের বিভিন্ন ফিচারে পুনর্ব্যবহার করা যাবে।

  • constants/: অ্যাপ্লিকেশনের কনস্ট্যান্ট ভ্যালু, যেমন কালার বা স্ট্রিং।
  • errors/: কাস্টম এক্সসেপশন হ্যান্ডলিং।
  • utils/: হেল্পার ক্লাস বা ফাংশন।
  • widgets/: রিইউজেবল উইজেট।

2. Features Folder

প্রতিটি ফিচার আলাদা ফোল্ডারে থাকে।

  • data/:
    • models/: JSON থেকে ডাটা ম্যাপিংয়ের জন্য মডেল।
    • datasources/: API কল বা লোকাল ডেটাবেস অ্যাক্সেসের কোড।
    • repositories/: ডোমেইন লেয়ারে ডাটা প্রসেস করে পাঠানোর জন্য ইমপ্লিমেন্টেশন।
  • domain/:
    • entities/: ফিচারের মূল ডেটা স্ট্রাকচার (POJO বা pure Dart classes)।
    • repositories/: অ্যাবস্ট্রাক্ট ক্লাস যা ইন্টারফেস হিসেবে কাজ করে।
    • usecases/: বিজনেস লজিক যা ডোমেইন লেয়ারের নিয়ম অনুযায়ী কাজ করে।
  • presentation/:
    • bloc/ বা cubit/: স্টেট ম্যানেজমেন্ট।
    • pages/: UI পেজ।
    • widgets/: ফিচার-স্পেসিফিক ছোট উইজেট।

3. App Folder

পুরো অ্যাপ্লিকেশনের শীর্ষস্তরের সেটআপ।

  • routes/: নেভিগেশন ব্যবস্থা।
  • theme/: অ্যাপের থিম বা স্টাইল।
  • app.dart: অ্যাপের মূল এন্ট্রি পয়েন্ট।

4. Main.dart

অ্যাপ্লিকেশনের এন্ট্রি পয়েন্ট, যেখানে runApp কল করা হয়।


উদাহরণ:

ধরা যাক, একটি Authentication ফিচার তৈরি করছি। ফোল্ডার স্ট্রাকচার হবে এমন:

plaintext
lib/ ├── features/ │ ├── authentication/ │ │ ├── data/ │ │ │ ├── models/ │ │ │ │ └── user_model.dart │ │ │ ├── datasources/ │ │ │ │ └── auth_remote_data_source.dart │ │ │ └── repositories/ │ │ │ └── auth_repository_impl.dart │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ │ └── user.dart │ │ │ ├── repositories/ │ │ │ │ └── auth_repository.dart │ │ │ └── usecases/ │ │ │ └── login_user.dart │ │ ├── presentation/ │ │ │ ├── bloc/ │ │ │ │ └── auth_bloc.dart │ │ │ ├── pages/ │ │ │ │ └── login_page.dart │ │ │ └── widgets/ │ │ │ └── login_form.dart

ব্যাখ্যা: Login Use Case

Domain Layer

  • Entity:
dart
class User { final String id; final String email; final String token; User({required this.id, required this.email, required this.token}); }
  • Use Case:
dart
class LoginUser { final AuthRepository repository; LoginUser(this.repository); Future<User> call(String email, String password) { return repository.login(email, password); } }

Data Layer

  • Model:
dart
class UserModel extends User { UserModel({required String id, required String email, required String token}) : super(id: id, email: email, token: token); factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( id: json['id'], email: json['email'], token: json['token'], ); } }
  • Repository Implementation:
dart
class AuthRepositoryImpl implements AuthRepository { final AuthRemoteDataSource remoteDataSource; AuthRepositoryImpl(this.remoteDataSource); @override Future<User> login(String email, String password) async { final result = await remoteDataSource.login(email, password); return UserModel.fromJson(result); } }

Presentation Layer

  • Bloc:
dart
class AuthBloc extends Bloc<AuthEvent, AuthState> { final LoginUser loginUser; AuthBloc(this.loginUser) : super(AuthInitial()) { on<LoginEvent>((event, emit) async { emit(AuthLoading()); final user = await loginUser(event.email, event.password); emit(AuthLoaded(user)); }); } }

এভাবে Clean Architecture অনুসরণ করলে কোড পুনর্ব্যবহারযোগ্য, পরীক্ষাযোগ্য এবং মডুলার হয়।

You said:
now i need full code to best understand with all folders (core, features, app)
ChatGPT said:
ChatGPT
Clean Architecture Flutter

উপরোক্ত কোডে Clean Architecture অনুযায়ী একটি Flutter অ্যাপের জন্য প্রয়োজনীয় সব ফোল্ডার এবং ফাইল তৈরি করা হয়েছে।

ফোল্ডার কাঠামো:

  • app/: অ্যাপ্লিকেশনের গ্লোবাল সেটআপ (থিম, রাউটিং ইত্যাদি)।
  • core/: শেয়ার করা কনস্ট্যান্টস, এরর হ্যান্ডলিং, এবং ইউটিলিটি।
  • features/: ফিচার ভিত্তিক ডাটা, ডোমেইন, এবং প্রেজেন্টেশন লেয়ারের আলাদা অংশ।

ফিচার উদাহরণ:

  • Authenticationfeatures/authentication ফোল্ডারে একটি Login ফিচারের ডেটা, ডোমেইন এবং প্রেজেন্টেশন লেয়ার আছে।

আপনার প্রোজেক্টে এই কাঠামো ব্যবহার করে নতুন ফিচার বা কম্পোনেন্ট সহজে যোগ করতে পারবেন। যদি কোনো নির্দিষ্ট অংশ সম্পর্কে বিস্তারিত জানতে চান, জানাবেন!

You said:
Error: Could not find the correct Provider<AuthBloc> above this BlocBuilder<AuthBloc, AuthState> Widget This happens because you used a BuildContext that does not include the provider of your choice. There are a few common scenarios:
ChatGPT said:
ChatGPT

এই সমস্যাটি সাধারণত ঘটে যখন আপনি BlocBuilderBlocProvider.of, বা context.read<AuthBloc>() এর মতো কিছু ব্যবহার করেন, কিন্তু AuthBloc-এর জন্য কোনো BlocProvider উপরের লেয়ারে দেয়া থাকে না।

সমাধানের জন্য নিচের ধাপগুলো অনুসরণ করুন:


১. নিশ্চিত করুন যে BlocProvider উপরের স্তরে আছে

আপনার LoginPage বা যেখানেই BlocBuilder ব্যবহার করেছেন, তার উপরের স্তরে BlocProvider যুক্ত করতে হবে। উদাহরণস্বরূপ:

dart
import 'package:flutter_bloc/flutter_bloc.dart'; import 'features/authentication/presentation/bloc/auth_bloc.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider<AuthBloc>( create: (_) => AuthBloc(/* আপনার ডিপেনডেন্সি ইনজেকশন */), ), ], child: MaterialApp( theme: AppTheme.lightTheme, onGenerateRoute: AppRoutes.onGenerateRoute, initialRoute: AppRoutes.loginPage, ), ); } }

২. নির্দিষ্ট স্ক্রিনে BlocProvider যুক্ত করা

যদি আপনি শুধু LoginPage-এর জন্য AuthBloc প্রয়োজন হয়, তাহলে ওই পৃষ্ঠায় সরাসরি যুক্ত করুন:

dart
import 'package:flutter_bloc/flutter_bloc.dart'; import 'features/authentication/presentation/bloc/auth_bloc.dart'; import 'features/authentication/presentation/pages/login_page.dart'; class AppRoutes { static const loginPage = '/login'; static Route<dynamic>? onGenerateRoute(RouteSettings settings) { switch (settings.name) { case loginPage: return MaterialPageRoute( builder: (_) => BlocProvider<AuthBloc>( create: (_) => AuthBloc(/* আপনার ডিপেনডেন্সি ইনজেকশন */), child: const LoginPage(), ), ); default: return null; } } }

৩. কোডটি ডিবাগ করা

  • নিশ্চিত করুন যে BlocBuilder<AuthBloc, AuthState> ঠিকঠাক BuildContext ব্যবহার করছে।
  • যদি আপনি ভুলভাবে কোনো অন্য BuildContext পাঠিয়ে থাকেন, তাহলে উপরের BlocProvider খুঁজে পাবে না।

৪. ফলোআপ চেকলিস্ট

  • BlocProvider সঠিক স্তরে আছে কি না।
  • ডিপেনডেন্সি সঠিকভাবে ইনজেক্ট করা হয়েছে কি না।
  • BlocBuilder সঠিক BuildContext ব্যবহার করছে কি না।

এভাবে উপরের সমস্যার সমাধান করা সম্ভব। যদি সমস্যা থেকেই যায়, তাহলে আপনার কোডের আরও বিস্তারিত পাঠিয়ে দিন, আমি আরও নির্দিষ্টভাবে সাহায্য করতে পারব। 😊

You said:
please give me this line
ChatGPT said:
ChatGPT

আপনি যেই BlocProvider ঠিকভাবে কনফিগার করতে চাইছেন, সেই লাইনটি নিচে উল্লেখ করা হলো:

dart
BlocProvider<AuthBloc>( create: (context) => AuthBloc(/* আপনার ডিপেনডেন্সি ইনজেকশন */), child: YourWidgetHere(), )

ব্যবহারের জায়গা:
যদি এটি MaterialApp বা Scaffold-এর উপরে যুক্ত করতে হয়, তাহলে:

dart
@override Widget build(BuildContext context) { return BlocProvider<AuthBloc>( create: (context) => AuthBloc(), child: MaterialApp( theme: AppTheme.lightTheme, home: const LoginPage(), ), ); }

অথবা, নির্দিষ্ট কোনো পৃষ্ঠায় যদি এটি ব্যবহার করতে চান:

dart
BlocProvider<AuthBloc>( create: (context) => AuthBloc(), child: LoginPage(), )

সমস্যার সমাধান নিশ্চিত করার জন্য:

  • create-এর মধ্যে AuthBloc ঠিকভাবে ইনিশিয়ালাইজ করুন।
  • LoginPage-এ BlocBuilder<AuthBloc, AuthState> বা context.read<AuthBloc>() সঠিকভাবে ব্যবহার করুন।

যদি আরও কোনো সাহায্য প্রয়োজন হয়, জানাবেন। 😊

Comments