新增决定了问答页面

This commit is contained in:
tanghong668 2023-12-02 00:45:45 +08:00
parent 9f27eda256
commit 5cade2cffa
14 changed files with 436 additions and 27 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -4,3 +4,4 @@ export 'base_response_model.dart';
export 'token_model.dart'; export 'token_model.dart';
export 'page_result_model.dart'; export 'page_result_model.dart';
export 'goal_model.dart'; export 'goal_model.dart';
export 'question_answer_model.dart';

View File

@ -1,11 +1,10 @@
// ignore_for_file: unnecessary_overrides // ignore_for_file: unnecessary_overrides
import 'dart:async'; import 'dart:async';
import 'package:dreampad/app/models/models.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../models/question_answer_model.dart';
class QuestionController extends GetxController { class QuestionController extends GetxController {
final step = 0.obs; final step = 0.obs;
final ipLeft = 149.obs; final ipLeft = 149.obs;

View File

@ -1,8 +1,10 @@
// ignore_for_file: unnecessary_overrides // ignore_for_file: unnecessary_overrides
import 'package:dreampad/app/models/models.dart';
import 'package:dreampad/app/routes/app_pages.dart'; import 'package:dreampad/app/routes/app_pages.dart';
import 'package:dreampad/app/shared/shared.dart'; import 'package:dreampad/app/shared/shared.dart';
import 'package:flustars_flutter3/flustars_flutter3.dart'; import 'package:flustars_flutter3/flustars_flutter3.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../models/occupation_model.dart'; import '../models/occupation_model.dart';
@ -11,11 +13,22 @@ class SelectController extends GetxController {
late int gender = 2; late int gender = 2;
late int count = 4; late int count = 4;
late int page = 0; late int page = 0;
final step = 0.obs;
final question = ''.obs;
final guide = ''.obs;
final btnTxt = '我要回答'.obs;
final allAnswer = false.obs;
final showQuestionDialog = false.obs;
late List<Occupation> occupations = []; late List<Occupation> occupations = [];
final confirm = false.obs; final confirm = false.obs;
final confirmTitle = '为你推荐的梦想职业是'.obs; final confirmTitle = '为你推荐的梦想职业是'.obs;
final recommend = false.obs;
final showBtn = false.obs;
final showOccupationName = false.obs;
final selectOccupation = Rx<Occupation?>(null); final selectOccupation = Rx<Occupation?>(null);
final selectOccupations = RxList<Rx<Occupation>>([]); final selectOccupations = RxList<Rx<Occupation>>([]);
final questionAnswers = RxList<Rx<QuestionAnswer>>([]);
final TextEditingController textController = TextEditingController();
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -26,6 +39,24 @@ class SelectController extends GetxController {
initMaleOccupation(); initMaleOccupation();
} }
changeOccupation(); changeOccupation();
questionAnswers.add(QuestionAnswer(
index: 1,
left: 110.0,
top: 147.0,
question: '很酷的选择!能告诉我为什么选择这个梦想的职业吗?',
display: false,
answer: '',
guide: '我想成为下一个“爱因斯坦”,他被称为最聪明的人',
).obs);
questionAnswers.add(QuestionAnswer(
index: 2,
left: 720.0,
top: 425.0,
question: '还有很多选择也非常精彩哦!你还有其他想选择的职业吗?',
display: false,
answer: '',
guide: '我只想做科学家',
).obs);
} }
@override @override
@ -208,8 +239,18 @@ class SelectController extends GetxController {
} }
} }
Future confimSelected() async {
confirm.value = true;
recommend.value = false;
confirmTitle.value = '你的梦想职业是';
showOccupationName.value = true;
await Future.delayed(const Duration(milliseconds: 1000));
showOccupationName.value = false;
}
Future selectedOccupation(Occupation occupation) async { Future selectedOccupation(Occupation occupation) async {
selectOccupation.value = occupation; selectOccupation.value = occupation;
await setStep();
for (var occupation in selectOccupations) { for (var occupation in selectOccupations) {
occupation.update((val) { occupation.update((val) {
val!.selected = false; val!.selected = false;
@ -221,6 +262,7 @@ class SelectController extends GetxController {
var occupation = selectOccupations.firstWhere((t) => t.value.id == id); var occupation = selectOccupations.firstWhere((t) => t.value.id == id);
selectOccupation.value = occupation.value; selectOccupation.value = occupation.value;
confirm.value = true; confirm.value = true;
recommend.value = true;
for (var occupation in selectOccupations) { for (var occupation in selectOccupations) {
occupation.update((val) { occupation.update((val) {
val!.selected = false; val!.selected = false;
@ -228,6 +270,63 @@ class SelectController extends GetxController {
} }
} }
Future setStep() async {
btnTxt.value = '我要回答';
bool hasQuestion = false;
for (var questionAnswer in questionAnswers) {
if (!questionAnswer.value.display!) {
if (questionAnswer.value.index != step.value) {
showQuestionDialog.value = false;
} else {
showQuestionDialog.value = true;
}
step.value = questionAnswer.value.index!;
question.value = questionAnswer.value.question!;
guide.value = questionAnswer.value.guide;
hasQuestion = true;
allAnswer.value = false;
break;
}
}
if (!hasQuestion) {
showQuestionDialog.value = false;
allAnswer.value = true;
}
}
Future updateAnswer(String answer) async {
var questionAnswer =
questionAnswers.firstWhere((t) => t.value.index == step.value);
questionAnswer.update((val) {
val!.answer = answer;
val.display = true;
});
await setStep();
textController.text = '';
if (allAnswer.value) {
await Future.delayed(const Duration(milliseconds: 1000));
for (var questionAnswer in questionAnswers) {
questionAnswer.update((val) {
val!.display = false;
});
}
showBtn.value = true;
showOccupationName.value = true;
}
}
Future reflect() async {
confirm.value = false;
for (var questionAnswer in questionAnswers) {
questionAnswer.update((val) {
val!.display = false;
});
}
showBtn.value = false;
allAnswer.value = false;
showOccupationName.value = false;
}
Future openDream() async { Future openDream() async {
SpUtil.putString(Constant.occupationName, selectOccupation.value!.name!); SpUtil.putString(Constant.occupationName, selectOccupation.value!.name!);
SpUtil.putInt(Constant.occupationId, selectOccupation.value!.id!); SpUtil.putInt(Constant.occupationId, selectOccupation.value!.id!);

View File

@ -1,3 +1,4 @@
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:dreampad/app/modules/select/views/animated_horizon_column_widget.dart'; import 'package:dreampad/app/modules/select/views/animated_horizon_column_widget.dart';
import 'package:dreampad/app/routes/app_pages.dart'; import 'package:dreampad/app/routes/app_pages.dart';
import 'package:dreampad/app/shared/shared.dart'; import 'package:dreampad/app/shared/shared.dart';
@ -82,8 +83,10 @@ class SelectView extends GetView<SelectController> {
() => AnimatedSwitcher( () => AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: OccupationListWidget( child: OccupationListWidget(
key: ValueKey(controller.selectOccupations.first.value.name ?? ''), key: ValueKey(
keyBuilder: (index) => controller.selectOccupations[index].value.name ?? '', controller.selectOccupations.first.value.name ?? ''),
keyBuilder: (index) =>
controller.selectOccupations[index].value.name ?? '',
children: controller.selectOccupations.map((t) { children: controller.selectOccupations.map((t) {
return GestureDetector( return GestureDetector(
key: ValueKey(t.value.id), key: ValueKey(t.value.id),
@ -190,20 +193,19 @@ class SelectView extends GetView<SelectController> {
), ),
), ),
const RSizedBox(width: 34.0), const RSizedBox(width: 34.0),
AnimatedVisibilityWidget( AnimatedVisibilityWidget(
isVisible: controller.selectOccupation.value != null, isVisible: controller.selectOccupation.value != null,
child: ImageTxtButton( child: ImageTxtButton(
text: '决定了', text: '决定了',
imgName: 'select/btn_icon_confirm', imgName: 'select/btn_icon_confirm',
textStyle: TextStyles.mediumWhiteShadow28_022, textStyle: TextStyles.mediumWhiteShadow28_022,
width: 264.0, width: 264.0,
height: 80.0, height: 80.0,
onPressed: () { onPressed: () async {
controller.confirm.value = true; controller.confimSelected();
controller.confirmTitle.value = '你的梦想职业是'; },
}, ),
), ),
),
], ],
), ),
); );
@ -285,14 +287,60 @@ class SelectView extends GetView<SelectController> {
), ),
), ),
), ),
buildConfirmBtn(context, controller.selectOccupation.value!.name!), controller.recommend.value
? buildRecommendConfirmBtn(
context, controller.selectOccupation.value!.name!)
: buildConfirmBtn(
context, controller.selectOccupation.value!.name!),
controller.showOccupationName.value
? Container()
: Positioned(
left: 90.w,
top: 62.h,
child: Container(
width: 999.w,
height: 558.h,
color: const Color(0x8C02184B),
),
),
RSizedBox(
child: Stack(
children: controller.questionAnswers.map((element) {
if (element.value.display!) {
return Positioned(
top: element.value.top!.h,
left: element.value.left!.w,
child: _ShowUp(
key: ValueKey(element.value.answer),
child: buildAnswer(
context,
element.value.index!,
element.value.answer!,
),
),
);
} else {
return Container();
}
}).toList()),
),
Positioned(
top: 207.h,
left: 378.w,
child: AnimatedVisibilityWidget(
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
isVisible: !controller.allAnswer.value &&
!controller.showOccupationName.value,
child: buildDialog(context)),
),
], ],
), ),
), ),
); );
} }
Widget buildConfirmBtn(BuildContext context, String name) { Widget buildRecommendConfirmBtn(BuildContext context, String name) {
return Positioned( return Positioned(
bottom: 12.h, bottom: 12.h,
left: 243.w, left: 243.w,
@ -380,10 +428,246 @@ class SelectView extends GetView<SelectController> {
), ),
); );
} }
Widget buildConfirmBtn(BuildContext context, String name) {
return Positioned(
bottom: 18.h,
left: 243.w,
child: Container(
width: 713.w,
height: 214.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectBgShadow,
fit: BoxFit.fill,
),
),
child: Obx(
() => Stack(
children: [
controller.showBtn.value
? Positioned(
left: 88.w,
top: 77.h,
child: ImageTxtButton(
text: '我再想想',
imgName: 'select/btn_bg_reflect_1',
textStyle: TextStyles.mediumWhiteShadow28_013,
width: 264.0,
height: 80.0,
onPressed: () async {
await controller.reflect();
},
),
)
: Container(),
controller.showBtn.value
? Positioned(
right: 66.w,
top: 77.h,
child: ImageTxtButton(
text: '生成梦之建木',
imgName: 'select/btn_bg_generate_1',
textStyle: TextStyles.mediumWhiteShadow28_013,
width: 264.0,
height: 80.0,
onPressed: () async {
await controller.openDream();
},
),
)
: Container(),
controller.showOccupationName.value
? Positioned(
left: 208.w,
top: 19.h,
child: ImageTxtButton(
text: name,
imgName: 'select/label_bg_career_1',
textStyle: TextStyles.mediumWhiteShadow28_113,
width: 324.0,
height: 45.0,
),
)
: Container(),
],
),
),
),
);
}
Widget buildAnswer(BuildContext context, int index, String answer) {
return Container(
width: 369.w,
height: 160.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectAnswer,
fit: BoxFit.fill,
),
),
child: Stack(
children: [
Positioned(
top: 23.h,
left: 68.w,
child: Text(
index.toString(),
style: TextStyles.boldColor24,
),
),
Positioned(
top: 25.h,
left: 105.w,
child: Text(
'问题回答',
style: TextStyles.boldColor20,
),
),
Positioned(
top: 65.h,
left: 85.w,
child: RSizedBox(
height: 64.h,
width: 230.w,
child: Text(
answer,
style: TextStyles.mediumWhite18,
),
),
),
],
),
);
}
Widget buildDialog(BuildContext context) {
return Obx(
() => AnimatedSwitcher(
duration: const Duration(milliseconds: 500),
child: KeyedSubtree(
key: ValueKey(controller.question.value),
child: HookBuilder(builder: (context) {
final isReady = useState(false);
final isDialogShown = useState(false);
final isTextShown = useState(false);
useMemoized(() async {
await Future.delayed(const Duration(milliseconds: 500));
isReady.value = true;
});
return AnimatedVisibilityWidget(
isVisible: isReady.value,
isInitAnimated: true,
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
duration: const Duration(milliseconds: 500),
onDone: (_) async {
await Future.delayed(const Duration(milliseconds: 500));
isDialogShown.value = true;
},
child: Container(
width: 444.w,
height: 248.h,
decoration: const BoxDecoration(
image: DecorationImage(
image: Images.selectDialog,
fit: BoxFit.fill,
),
),
padding: REdgeInsets.only(top: 28.0, left: 27.0, right: 63.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: SizedBox(
width: double.infinity,
child: Visibility(
visible: isDialogShown.value,
child: AnimatedTextKit(
totalRepeatCount: 1,
pause: Duration.zero,
onFinished: () {
isTextShown.value = true;
},
animatedTexts: [
TypewriterAnimatedText(
controller.question.value,
textStyle: TextStyles.mediumWhiteShadow18_034,
cursor: '',
speed: const Duration(milliseconds: 150),
textAlign: TextAlign.start,
)
],
),
),
),
),
SizedBox(height: 16.h),
AnimatedVisibilityWidget(
isVisible: isTextShown.value,
animationWidgetBuilder:
AnimatedVisibilityWidget.fadeAnimationWidgetBuilder,
child: ImageTxtButton(
text: controller.btnTxt.value,
imgName: 'question/btn_icon_begin',
textStyle: TextStyles.boldWhite20_014,
width: 186.0,
height: 54.0,
onPressed: () async {
await controller.setStep();
if (controller.showQuestionDialog.value) {
SmartDialog.show(
alignment: Alignment.topCenter,
onDismiss: () async {
FocusScope.of(context).requestFocus();
if (controller.textController.text.isNotEmpty) {
await controller.updateAnswer(
controller.textController.text);
}
},
maskColor:
const Color(0xFF080F3D).withOpacity(0.8),
builder: (_) {
return HookBuilder(builder: (context) {
useMemoized(() async {
final guide = controller.guide.value;
for (int i = 0; i < guide.length + 1; i++) {
controller.textController.text =
guide.substring(0, i);
await Future.delayed(
const Duration(milliseconds: 80));
}
});
return QuestionDialog(
question: controller.question.value,
controller: controller.textController,
);
});
},
);
}
},
),
),
const RSizedBox(
height: 64,
),
],
),
),
);
}),
),
),
);
}
} }
class _ShowUp extends HookWidget { class _ShowUp extends HookWidget {
const _ShowUp({ const _ShowUp({
super.key,
required this.child, required this.child,
}); });
@ -392,16 +676,13 @@ class _ShowUp extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final controller = final controller =
useAnimationController(duration: const Duration(milliseconds: 300)); useAnimationController(duration: const Duration(milliseconds: 300));
useMemoized(() async { useMemoized(() async {
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
controller.forward(); controller.forward();
}); });
return FadeTransition( return FadeTransition(
opacity: CurvedAnimation( opacity: CurvedAnimation(curve: Curves.easeIn, parent: controller),
curve: Curves.easeIn,
parent: controller
),
child: child, child: child,
); );
} }

