Skip to content

On finish callback #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion core/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -37,7 +37,10 @@ class MyHomePage extends StatelessWidget {
),
// Add Survey to your widget tree with filePath parameter that accepts
// a json file with parsed survey data
body: const Survey(filePath: 'assets/questions.json'),
body: const Survey(
filePath: 'assets/questions.json',
onFinish: print,
),
);
}
}
9 changes: 6 additions & 3 deletions core/lib/src/presentation/survey/survey.dart
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import 'package:survey_sdk/src/presentation/survey/survey_cubit.dart';
import 'package:survey_sdk/src/presentation/survey/survey_state.dart';
import 'package:survey_sdk/src/presentation/survey_error/survey_error.dart';
import 'package:survey_sdk/src/presentation/utils/callback_type.dart';
import 'package:survey_sdk/src/presentation/utils/on_finish_callback.dart';
import 'package:survey_sdk/src/presentation/utils/utils.dart';

// TODO(dev): Maybe create two classes, where one is for filePath and the other
@@ -44,13 +45,17 @@ class Survey extends StatefulWidget {
/// Whether the survey should save user selected answers.
final bool saveAnswer;

/// Called after the survey is finished.
final OnFinishCallback? onFinish;

/// Either [filePath] or [surveyData] must pe provided. The [controller]
/// parameter is optional and can be used to provide a custom survey
/// controller.
const Survey({
this.filePath,
this.surveyData,
this.controller,
this.onFinish,
this.saveAnswer = true,
super.key,
}) : assert(
@@ -107,6 +112,7 @@ class _SurveyState extends State<Survey> {
index,
answer,
callbackType,
onFinish: widget.onFinish,
saveAnswer: widget.saveAnswer,
);
}
@@ -177,9 +183,6 @@ class _SurveyState extends State<Survey> {
onGoNext: _surveyController.onNext,
),
),
DataToWidgetUtil.createEndPage(
data: data.endPage,
),
],
),
),
19 changes: 17 additions & 2 deletions core/lib/src/presentation/survey/survey_cubit.dart
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:survey_sdk/src/domain/entities/question_answer.dart';
import 'package:survey_sdk/src/domain/repository_interfaces/survey_data_repository.dart';
import 'package:survey_sdk/src/presentation/survey/survey_state.dart';
import 'package:survey_sdk/src/presentation/utils/on_finish_callback.dart';
import 'package:survey_sdk/src/presentation/utils/survey_button_callback.dart';

import 'package:survey_sdk/survey_sdk.dart';
@@ -29,6 +30,7 @@ class SurveyCubit extends Cubit<SurveyState> {
QuestionAnswer? answer,
CallbackType callbackType, {
required bool saveAnswer,
OnFinishCallback? onFinish,
}) {
if (state is SurveyLoadedState) {
final loadedState = state as SurveyLoadedState;
@@ -41,10 +43,16 @@ class SurveyCubit extends Cubit<SurveyState> {
callback: callback,
callbackType: callbackType,
surveyController: surveyController,
onFinish: onFinish,
answers: loadedState.answers,
questions: loadedState.surveyData.questions,
saveAnswer: () => answer == null || !saveAnswer
? null
: _saveAnswer(index: questionIndex, answer: answer),
: _saveAnswer(
index: questionIndex,
answer: answer,
onFinish: onFinish,
),
).callbackFromType();
}
}
@@ -72,11 +80,18 @@ class SurveyCubit extends Cubit<SurveyState> {
}

/// Saves the provided [answer] for the question at the specified [index].
void _saveAnswer({required int index, required QuestionAnswer answer}) {
void _saveAnswer({
required int index,
required QuestionAnswer answer,
OnFinishCallback? onFinish,
}) {
final currentState = state;
if (currentState is SurveyLoadedState) {
final newAnswers = Map<int, QuestionAnswer>.of(currentState.answers);
newAnswers[index] = answer;
if (index == currentState.surveyData.questions.length) {
onFinish?.call(newAnswers);
}
emit(currentState.copyWith(answers: newAnswers));
}
}
3 changes: 3 additions & 0 deletions core/lib/src/presentation/utils/on_finish_callback.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import 'package:survey_sdk/src/domain/entities/question_answer.dart';

typedef OnFinishCallback = void Function(Map<int, QuestionAnswer> answers);
13 changes: 11 additions & 2 deletions core/lib/src/presentation/utils/survey_button_callback.dart
Original file line number Diff line number Diff line change
@@ -5,24 +5,33 @@ import 'package:survey_sdk/src/domain/entities/actions/go_next_action.dart';
import 'package:survey_sdk/src/domain/entities/actions/go_to_action.dart';
import 'package:survey_sdk/src/domain/entities/actions/skip_question_action.dart';
import 'package:survey_sdk/src/domain/entities/actions/survey_action.dart';
import 'package:survey_sdk/src/domain/entities/question_answer.dart';
import 'package:survey_sdk/src/domain/entities/question_types/question_data.dart';
import 'package:survey_sdk/src/presentation/survey/survey_controller.dart';
import 'package:survey_sdk/src/presentation/utils/callback_type.dart';
import 'package:survey_sdk/src/presentation/utils/on_finish_callback.dart';

class SurveyButtonCallback {
final SurveyAction? callback;
final VoidCallback? saveAnswer;
final SurveyController surveyController;
final List<QuestionData> questions;
final OnFinishCallback? onFinish;
final CallbackType callbackType;
final Map<int, QuestionAnswer>? answers;

SurveyButtonCallback({
required this.callback,
required this.saveAnswer,
required this.surveyController,
required this.questions,
required this.callbackType,
});
this.answers,
this.onFinish,
}) : assert(
onFinish != null && answers != null || onFinish == null,
'If onFinish != null answers should not be null either',
);

void callbackFromType() => switch (callback.runtimeType) {
GoToAction => goToCallback(),
@@ -33,7 +42,6 @@ class SurveyButtonCallback {
_ => defaultSurveyCallback(),
};


@visibleForTesting
void goToCallback() {
saveAnswer?.call();
@@ -43,6 +51,7 @@ class SurveyButtonCallback {
@visibleForTesting
void finishSurveyCallback() {
saveAnswer?.call();
onFinish?.call(answers!);
surveyController.animateTo(questions.length);
}