Merge remote-tracking branch 'origin/yuanjunyao_dev' into yuanjunyao_dev

This commit is contained in:
yuanjunyao 2023-12-02 10:39:31 +08:00
commit d6ea57859c
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

@ -3,4 +3,5 @@ export 'user_model.dart';
export 'base_response_model.dart';
export 'token_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
import 'dart:async';
import 'package:dreampad/app/models/models.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../models/question_answer_model.dart';
class QuestionController extends GetxController {
final step = 0.obs;
final ipLeft = 149.obs;

View File

@ -1,8 +1,10 @@
// ignore_for_file: unnecessary_overrides
import 'package:dreampad/app/models/models.dart';
import 'package:dreampad/app/routes/app_pages.dart';
import 'package:dreampad/app/shared/shared.dart';
import 'package:flustars_flutter3/flustars_flutter3.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../models/occupation_model.dart';
@ -11,11 +13,22 @@ class SelectController extends GetxController {
late int gender = 2;
late int count = 4;
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 = [];
final confirm = false.obs;
final confirmTitle = '为你推荐的梦想职业是'.obs;
final recommend = false.obs;
final showBtn = false.obs;
final showOccupationName = false.obs;
final selectOccupation = Rx<Occupation?>(null);
final selectOccupations = RxList<Rx<Occupation>>([]);
final questionAnswers = RxList<Rx<QuestionAnswer>>([]);
final TextEditingController textController = TextEditingController();
@override
void onInit() {
super.onInit();
@ -26,6 +39,24 @@ class SelectController extends GetxController {
initMaleOccupation();
}
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
@ -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 {
selectOccupation.value = occupation;
await setStep();
for (var occupation in selectOccupations) {
occupation.update((val) {
val!.selected = false;
@ -221,6 +262,7 @@ class SelectController extends GetxController {
var occupation = selectOccupations.firstWhere((t) => t.value.id == id);
selectOccupation.value = occupation.value;
confirm.value = true;
recommend.value = true;
for (var occupation in selectOccupations) {
occupation.update((val) {
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 {
SpUtil.putString(Constant.occupationName, selectOccupation.value!.name!);
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/routes/app_pages.dart';
import 'package:dreampad/app/shared/shared.dart';
@ -82,8 +83,10 @@ class SelectView extends GetView<SelectController> {
() => AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: OccupationListWidget(
key: ValueKey(controller.selectOccupations.first.value.name ?? ''),
keyBuilder: (index) => controller.selectOccupations[index].value.name ?? '',
key: ValueKey(
controller.selectOccupations.first.value.name ?? ''),
keyBuilder: (index) =>
controller.selectOccupations[index].value.name ?? '',
children: controller.selectOccupations.map((t) {
return GestureDetector(
key: ValueKey(t.value.id),
@ -190,20 +193,19 @@ class SelectView extends GetView<SelectController> {
),
),
const RSizedBox(width: 34.0),
AnimatedVisibilityWidget(
isVisible: controller.selectOccupation.value != null,
child: ImageTxtButton(
text: '决定了',
imgName: 'select/btn_icon_confirm',
textStyle: TextStyles.mediumWhiteShadow28_022,
width: 264.0,
height: 80.0,
onPressed: () {
controller.confirm.value = true;
controller.confirmTitle.value = '你的梦想职业是';
},
),
),
AnimatedVisibilityWidget(
isVisible: controller.selectOccupation.value != null,
child: ImageTxtButton(
text: '决定了',
imgName: 'select/btn_icon_confirm',
textStyle: TextStyles.mediumWhiteShadow28_022,
width: 264.0,
height: 80.0,
onPressed: () async {
controller.confimSelected();
},
),
),
],
),
);
@ -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(
bottom: 12.h,
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 {
const _ShowUp({
super.key,
required this.child,
});
@ -392,16 +676,13 @@ class _ShowUp extends HookWidget {
@override
Widget build(BuildContext context) {
final controller =
useAnimationController(duration: const Duration(milliseconds: 300));
useAnimationController(duration: const Duration(milliseconds: 300));
useMemoized(() async {
await Future.delayed(const Duration(milliseconds: 300));
controller.forward();
});
return FadeTransition(
opacity: CurvedAnimation(
curve: Curves.easeIn,
parent: controller
),
opacity: CurvedAnimation(curve: Curves.easeIn, parent: controller),
child: child,
);
}

View File

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

View File

@ -369,6 +369,10 @@ class Images {
AssetImage("assets/images/select/btn_bg_generate.png");
static const AssetImage selectBgCareer =
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 =
AssetImage("assets/images/question/bg_pic_answer_page.png");

View File

@ -95,6 +95,16 @@ class Shadows {
offset: Offset(1.w, 0.h),
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 {
@ -121,6 +131,13 @@ class TextStyles {
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(
fontSize: Dimens.font_sp26.sp,
color: Colors.white,
@ -218,6 +235,14 @@ class TextStyles {
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(
fontSize: Dimens.font_sp28.sp,
fontFamily: 'alph-b',