View File

@ -18,7 +18,7 @@ part 'app_routes.dart';
class AppPages { class AppPages {
AppPages._(); AppPages._();
static const INITIAL = Routes.HOME; static const INITIAL = Routes.SELECT;
static final routes = [ static final routes = [
GetPage( GetPage(

View File

@ -369,6 +369,10 @@ class Images {
AssetImage("assets/images/select/btn_bg_generate.png"); AssetImage("assets/images/select/btn_bg_generate.png");
static const AssetImage selectBgCareer = static const AssetImage selectBgCareer =
AssetImage("assets/images/select/label_bg_career.png"); AssetImage("assets/images/select/label_bg_career.png");
static const AssetImage selectDialog =
AssetImage("assets/images/select/pic_dialogue_type.png");
static const AssetImage selectAnswer =
AssetImage("assets/images/select/label_bg_answer.png");
static const AssetImage questionBg = static const AssetImage questionBg =
AssetImage("assets/images/question/bg_pic_answer_page.png"); AssetImage("assets/images/question/bg_pic_answer_page.png");

View File

@ -95,6 +95,16 @@ class Shadows {
offset: Offset(1.w, 0.h), offset: Offset(1.w, 0.h),
blurRadius: 4.r, blurRadius: 4.r,
); );
static Shadow txtShadow113 = Shadow(
color: const Color(0xFF513892),
offset: Offset(1.w, 1.h),
blurRadius: 3.r,
);
static Shadow txtShadow013 = Shadow(
color: const Color(0xA30D0C0A),
offset: Offset(0.w, 1.h),
blurRadius: 3.r,
);
} }
class TextStyles { class TextStyles {
@ -121,6 +131,13 @@ class TextStyles {
shadows: [Shadows.txtShadow022], shadows: [Shadows.txtShadow022],
); );
static TextStyle mediumWhiteShadow28_013 = TextStyle(
fontSize: Dimens.font_sp28.sp,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: [Shadows.txtShadow013],
);
static TextStyle mediumWhiteShadow26_034 = TextStyle( static TextStyle mediumWhiteShadow26_034 = TextStyle(
fontSize: Dimens.font_sp26.sp, fontSize: Dimens.font_sp26.sp,
color: Colors.white, color: Colors.white,
@ -218,6 +235,14 @@ class TextStyles {
shadows: [Shadows.txtShadow100], shadows: [Shadows.txtShadow100],
); );
static TextStyle mediumWhiteShadow28_113 = TextStyle(
fontSize: Dimens.font_sp28.sp,
fontFamily: 'alph-b',
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: [Shadows.txtShadow113],
);
static TextStyle boldWhiteShadow28_110 = TextStyle( static TextStyle boldWhiteShadow28_110 = TextStyle(
fontSize: Dimens.font_sp28.sp, fontSize: Dimens.font_sp28.sp,
fontFamily: 'alph-b', fontFamily: 'alph-b',