keyboard_tutorial_page.dart 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter_screenutil/flutter_screenutil.dart';
  3. import 'package:get/get.dart';
  4. import 'package:keyboard/base/base_page.dart';
  5. import 'package:keyboard/resource/colors.gen.dart';
  6. import 'package:keyboard/resource/string.gen.dart';
  7. import 'package:keyboard/router/app_pages.dart';
  8. import 'package:lottie/lottie.dart';
  9. import '../../resource/assets.gen.dart';
  10. import '../../utils/status_bar_util.dart';
  11. import '../../widget/app_lifecycle_widget.dart';
  12. import '../../widget/gradient_btn.dart';
  13. import '../../widget/top_bar.dart';
  14. import 'keyboard_tutorial_controller.dart';
  15. /// 键盘使用教程-引导页
  16. class KeyboardTutorialPage extends BasePage<KeyboardTutorialController> {
  17. const KeyboardTutorialPage({super.key});
  18. static start() {
  19. Get.toNamed(RoutePath.keyboardTutorial);
  20. }
  21. /// 跳转并关闭当前页
  22. static void startAndOffMe() {
  23. Get.offNamed(RoutePath.keyboardTutorial);
  24. }
  25. @override
  26. bool immersive() {
  27. // 开启沉浸式
  28. return true;
  29. }
  30. @override
  31. backgroundColor() {
  32. return Color(0xFFF6F5FA);
  33. }
  34. @override
  35. Widget buildBody(BuildContext context) {
  36. return Scaffold(
  37. backgroundColor: backgroundColor(),
  38. body: AppLifecycleWidget(
  39. onAppLifecycleCallback: (isForeground) async {
  40. // 步骤都做完了,则跳转去键盘引导页
  41. if (await controller.checkHasComplete()) {
  42. return;
  43. }
  44. // 未完成,则每次切换到前台时,重新检查设置,更新按钮状态
  45. if (isForeground) {
  46. controller.checkSetting();
  47. }
  48. },
  49. child: Stack(
  50. children: [
  51. // 头部
  52. Positioned(left: 0, top: 0, right: 0, child: _buildHeader(context)),
  53. // 状态栏和标题栏
  54. Positioned(
  55. left: 0,
  56. top: 0,
  57. right: 0,
  58. child: Column(
  59. mainAxisSize: MainAxisSize.min,
  60. children: [_buildStatusBar(), _buildTopBar()],
  61. ),
  62. ),
  63. // 内容,填充剩余部分
  64. Positioned.fill(
  65. top: 170.h + StatusBarUtil.getStatusBarHeight(Get.context!),
  66. left: 0,
  67. right: 0,
  68. child: Column(children: [_buildContent()]),
  69. ),
  70. // 底部按钮
  71. Positioned(
  72. left: 0,
  73. right: 0,
  74. bottom: 0,
  75. child: _buildBottomActionBtn(),
  76. ),
  77. ],
  78. ),
  79. ),
  80. );
  81. }
  82. /// 导航栏占位
  83. Widget _buildStatusBar() {
  84. // 导航栏高度
  85. double statusBarHeight = StatusBarUtil.getStatusBarHeight(Get.context!);
  86. return Container(height: statusBarHeight);
  87. }
  88. /// 顶部栏
  89. Widget _buildTopBar() {
  90. return TopBar(
  91. leftWidget: GestureDetector(
  92. onTap: controller.clickBack,
  93. child: Assets.images.iconBlackBackArrow.image(
  94. width: 24.w,
  95. height: 24.h,
  96. ),
  97. ),
  98. rightWidget: // 视频教程按钮
  99. Positioned(
  100. right: 16.w,
  101. child: Visibility(
  102. visible: true,
  103. child: GestureDetector(
  104. onTap: () {
  105. controller.clickTutorialVideo();
  106. },
  107. child: Text(
  108. StringName.keyboardTutorialVideo,
  109. style: TextStyle(
  110. color: ColorName.black85,
  111. fontSize: 14.sp,
  112. fontWeight: FontWeight.w500,
  113. ),
  114. ),
  115. ),
  116. ),
  117. ),
  118. );
  119. }
  120. /// 头部布局
  121. Widget _buildHeader(BuildContext context) {
  122. return SizedBox(
  123. width: double.infinity,
  124. height: 298.h,
  125. child: Stack(
  126. alignment: Alignment.center,
  127. children: [
  128. // 头像
  129. Positioned(
  130. top: 37.5.h,
  131. bottom: 86.5.h,
  132. child: Assets.images.iconKeyboardTutorialHeader.image(
  133. height: 174.h,
  134. fit: BoxFit.cover,
  135. ),
  136. ),
  137. // 蒙版
  138. Assets.images.bgKeyboardTutorialHeaderMask.image(
  139. width: double.infinity,
  140. height: double.infinity,
  141. ),
  142. // 提示语
  143. Positioned(
  144. top: 70.h + StatusBarUtil.getStatusBarHeight(context),
  145. child: Assets.images.iconKeyboardTutorialHeaderSlogan.image(
  146. width: 200.w,
  147. height: 73.h,
  148. ),
  149. ),
  150. ],
  151. ),
  152. );
  153. }
  154. /// 内容
  155. Widget _buildContent() {
  156. return Expanded(child: Column(children: [_buildTutorialAnimation()]));
  157. }
  158. /// 键盘设置引导动画
  159. Widget _buildTutorialAnimation() {
  160. return Lottie.asset(
  161. Assets.anim.animKeyboardTutorialSetting,
  162. repeat: true,
  163. width: 340.w,
  164. );
  165. }
  166. /// 启用键盘按钮
  167. Widget _buildEnableKeyboard() {
  168. return Obx(() {
  169. return Container(
  170. margin: EdgeInsets.symmetric(horizontal: 50.w),
  171. child: GradientTextBtn(
  172. // 是否启用,这里UI设计上,未启用时要高亮按钮,所以要取反
  173. enable: !controller.isKeyboardEnable.value,
  174. StringName.tutorialEnableKeyboardStep,
  175. onPressed: () {
  176. // 已启用,不响应点击
  177. if (controller.isKeyboardEnable.value) {
  178. return;
  179. }
  180. // 去启用键盘
  181. controller.goEnableKeyboard();
  182. },
  183. ),
  184. );
  185. });
  186. }
  187. /// 悬浮球设置按钮
  188. Widget _buildFloatingBallActionBtn() {
  189. return Obx(() {
  190. bool isKeyboardEnable = controller.isKeyboardEnable.value;
  191. bool isFloatingWindowEnable = controller.isFloatingWindowEnable.value;
  192. // 启用了键盘,但悬浮窗权限未获取到,则高亮按钮
  193. bool isHighlightBtn = isKeyboardEnable && !isFloatingWindowEnable;
  194. return Container(
  195. margin: EdgeInsets.symmetric(horizontal: 50.w),
  196. child: GradientTextBtn(
  197. enable: isHighlightBtn,
  198. StringName.tutorialEnableFloatingBallStep,
  199. onPressed: () {
  200. // 已获取,不响应点击
  201. if (controller.isFloatingWindowEnable.value) {
  202. return;
  203. }
  204. // 去启用悬浮球
  205. controller.jumpFloatingWindowSetting();
  206. },
  207. ),
  208. );
  209. });
  210. }
  211. /// 底部操作按钮
  212. Widget _buildBottomActionBtn() {
  213. return Column(
  214. children: [
  215. // 启用键盘
  216. _buildEnableKeyboard(),
  217. SizedBox(height: 20.h),
  218. // 启用悬浮球
  219. _buildFloatingBallActionBtn(),
  220. // 距离底部一定距离
  221. SizedBox(height: 25.h),
  222. ],
  223. );
  224. }
  225. }