flutter_architecture_blueprint is a flutter project that demonstrates a three layers architecture in the form of ToDo app.
Detailed explanations and background information are provided in the related article on our technical blog.
π https://tech.up-sider.com/entry/2024/04/15/110000
https://upsidr.github.io/flutter_architecture_blueprint/
Purpose | Package |
---|---|
State Management | hooks_riverpod, rxdart |
Modeling | freezed |
Routing | auto_route |
typedef TaskListContract
= BaseContract<TaskListUiState, TaskListAction, TaskListEffect>;
@freezed
class TaskListUiState with _$TaskListUiState {
const factory TaskListUiState({
@Default([]) List<EditableUserTask> taskList,
}) = _TaskListUiState;
}
@freezed
sealed class TaskListAction with _$TaskListAction {
const factory TaskListAction.onAppear() = OnAppear;
const factory TaskListAction.newTaskButtonTapped() = NewTaskButtonTapped;
const factory TaskListAction.taskTapped(EditableUserTask task) = TaskTapped;
const factory TaskListAction.toggleIsCompleted(EditableUserTask task) =
ToggleIsCompleted;
const factory TaskListAction.onTaskSwiped(EditableUserTask task) =
OnTaskSwiped;
}
@freezed
sealed class TaskListEffect with _$TaskListEffect {
const factory TaskListEffect.none() = None;
const factory TaskListEffect.goDetail({
required EditableUserTask? task,
}) = GoDetail;
const factory TaskListEffect.showAlert({
required AlertState state,
}) = ShowAlert;
}
Steps of Unit Testing for presentation layer:
- Call
notifier.send(Action)
to trigger View events - Assert UiState / Effect
test('Tap NewTaskButton, navigate detail', () async {
final (notifier, uiState, effect) = buildAccessors();
todoRepository.handler.fetchTaskList = () async =>
fakeTodoState.update((value) => value.copyWith(taskList: []));
await notifier.send(const TaskListAction.onAppear());
expect(uiState().taskList.isEmpty, true);
await notifier.send(const TaskListAction.newTaskButtonTapped());
expect(
effect(),
const TaskListEffect.goDetail(task: null),
);
});
βββ app_router.dart
βββ app_router.gr.dart
βββ core
β βββ data
β β βββ network
β β β βββ fake_todo_api_client.dart
β β βββ repository
β β βββ todo
β β βββ fake_todo_repository.dart
β β βββ fake_todo_repository.freezed.dart
β β βββ todo_repository.dart
β β βββ todo_repository.freezed.dart
β βββ domain
β β βββ model
β β β βββ editable_user_task.dart
β β β βββ editable_user_task.freezed.dart
β β βββ todo
β β βββ edit_task_usecase.dart
β β βββ edit_task_usecase.freezed.dart
β β βββ task_list_usecase.dart
β β βββ task_list_usecase.freezed.dart
β βββ model
β β βββ user_task.dart
β β βββ user_task.freezed.dart
β β βββ user_task.g.dart
β βββ util
β βββ alert_state.dart
β βββ alert_state.freezed.dart
β βββ base_contract.dart
β βββ datetime_formatted.dart
β βββ stream_extensions.dart
βββ feature
β βββ todo
β βββ edit_task
β β βββ edit_task_contract.dart
β β βββ edit_task_contract.freezed.dart
β β βββ edit_task_notifier.dart
β β βββ edit_task_notifier.g.dart
β β βββ edit_task_page.dart
β β βββ ui_components
β β βββ task_text_field.dart
β β βββ toggle_complete_button.dart
β βββ task_list
β βββ task_list_contract.dart
β βββ task_list_contract.freezed.dart
β βββ task_list_notifier.dart
β βββ task_list_notifier.g.dart
β βββ task_list_page.dart
β βββ ui_components
β βββ task_list_item.dart
β βββ task_list_placeholder.dart
βββ main.dart
βββ main_device_preview.dart