0

This is less about a specific implementation, but more about good practice.

I have the following structure in a flutter desktop project:

  • DataProviders: read data from one of two different fileformats (locally)
  • Repository: parses the data and instantiates my Model
  • ProjectCubit: takes a path from a FilePicker and gets the Project from the upper 2 layers

ProjectCubit.dart:

class ProjectCubit extends Cubit<ProjectState> {
  ProjectCubit() : super(ProjectState.Closed);

  Project? loadedProject;

  Project? getProject() {
    // return loaded instance of Project if loaded
    if(loadedProject != null)
      return loadedProject;
  }

  // creates Project instance from csv file
  void importProject(String filePath) async {
    emit(ProjectState.Importing);
    loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
    emit(ProjectState.Open);
  }

  // open json-Project file 
  void openProject(String filePath) async {
    emit(ProjectState.Opening);
  try {
      loadedProject = await ProjectRepository().loadData(loadType: ProjectLoadType.OPEN_PROJECT_FILE, filePath: filePath);
    } catch (e) {
      emit(ProjectState.Closed);
      Log().l.e("Opening file failed with ${e.toString()}");
    }
    emit(ProjectState.Open);
  }
}

where the states are:

enum ProjectState {
  Closed,
  Importing,
  Opening,
  Open
}

The Project instance in the ProjectCubit needs to be accessed and changed from multiple screens in multiple settings (DataTable, simple Inputs etc.). For example, Project has a Customer, which has a customerName, customerId etc. which have to be changed from a Customer-Settings screen.

I thought of two ways:

  • creating a ProjectSettingsCubit, CustomerDataCubit, ProjectDataCubit etc. which take the ProjectCubit as an argument and modify the Project from there
  • just using the ProjectCubit the entire time and making the changes from the Presentation layer

What would be the best way to accomplish this? And if the whole structure or Cubit is bad, why?

Would appreciate any help, thanks

snti
  • 35
  • 1
  • 6

1 Answers1

0

The best practice depends on what you want to accomplish. If you want your application to scale in future, have several people work on it, facilitate better reusability and better testability, it is recommended to separate business logic & UI as much as you can. So it would not make sense to have logic in your presentation layer directly. As you are using cubit, you would want to be consistent in your program & try to have UI and logic decoupled as much as you can.

This comes at a cost ofcourse. You need to put more time & make your code more complicated than before.

As for your answer, I suggest using a ProjectCubit and implement several events as for your requirements, like CustomerChangeEvent for changing customer.

If you have any special requirements that need to be implemented differently in two pages, then I suggest inheriting from a base class or just using a mixin and extending that class in different cubits.

class BaseProjectCubit extends Cubit<ProjectState> {
  void importProject(String filePath) async {
    emit(ProjectState.Importing);
    loadedProject = await ProjectRepository().loadData(loadType: 
  ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
    emit(ProjectState.Open);
  }
...
}

class ProjectCubitA extends BaseProjectCubit {
  @override
  void importProject(String filePath) async {

    ...
  }
}

class ProjectCubitB extends BaseProjectCubit {
  importProject(String filePath) async {
    ...
  }
}

Or for using mixins, it would be something like this:

mixin ProjectModifier {
  void importProject(String filePath) async {
    emit(ProjectState.Importing);
    loadedProject = await ProjectRepository().loadData(loadType: 
  ProjectLoadType.IMPORT_FROM_CSV, filePath: filePath);
    emit(ProjectState.Open);
  }
...
}

class CustomerTypeOneProjectCubit extends Cubit<ProjectState> with ProjectModifier {
  changeName(String newName) {
    ...
  }
}

class CustomerTypeTwoProjectCubit extends Cubit<ProjectState> with ProjectModifier {
  changeName(String newName) {
    ...
  }
}
Sajad Rezvani
  • 366
  • 2
  • 14
  • Thank you so much, however, if I go with either a mixin or the Baseclass Subclass model, how would I get them to share the same instance of Project? Now I basically call openProject() once and would need the created instance for all operations of the other cubits. – snti Aug 21 '21 at 21:01
  • I just created a ProjectSettingsCubit and it seems to work. Thank you! – snti Aug 21 '21 at 21:20
  • I see. If you want to share the project instance, you could use project as static field in your base class. Or as you said yourself, share the `projectCubit` itself. – Sajad Rezvani Aug 21 '21 at 21:20
  • I am really confused because I thought that it would be passed by value, not by reference, and I would just edit a copy when using Project instead of ProjectCubit, but it seems to work, gotta look at how Dart passes variables again – snti Aug 21 '21 at 21:23