Dependency Injection In Flutter Clean Architecture with Provider State Management

Viewed 279

I am trying to wrap my head around clean architecture and I'd be grateful if someone could explain to me how to implement dependency injection in a flutter front end, and give me a basic idea of why it's useful.

I've been trying to make it work with get_it but there's so much info out there it just overwhelming so maybe if I could get one explanation on how to do this in the following case, I'd appreciate that very much.

Just a quick thank you in advance for reading through the below code.

member_remote_data.dart file inside data layer:

abstract class MemberRemoteDataSource {
  Future create({required Map<String, dynamic> member});
}

class MemberRemoteDataSourceImpl implements MemberRemoteDataSource {
  final http.Client _client = http.Client();
  final String _apiHost = Environment().config!.apiHost;

  @override
  Future create({required Map<String, dynamic> member}) async {
    final String url = "$_apiHost/api/member/create";
    final Uri uri = Uri.parse(url);
    final Map<String, String> headers = {
      'Content-Type': 'application/json',
    };

    final http.Response response = await _client.post(
      uri,
      headers: headers,
      body: member['type'] == 1
          ? ParentModel.toJson(member)
          : ChildModel.toJson(member),
    );

    if (response.statusCode >= 200 && response.statusCode < 300) {
      return jsonDecode(response.body);
    } else if (response.statusCode == 422) {
      return ValidationError(error: response.body);
    } else if (response.statusCode == 404) {
      return HttpPageNotFoundError();
    } else if (response.statusCode == 500) {
      return HttpInternalServerError();
    } else if (response.statusCode == 400) {
      return HttpBadRequestError(error: response.body);
    }
  }
}

member_repositroy_impl.dart file inside data layer:

class MemberRepositoryImpl implements MemberRepository {
  MemberRepositoryImpl({required this.memberRemoteDataSource});
  final MemberRemoteDataSource memberRemoteDataSource;

  @override
  Future create({required Map<String, dynamic> member}) async {
    return await memberRemoteDataSource.create(member: member);
  }
}

member_repository.dart file inside domain layer:

abstract class MemberRepository {
  Future create({required Map<String, dynamic> member});
}

create_member.dart use case file inside domain layer:

class CreateMember implements UseCase {
  CreateMember({required this.memberRepository});
  final MemberRepository memberRepository;

  @override
  Future create({required Map<String, dynamic> member}) async {
    return await memberRepository.create(member: member);
  }
}

Now, inside the presentation layer, I have my change notifiers where I want to "connect" all of the above together.

How do I do that? How do I add those parameters in a way that makes sens in clean architecture?

enum NotifierState { initial, loading, loaded }

class MemberNotifier extends ChangeNotifier {
  // How do I "connect" everything together
  // here to show this on the front end?
  final UseCase createMember = CreateMember();

  NotifierState _notifierState = NotifierState.initial;

  NotifierState get notifierState => _notifierState;

  void _setState(NotifierState notifierState) {
    _notifierState = notifierState;
    notifyListeners();
  }

  String? _emailAlreadyExists;
  String? get emailAlreadyExists => _emailAlreadyExists;
  void setFailure(emailAlreadyExists) {
    _emailAlreadyExists = emailAlreadyExists;
    notifyListeners();
  }

  Future create({required Map<String, dynamic> member}) async {
    // _setState(NotifierState.loading);
    var body = await createMember.create(member: member);
    if (body is ValidationError) {
      setFailure(body.emailAlreadyExists());
      _setState(NotifierState.loaded);
    } else {}
    _setState(NotifierState.loaded);
    return body;
  }
}
0 Answers
Related