import 'dart:io'; import 'dart:math'; import 'package:animated_widgets/animated_widgets.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get_it/get_it.dart'; import 'package:like_button/like_button.dart'; import 'package:sport/application.dart'; import 'package:sport/bean/game.dart'; import 'package:sport/game/sdk_parse.dart'; import 'package:sport/provider/bluetooth.dart'; import 'package:sport/services/app_subscription_state.dart'; import 'package:sport/widgets/dialog/alert_dialog.dart'; import 'package:sport/widgets/dialog/game_alert_dialog.dart'; import 'package:sport/widgets/image.dart'; import 'package:video_player/video_player.dart'; import 'package:visibility_detector/visibility_detector.dart'; import 'package:wakelock/wakelock.dart'; Map>> guideActionMap = { 0: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/b0e0ac59-e150-38d6-bd24-5bc1d83b0ece.mp4", }, { "name": "右踏步", "motion": [4], "video": "http://static.ouj.com/video/9ef77bac-2a6f-3aaa-8e8c-b0e7b7916624.mp4", }, { "name": "左踏步", "motion": [3], "video": "http://static.ouj.com/video/9b4706aa-3809-309e-84a4-040c498a2e15.mp4", }, { "name": "右踮脚", "motion": [5], "video": "http://static.ouj.com/video/64fab916-00ac-33fa-b8d0-cebf4c077f26.mp4", }, { "name": "左踮脚", "motion": [6], "video": "http://static.ouj.com/video/f1f49cfc-3fc5-37eb-a8ac-d8a1eee0bc11.mp4", }, ], 3: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/962d2d03-2a47-3418-bc1d-7b92afa29009.mp4", }, { "name": "原地跑", "motion": [1], "motion_type": 1, "video": "http://static.ouj.com/video/0c067c1d-a8ac-3e1b-9b5a-dda32abbdb1d.mp4", }, { "name": "左换道", "motion": [4], "video": "http://static.ouj.com/video/ee846e82-3829-3bf4-93ba-caf810aedb2b.mp4", }, { "name": "右换道", "motion": [5], "video": "http://static.ouj.com/video/4ab6498e-a3fc-3870-af06-8aeba3f97453.mp4", }, { "name": "跳跃", "motion": [2], "video": "http://static.ouj.com/video/299eb3d1-8d73-3ca1-80c2-8469ffc770fa.mp4", }, { "name": "下蹲", "motion": [3], "video": "http://static.ouj.com/video/47155e50-a14a-329e-8b33-b9d5d101f184.mp4", }, ], 1: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/18d5f02d-b397-3c1d-8604-ffa84005ed09.mp4", }, { "name": "原地踩", "motion": [12], "video": "http://static.ouj.com/video/ee05b628-63e6-30d1-9595-b1efbf71ebd8.mp4", "icon": "http://static.ouj.com/shoes/game/136e85575f574865a544a87c2ae24d9c.png", }, { "name": "左上踩", "motion": [8], "video": "http://static.ouj.com/video/4f4424f6-3819-3f70-b1db-3cb68f0b0261.mp4", "icon": "http://static.ouj.com/shoes/game/4e55b8819c9f4b2dbbad64db3cf20605.png", }, { "name": "左下踩", "motion": [9], "video": "http://static.ouj.com/video/f574233d-7580-35cb-81c5-0d29e716a83e.mp4", "icon": "http://static.ouj.com/shoes/game/b332785b77244bc59ea67b9b76ae11b3.png", }, { "name": "右上踩", "motion": [10], "video": "http://static.ouj.com/video/c05c97fc-218b-32ae-a595-4aa4dcd5b713.mp4", "icon": "http://static.ouj.com/shoes/game/a181082b58cf49aca6a73a02d7196d3e.png", }, { "name": "右下踩", "motion": [11], "video": "http://static.ouj.com/video/617a5dfc-f3cc-3d06-896d-4907f4b1123b.mp4", "icon": "http://static.ouj.com/shoes/game/5d210d906bef4fc68b51dbb648449229.png", }, ], 10: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/26b2a19e-8c13-31e9-9eeb-186f346114cf.mp4", }, { "name": "左右踩", "motion": [4, 5], "video": "http://static.ouj.com/video/ad852e3a-37a7-3bf1-8055-009bfd25afea.mp4", }, { "name": "跳跃", "motion": [2], "video": "http://static.ouj.com/video/02fdb193-18bc-3a59-8871-57d92b935306.mp4", }, { "name": "下蹲", "motion": [3], "video": "http://static.ouj.com/video/cf2a28dc-56b6-37dd-8523-8b133a43709f.mp4", }, ], 9: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/ce0096d5-6d43-3dbd-9b39-51921a3a5ba8.mp4", }, { "name": "原地跑", "motion": [1], "motion_type": 1, "video": "http://static.ouj.com/video/fa1ae69f-b753-31dc-b7db-d694370ccdbe.mp4", }, { "name": "跳跃", "motion": [2], "video": "http://static.ouj.com/video/52e9b690-6a08-3ca4-9b1d-cad322ab0561.mp4", }, ], // 2: [ // { // "name": "原地跑", // "motion": [1] // }, // { // "name": "向左转", // "motion": [-1] // }, // { // "name": "向右转", // "motion": [-2] // }, // { // "name": "跳跃", // "motion": [14] // }, // ], 22: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/05084300-0ddb-384a-9d7d-d5b3679f1114.mp4", }, { "name": "石头", "motion": [15], "video": "http://static.ouj.com/video/05a7b15c-d94b-340d-a503-2fe39f03381d.mp4", }, { "name": "剪刀", "motion": [16], "video": "http://static.ouj.com/video/aa864f5d-cd35-3727-a6eb-6b63012fdcc1.mp4", }, { "name": "布", "motion": [17], "video": "http://static.ouj.com/video/7f5fc141-bc96-3ba1-a453-b8686d3565cf.mp4", }, ], 33: [ { "name": "开始", "motion": [], "video": "http://static.ouj.com/video/3155330b-1bc7-3cfe-af21-8efbfc1da7c9.mp4", }, { "name": "高抬腿", "motion": [19, 21], "video": "http://static.ouj.com/video/ca4819b4-e66b-3a62-84a1-28e3b9a8cc37.mp4", "icon": "http://static.ouj.com/shoes/game/02d3a2fb8f0045f9ae608a163a30a83f.png", }, { "name": "前踢脚", "motion": [22, 23], "video": "http://static.ouj.com/video/73c99824-0ee2-3d70-8695-fc4e8eaf9f5d.mp4", "icon": "http://static.ouj.com/shoes/game/03a39e4a51334fde8cd7ccfa14ad3ac3.png", }, { "name": "侧踢脚", "motion": [18, 20], "video": "http://static.ouj.com/video/be2841b0-7a08-3e18-8fd6-d4b0d623985f.mp4", "icon": "http://static.ouj.com/shoes/game/6cdb79103367417ba7fad82585900327.png", }, { "name": "下蹲", "motion": [3], "video": "http://static.ouj.com/video/85a16233-e70b-37ee-a584-10be044bba8c.mp4", "icon": "http://static.ouj.com/shoes/game/20d94a43b2cd4404b23bdda556d75ea2.png", }, ], }; class GameGuide extends StatefulWidget { final GameInfoData game; final bool base; final bool launch4GameCenter; final bool detailGuide; const GameGuide({Key? key, required this.game, this.base = false, this.launch4GameCenter = false, this.detailGuide = false}) : super(key: key); @override State createState() { return _GameGuideState(); } } class _GameGuideState extends State with SubscriptionState { late Bluetooth _bluetooth; late SDKApi _sdk; VideoPlayerController? _videoPlayerController; int _videoIndex = 0; bool _topBar = true; int _topBarTime = 0; bool _videoReady = false; bool _videoFirst = false; bool _motionFinished = false; bool _motionFinishedUi = false; int _finishTimes = 0; int _videoTime = 0; int _motionStep = 0; int _motionTime = 0; Set motionList = Set(); late List> actions; late int gameId; GlobalKey dialogKey = GlobalKey(); List> _motionKey = [GlobalKey(), GlobalKey(), GlobalKey()]; @override void initState() { super.initState(); gameId = widget.base ? 0 : widget.game.id; actions = List>.from(guideActionMap[gameId] ?? []).map((e) { e["a"] = false; e["test"] = 0; e["finish"] = false; if (e["motion_type"] == 1) { e["motion_progress"] = 0; } return e; }).toList(); _bluetooth = GetIt.I(); _sdk = _bluetooth.gameSDK(); _bluetooth.gameInit(widget.game.gameType ?? 0); _bluetooth.setupGameMode4h5(true); addSubscription(_bluetooth.sdkCmdStream.listen((event) { int cmd = event; if (widget.base != true) { State? dialogState = dialogKey.currentState; if (dialogState is CustomGameAlertDialogState) { dialogState.postCmd(cmd); } else { if (cmd == 6) { _back(); } if (cmd == 5) { _ok(); } } if (cmd == 6) { _bluetooth.vibrate(200, leftOrRight: 1); } if (cmd == 5) { _bluetooth.vibrate(200, leftOrRight: 2); } } else { if (_videoIndex == -1) return; if (_addMotion(cmd)) { setState(() {}); } } })); addSubscription(_bluetooth.dataStream.listen((event) { if (_videoIndex == -1) return; bool mm = false; if (widget.base != true) { List result = _sdk.getMotion(); mm = _addMotion(1); int attX = _sdk.getAttX(); double angle = attX / 10000.0 * 180 / (pi); if (mm != true && angle > 30) { mm = _addMotion(-1); } if (mm != true && angle < -30) { mm = _addMotion(-1); } if (mm != true) { if (result.any((element) => element > 0)) { for (var i = 0; i < result.length; i++) { if (result[i] > 0) { mm = _addMotion(result[i]); } } } } } if (mm == true) { setState(() { // _motion(); }); } })); var start = DateTime.now(); _initVideo(0).then((value) async { int end = 3000 - DateTime.now().difference(start).inMilliseconds; if (end > 0) await Future.delayed(Duration(milliseconds: end)); if (!mounted) return; setState(() { _videoReady = value != null; _videoPlayerController = value; _videoPlayerController?.play(); }); }); Wakelock.enable(); WidgetsBinding.instance?.addPostFrameCallback((timeStamp) { SystemChrome.setPreferredOrientations(Platform.isIOS ? [DeviceOrientation.landscapeRight] : [DeviceOrientation.landscapeLeft]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); }); if (isDebugShoe) { _bluetooth.createGameLog("${widget.game.name}_video"); } } _videoState() { _videoTime = _videoPlayerController?.value.position.inSeconds ?? 0; if (_videoTime - _topBarTime > 5) { if (_topBar == true) { setState(() { _topBar = false; }); } } } Future _initVideo(int index) async { try { var item = actions[index]; var controller = VideoPlayerController.network(item["video"]); await controller.initialize(); if ((item["motion"] as List).isEmpty) { controller.addListener(() { if (!_videoFirst && !controller.value.isPlaying && controller.value.position == controller.value.duration) { _videoFirst = true; _jumpVideo(_videoIndex + 1); } }); } else { controller.setLooping(true); } return controller; } catch (e) { print(e); showDialog( context: context, builder: (context) => CustomAlertDialog(title: '加载视频失败', cancelable: false, textOk: "知道了", ok: () => Navigator.of(context).pop(true)), ).then((value) { if (value == true) { Navigator.of(context).pop([true, true]); } }); } return null; } @override void dispose() { _bluetooth.uploadGameLog(); _videoPlayerController?.dispose(); super.dispose(); } _jumpVideo(int index, {bool tap = false}) { if (_videoPlayerController != null) { var controller = _videoPlayerController!; controller.pause(); controller.removeListener(_videoState); controller.dispose(); } _videoPlayerController = null; if (_videoIndex == index) return; if (index < actions.length) { _initVideo(index).then((value) { if (value != null) { if (mounted) { setState(() { if (mounted) { _videoIndex = index; actions[index]["a"] = true; var controller = value; controller.addListener(_videoState); if (mounted) controller.play(); _videoPlayerController = controller; } else { value.dispose(); } }); } else { value.dispose(); } } }); } else { Future.delayed(Duration(seconds: 1)).then((value) { if (mounted) { setState(() { _topBar = true; _motionFinishedUi = true; }); _videoPlayerController?.pause(); Future.delayed(Duration(seconds: 2)).then((value) async { if (mounted) { if (widget.launch4GameCenter != true) { await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top]); } Navigator.of(context).pop([true, true]); } }); } }); } } bool _addMotion(int m) { bool result = false; bool vibrate = false; // for (var i = 0; i < actions.length; i++) { var e = actions[_videoIndex]; // print("========== $m ${e["a"]} ${e["motion"]} ${(e["motion"] as List).contains(m)} ${motionList.contains(m)}"); if (e["a"] == true && (e["motion"] as List).contains(m) && !motionList.contains(m)) { bool finish = false; if (e["motion_progress"] != null) { int progress = e["motion_progress"]; int stepCount = _sdk.getStepCount(); print("11111111111111111111111111111 ${_sdk.getStepFreq()} $stepCount"); if (_sdk.getStepFreq() > 80) { if (stepCount > _motionStep) { _motionStep = stepCount; progress += 3; } } else { progress -= 1; } progress = max(0, progress); e["motion_progress"] = progress; finish = progress >= 100; if (finish) { e["test"] = 3; _motionKey[0].currentState?.onTap(); } } else { var now = DateTime.now().millisecondsSinceEpoch; if (now - _motionTime > 800) { _motionTime = now; int test = (e["test"] ?? 0) + 1; e["test"] = test; finish = test >= 3; _motionKey[min(test - 1, 2)].currentState?.onTap(); vibrate = true; } } result = true; if (finish && e["finish"] != true) { e["finish"] = true; motionList.add(m); _videoPlayerController?.pause(); Future.delayed(Duration(seconds: 1)).then((value) => _jumpVideo(_videoIndex + 1)); } // break; } // } if (vibrate == true) { _bluetooth.vibrate(200); } return result; } void _handleVisibilityChanged(VisibilityInfo info) { if (!mounted) return; if (info.visibleFraction == 0) { if (_videoPlayerController?.value.isInitialized == true) _videoPlayerController?.pause(); } else { // _videoPlayerController.play(); } } _back() { showDialog( context: context, builder: (context) => CustomGameAlertDialog(title: '是否退出教程', key: dialogKey, ok: () => Navigator.of(context).pop(true)), useSafeArea: false, ).then((value) { if (value == true) { Navigator.of(context).pop(); if (widget.launch4GameCenter != true) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top]); } } }); } _ok() { ValueNotifier selected = ValueNotifier(false); showDialog( context: context, useSafeArea: false, builder: (context) => CustomGameAlertDialog( title: '是否跳过教程', key: dialogKey, child: Center( child: InkWell( onTap: () { selected.value = !selected.value; }, child: Row( mainAxisSize: MainAxisSize.min, children: [ ValueListenableBuilder( valueListenable: selected, builder: (context, value, _) { return Padding( padding: const EdgeInsets.all(8.0), child: Image.asset("lib/assets/img/${value ? "pop_icon_conneted" : "pop_icon_choose_normal"}.png"), ); }), Text( "不再显示教程", style: Theme.of(context).textTheme.bodyText2, ), ], ), ), ), ok: () => Navigator.of(context).pop(true)), ).then((value) { if (value == true) { Navigator.of(context).pop([value, selected.value]); } }); } @override Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { if (_videoReady != true) { if (widget.launch4GameCenter != true) { SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top]); } return true; } return false; }, child: Scaffold( backgroundColor: Colors.white, body: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { setState(() { _topBar = !_topBar; _topBarTime = _videoTime; }); }, child: Stack( fit: StackFit.expand, children: [ if (_videoPlayerController != null) Center( child: AspectRatio( aspectRatio: _videoPlayerController!.value.aspectRatio, child: VisibilityDetector( key: ValueKey(widget.game.id), onVisibilityChanged: _handleVisibilityChanged, child: LayoutBuilder(builder: (context, constraints) { return Container( child: Stack( fit: StackFit.expand, children: [ VideoPlayer(_videoPlayerController!), if (_videoIndex > -1 && (actions[_videoIndex]["motion"] as List).isNotEmpty == true) Positioned( top: constraints.maxHeight * 0.75, left: constraints.maxWidth * .56, right: constraints.maxWidth * .08, child: Container( child: Column( children: [ actions[_videoIndex]["motion_progress"] != null ? Text( "跟着视频跑起来", style: Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 16.0, color: Theme.of(context).colorScheme.secondary), ) : Text( "跟着视频做三次", style: Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 16.0, color: Theme.of(context).colorScheme.secondary), ), actions[_videoIndex]["motion_progress"] != null ? Container( width: 160, height: 40, child: Row( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: Container( child: LinearProgressIndicator( valueColor: AlwaysStoppedAnimation( Theme.of(context).colorScheme.secondary, ), backgroundColor: Theme.of(context).scaffoldBackgroundColor, value: (actions[_videoIndex]["motion_progress"] as int) / 100.0, minHeight: 5, ), ), ), LikeButton( likeBuilder: (bool isLiked) { if (actions[_videoIndex]["icon"] != null) { return !isLiked ? ColorFiltered( colorFilter: ColorFilter.matrix([ 0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0, 0, 0, 0, 1, 0, ]), child: CachedNetworkImage(imageUrl: '${actions[_videoIndex]["icon"]}'), ) : CachedNetworkImage( imageUrl: '${actions[_videoIndex]["icon"]}', ); } return isLiked ? Image.asset("lib/assets/img/pop_icon_conneted.png") : Image.asset( "lib/assets/img/pop_icon_choose_normal.png", color: const Color(0xff666666), ); }, isLiked: (actions[_videoIndex]["test"] ?? 0) >= 3, key: _motionKey[0], ), ], ), margin: const EdgeInsets.fromLTRB(32, 8, 0, 8), ) : Row( children: [ for (var i = 0; i < 3; i++) Padding( padding: const EdgeInsets.all(8.0), child: LikeButton( likeBuilder: (bool isLiked) { if (actions[_videoIndex]["icon"] != null) { return !isLiked ? ColorFiltered( colorFilter: ColorFilter.matrix([ 0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0, 0.2126, 0.7152, 0.0722, 0, 0, 0, 0, 0, 1, 0, ]), child: CachedNetworkImage(imageUrl: '${actions[_videoIndex]["icon"]}'), ) : CachedNetworkImage( imageUrl: '${actions[_videoIndex]["icon"]}', ); } return isLiked ? Image.asset("lib/assets/img/pop_icon_conneted.png") : Image.asset( "lib/assets/img/pop_icon_choose_normal.png", color: const Color(0xff666666), ); }, isLiked: (actions[_videoIndex]["test"] ?? 0) > i, key: _motionKey[i], ), ), ], mainAxisSize: MainAxisSize.min, ), ], ), ), ) ], ), ); })), ), ), Align( alignment: Alignment.centerLeft, child: OpacityAnimatedWidget.tween( opacityEnabled: 1, opacityDisabled: 0, duration: Duration(seconds: 3), enabled: _videoReady, child: Container( constraints: BoxConstraints(maxWidth: 148 + MediaQuery.of(context).viewPadding.left), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( children: actions.where((element) => (element['motion'] as List).isNotEmpty).map((e) { // bool done = motionList.any((element) => (e['motion'] as List).contains(element)); // bool enable = e["a"] == true; int index = actions.indexOf(e); var child = GestureDetector( onTap: () { _jumpVideo(index, tap: true); }, behavior: HitTestBehavior.opaque, child: Container( margin: const EdgeInsets.symmetric(vertical: 4.0), padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 30), decoration: index == _videoIndex ? BoxDecoration(color: Theme.of(context).colorScheme.secondary) : null, alignment: Alignment.centerLeft, child: Padding( padding: EdgeInsets.only(left: MediaQuery.of(context).viewPadding.left), child: Row( mainAxisSize: MainAxisSize.min, children: [ // Padding( // padding: const EdgeInsets.only(right: 6.0), // child: done // ? Image.asset("lib/assets/img/pop_icon_conneted.png") // : enable // ? Image.asset( // "lib/assets/img/pop_icon_choose_normal.png", // color: const Color(0xff666666), // ) // : Image.asset( // "lib/assets/img/pop_icon_choose_normal.png", // color: const Color(0xffcecece), // ), // ), ConstrainedBox( constraints: BoxConstraints(minWidth: 40), child: Text( "${e['name']}", style: index == _videoIndex ? Theme.of(context).textTheme.bodyText2?.copyWith(color: Colors.white, fontSize: 22) : Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 16), ), ), Container( padding: const EdgeInsets.only(left: 10), child: e['test'] >= 3 ? Image.asset( "lib/assets/img/topbar_ok.png", color: const Color(0xff666666), width: 10, fit: BoxFit.cover, ) : null, ), ], ), ), )); return index == _videoIndex ? ClipPath( clipper: _TabPath(), child: child, ) : child; }).toList(), ), ], ), ), ), ), // Positioned( // bottom: 8, // left: 16, // right: 16, // child: ValueListenableBuilder( // valueListenable: _videoPlayerController, // builder: (context, v, __) { // return Row( // crossAxisAlignment: CrossAxisAlignment.center, // children: [ // Padding( // padding: EdgeInsets.symmetric(horizontal: 5.0), // child: Text(DateFormat.toVideoTime(v.position.inSeconds), style: Theme.of(context).textTheme.bodyText1?.copyWith(fontSize: 10)), // ), // Expanded( // child: SizedBox( // height: 2, // width: double.infinity, // child: VideoProgressIndicator( // _videoPlayerController, // allowScrubbing: false, // colors: VideoProgressColors(backgroundColor: const Color(0xffdcdcdc), bufferedColor: Colors.transparent, playedColor: Theme.of(context).colorScheme.secondary), // padding: EdgeInsets.zero, // ), // ), // ), // Padding( // padding: EdgeInsets.symmetric(horizontal: 5.0), // child: Text(DateFormat.toVideoTime(v.duration.inSeconds), style: Theme.of(context).textTheme.bodyText1?.copyWith(fontSize: 10)), // ), // ], // ); // }), // ), if (_videoReady != true) Container( color: Colors.white, child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text("欢迎使用趣动智能鞋", style: Theme.of(context).textTheme.headline1?.copyWith( fontSize: 30, )), SizedBox( height: 20, ), RichText( text: TextSpan( style: Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 18.0), children: [ TextSpan(text: '下面开始'), TextSpan( text: '新手教程', style: Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 18, color: Theme.of(context).colorScheme.secondary), ), ], ), ), ], ), ), ), if (_motionFinishedUi == true) Container( color: Colors.white, child: Center( child: RichText( text: TextSpan( style: Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 18.0), children: [ TextSpan(text: '您已完成 '), TextSpan( text: '${widget.base ? "基础动作" : widget.game.name}', style: Theme.of(context).textTheme.bodyText2?.copyWith(fontSize: 18, color: Theme.of(context).colorScheme.secondary), ), TextSpan(text: ' 新手教程,祝您运动愉快'), ], ), ), ), ), Positioned( left: 0, right: 0, top: 0, child: Offstage( offstage: !_topBar, child: SafeArea( child: Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( onTap: _back, child: Row( children: [ arrowBack(), Text( widget.base ? "返回" : "左踮脚 · 返回", style: Theme.of(context).textTheme.subtitle1, ) ], ), ), // Text( // "${widget.base ? "基础动作" : widget.game.name}操作指引", // style: Theme.of(context).textTheme.headline1, // ), if (widget.detailGuide != true) InkWell( onTap: _ok, child: Row( children: [ Text( widget.base ? "跳过" : "右踮脚 · 跳过", style: Theme.of(context).textTheme.subtitle1, ), RotatedBox( quarterTurns: 90, child: arrowBack(), ), ], ), ), ], ), ), ), ), ), ], ), ), ), ); } } class _TabPath extends CustomClipper { @override Path getClip(Size size) { var path = Path(); path.moveTo(0, 0); path.lineTo(size.width - 20, 0); path.lineTo(size.width, size.height / 2); path.lineTo(size.width - 20, size.height); path.lineTo(0, size.height); path.close(); return path; } @override bool shouldReclip(CustomClipper oldClipper) { return false; } }