|
|
@@ -0,0 +1,250 @@
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
+import 'package:keyboard/base/base_page.dart';
|
|
|
+import 'package:keyboard/resource/colors.gen.dart';
|
|
|
+import 'package:keyboard/resource/string.gen.dart';
|
|
|
+import 'package:keyboard/router/app_pages.dart';
|
|
|
+import 'package:lottie/lottie.dart';
|
|
|
+
|
|
|
+import '../../resource/assets.gen.dart';
|
|
|
+import '../../utils/status_bar_util.dart';
|
|
|
+import '../../widget/app_lifecycle_widget.dart';
|
|
|
+import '../../widget/gradient_btn.dart';
|
|
|
+import 'keyboard_tutorial_controller.dart';
|
|
|
+
|
|
|
+/// 键盘使用教程-引导页
|
|
|
+class KeyboardTutorialPage extends BasePage<KeyboardTutorialController> {
|
|
|
+ const KeyboardTutorialPage({super.key});
|
|
|
+
|
|
|
+ static start() {
|
|
|
+ Get.toNamed(RoutePath.keyboardTutorial);
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ bool immersive() {
|
|
|
+ // 开启沉浸式
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ backgroundColor() {
|
|
|
+ return Color(0xFFF6F5FA);
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget buildBody(BuildContext context) {
|
|
|
+ return Scaffold(
|
|
|
+ backgroundColor: backgroundColor(),
|
|
|
+ body: AppLifecycleWidget(
|
|
|
+ onAppLifecycleCallback: (isForeground) {
|
|
|
+ // 步骤都做完了,则跳转去键盘引导页
|
|
|
+ if (controller.checkHasComplete()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 未完成,则每次切换到前台时,重新检查设置,更新按钮状态
|
|
|
+ if (isForeground) {
|
|
|
+ controller.checkSetting();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ child: Stack(
|
|
|
+ children: [
|
|
|
+ // 头部
|
|
|
+ Positioned(left: 0, top: 0, right: 0, child: _buildHeader()),
|
|
|
+ // 状态栏和标题栏
|
|
|
+ Positioned(
|
|
|
+ left: 0,
|
|
|
+ top: 0,
|
|
|
+ right: 0,
|
|
|
+ child: Column(
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
+ children: [_buildStatusBar(), _buildTopBar()],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ // 内容,填充剩余部分
|
|
|
+ Positioned.fill(
|
|
|
+ top: 235.h + StatusBarUtil.getStatusBarHeight(Get.context!),
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ child: Column(children: [_buildContent()]),
|
|
|
+ ),
|
|
|
+ // 底部按钮
|
|
|
+ Positioned(
|
|
|
+ left: 0,
|
|
|
+ right: 0,
|
|
|
+ bottom: 0,
|
|
|
+ child: _buildBottomActionBtn(),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 导航栏占位
|
|
|
+ Widget _buildStatusBar() {
|
|
|
+ // 导航栏高度
|
|
|
+ double statusBarHeight = StatusBarUtil.getStatusBarHeight(Get.context!);
|
|
|
+ return Container(height: statusBarHeight);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 顶部栏
|
|
|
+ Widget _buildTopBar() {
|
|
|
+ return Container(
|
|
|
+ // 宽度撑满父组件
|
|
|
+ width: double.infinity,
|
|
|
+ height: kToolbarHeight,
|
|
|
+ // 背景颜色
|
|
|
+ color: Colors.transparent,
|
|
|
+ // padding: EdgeInsets.symmetric(horizontal: 16.0),
|
|
|
+ child: ConstrainedBox(
|
|
|
+ // 设置宽度为无限大,撑满父组件,否则Stack获取不到高度,会报错
|
|
|
+ constraints: BoxConstraints(minWidth: double.infinity),
|
|
|
+ child: Stack(
|
|
|
+ alignment: Alignment.center,
|
|
|
+ children: [
|
|
|
+ // 返回按钮
|
|
|
+ Positioned(
|
|
|
+ left: 16.w,
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: controller.clickBack,
|
|
|
+ child: Assets.images.iconBlackBackArrow.image(
|
|
|
+ width: 24.w,
|
|
|
+ height: 24.h,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ // 跳过按钮
|
|
|
+ Positioned(
|
|
|
+ right: 16.w,
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.clickSkip();
|
|
|
+ },
|
|
|
+ child: Text(
|
|
|
+ StringName.skip,
|
|
|
+ style: TextStyle(
|
|
|
+ color: ColorName.black85,
|
|
|
+ fontSize: 14.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 头部布局
|
|
|
+ Widget _buildHeader() {
|
|
|
+ return SizedBox(
|
|
|
+ width: double.infinity,
|
|
|
+ height: 298.h,
|
|
|
+ child: Stack(
|
|
|
+ alignment: Alignment.center,
|
|
|
+ children: [
|
|
|
+ // 头像
|
|
|
+ Positioned(
|
|
|
+ top: 37.5.h,
|
|
|
+ bottom: 86.5.h,
|
|
|
+ child: Assets.images.iconKeyboardTutorialHeader.image(
|
|
|
+ height: 174.h,
|
|
|
+ fit: BoxFit.cover,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ // 蒙版
|
|
|
+ Assets.images.bgKeyboardTutorialHeaderMask.image(
|
|
|
+ width: double.infinity,
|
|
|
+ height: double.infinity,
|
|
|
+ ),
|
|
|
+ // 提示语
|
|
|
+ Positioned(
|
|
|
+ bottom: 60.h,
|
|
|
+ child: Assets.images.iconKeyboardTutorialHeaderSlogan.image(
|
|
|
+ width: 200.w,
|
|
|
+ height: 73.h,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 内容
|
|
|
+ Widget _buildContent() {
|
|
|
+ return Expanded(child: Column(children: [_buildTutorialAnimation()]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 键盘设置引导动画
|
|
|
+ Widget _buildTutorialAnimation() {
|
|
|
+ return Lottie.asset(
|
|
|
+ Assets.anim.animKeyboardTutorialSetting,
|
|
|
+ repeat: true,
|
|
|
+ width: 340.w,
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 启用键盘按钮
|
|
|
+ Widget _buildEnableKeyboard() {
|
|
|
+ return Obx(() {
|
|
|
+ return Container(
|
|
|
+ margin: EdgeInsets.symmetric(horizontal: 50.w),
|
|
|
+ child: GradientTextBtn(
|
|
|
+ // 是否启用,这里UI设计上,未启用时要高亮按钮,所以要取反
|
|
|
+ enable: !controller.isKeyboardEnable.value,
|
|
|
+ StringName.tutorialEnableKeyboardStep,
|
|
|
+ onPressed: () {
|
|
|
+ // 已启用,不响应点击
|
|
|
+ if (controller.isKeyboardEnable.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 去启用键盘
|
|
|
+ controller.goEnableKeyboard();
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 悬浮球设置按钮
|
|
|
+ Widget _buildFloatingBallActionBtn() {
|
|
|
+ return Obx(() {
|
|
|
+ bool isKeyboardEnable = controller.isKeyboardEnable.value;
|
|
|
+ bool isFloatingWindowEnable = controller.isFloatingWindowEnable.value;
|
|
|
+ // 启用了键盘,但悬浮窗权限未获取到,则高亮按钮
|
|
|
+ bool isHighlightBtn = isKeyboardEnable && !isFloatingWindowEnable;
|
|
|
+ return Container(
|
|
|
+ margin: EdgeInsets.symmetric(horizontal: 50.w),
|
|
|
+ child: GradientTextBtn(
|
|
|
+ enable: isHighlightBtn,
|
|
|
+ StringName.tutorialEnableFloatingBallStep,
|
|
|
+ onPressed: () {
|
|
|
+ // 已获取,不响应点击
|
|
|
+ if (controller.isFloatingWindowEnable.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 去启用悬浮球
|
|
|
+ controller.jumpFloatingWindowSetting();
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 底部操作按钮
|
|
|
+ Widget _buildBottomActionBtn() {
|
|
|
+ return Column(
|
|
|
+ children: [
|
|
|
+ // 启用键盘
|
|
|
+ _buildEnableKeyboard(),
|
|
|
+ SizedBox(height: 20.h),
|
|
|
+ // 启用悬浮球
|
|
|
+ _buildFloatingBallActionBtn(),
|
|
|
+ // 距离底部一定距离
|
|
|
+ SizedBox(height: 25.h),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|