view.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import 'dart:io';
  2. import 'package:electronic_assistant/base/base_page.dart';
  3. import 'package:electronic_assistant/module/record/constants.dart';
  4. import 'package:electronic_assistant/module/record/controller.dart';
  5. import 'package:electronic_assistant/resource/colors.gen.dart';
  6. import 'package:electronic_assistant/utils/expand.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:flutter/services.dart';
  9. import 'package:flutter_screenutil/flutter_screenutil.dart';
  10. import 'package:get/get.dart';
  11. import 'package:lottie/lottie.dart';
  12. import '../../resource/assets.gen.dart';
  13. import '../../router/app_pages.dart';
  14. enum RecordFromType { home, shortcutIcon, shortcutInstruction }
  15. class RecordPage extends BasePage<RecordController> {
  16. const RecordPage({super.key});
  17. static start({RecordFromType? fromType}) {
  18. Get.toNamed(RoutePath.record, arguments: {'fromType': fromType});
  19. }
  20. @override
  21. bool immersive() {
  22. return true;
  23. }
  24. @override
  25. bool statusBarDarkFont() {
  26. return false;
  27. }
  28. @override
  29. Color backgroundColor() {
  30. return ColorName.recordBackgroundColor;
  31. }
  32. @override
  33. Color navigationBarColor() {
  34. return "#4A4F67".color;
  35. }
  36. @override
  37. Widget buildBody(BuildContext context) {
  38. return Stack(alignment: Alignment.bottomCenter, children: [
  39. _buildBottomGradient(),
  40. Scaffold(
  41. appBar: AppBar(
  42. leading: IconButton(
  43. icon: const Icon(Icons.arrow_back_ios_new_rounded),
  44. color: ColorName.white,
  45. onPressed: () {
  46. controller.onBackClick();
  47. },
  48. ),
  49. scrolledUnderElevation: 0,
  50. backgroundColor: ColorName.transparent,
  51. systemOverlayStyle: SystemUiOverlayStyle.light,
  52. actions: [
  53. _buildAddShortcut(true),
  54. ],
  55. ),
  56. backgroundColor: ColorName.transparent,
  57. body: Flex(
  58. direction: Axis.vertical,
  59. children: [
  60. _buildRecordStatus(),
  61. const Spacer(flex: 271),
  62. _buildRecordAnim(),
  63. const Spacer(flex: 407),
  64. _buildRecordControl(),
  65. ],
  66. ),
  67. ),
  68. _buildAvailableTimeRemind(),
  69. ]);
  70. }
  71. Widget _buildAvailableTimeRemind() {
  72. return Obx(() {
  73. int? electric = controller.userInfo?.memberInfo?.electric;
  74. return Visibility(
  75. visible: electric != null &&
  76. electric < 12 &&
  77. !controller.isHideIntegrationInsufficient.value,
  78. child: IntrinsicHeight(
  79. child: Align(
  80. alignment: Alignment.bottomCenter,
  81. child: Container(
  82. margin: EdgeInsets.only(
  83. left: 16.w,
  84. right: 16.w,
  85. bottom: 200.h,
  86. ),
  87. child: Stack(
  88. children: [
  89. Align(
  90. alignment: Alignment.bottomCenter,
  91. child: Container(
  92. width: double.infinity,
  93. height: 48.w,
  94. decoration: BoxDecoration(
  95. borderRadius: BorderRadius.circular(10.w),
  96. gradient: LinearGradient(colors: [
  97. '#8671FF'.color,
  98. '#3E55FF'.color,
  99. '#7E80FE'.color,
  100. ], stops: const [
  101. 0.0,
  102. 0.7,
  103. 1
  104. ]),
  105. ),
  106. child: Stack(
  107. children: [
  108. Align(
  109. alignment: const Alignment(-0.05, -0.15),
  110. child: Assets
  111. .images.iconRecordIntegrationInsufficient
  112. .image(width: 153.w, height: 20.w),
  113. ),
  114. Align(
  115. alignment: Alignment.centerRight,
  116. child: GestureDetector(
  117. onTap: () =>
  118. controller.onAvailableTimeClick(),
  119. child: Container(
  120. padding: EdgeInsets.symmetric(
  121. horizontal: 10.w, vertical: 4.w),
  122. decoration: BoxDecoration(
  123. gradient: RadialGradient(
  124. center: Alignment.centerRight,
  125. colors: [
  126. "#E7F2FF".toColor(),
  127. "#FFFFFF".toColor(),
  128. "#F9E8FF".toColor()
  129. ],
  130. radius: 2),
  131. borderRadius:
  132. BorderRadius.circular(100.w),
  133. ),
  134. margin: EdgeInsets.only(right: 12.w),
  135. child: Assets.images.iconRecordRecharge
  136. .image(width: 39.w, height: 19.w)),
  137. ))
  138. ],
  139. ),
  140. ),
  141. ),
  142. Assets.images.iconRecordAvailableTime
  143. .image(width: 88.w, height: 77.w),
  144. Align(
  145. alignment: Alignment.topRight,
  146. child: GestureDetector(
  147. onTap: () {
  148. controller.onCloseAvailableTimeClick();
  149. },
  150. child: Assets
  151. .images.iconRecordIntegrationInsufficientClose
  152. .image(width: 18.w, height: 18.w),
  153. ),
  154. )
  155. ],
  156. ))),
  157. ),
  158. );
  159. });
  160. }
  161. Widget _buildAddShortcut(bool visible) {
  162. return GestureDetector(
  163. onTap: () {
  164. controller.addShortcut();
  165. },
  166. child: Visibility(
  167. visible: visible,
  168. child: Row(
  169. children: [
  170. Image(
  171. image: Assets.images.iconRecordAddShortcut.provider(),
  172. width: 24.w,
  173. height: 24.w),
  174. Padding(
  175. padding: EdgeInsets.only(left: 8.w, right: 16.w),
  176. child: Text(
  177. Platform.isIOS ? '添加到快捷方式' : '添加到桌面',
  178. style: TextStyle(color: ColorName.white, fontSize: 14.w),
  179. ),
  180. )
  181. ],
  182. ),
  183. ),
  184. );
  185. }
  186. Widget _buildRecordStatus() {
  187. return Container(
  188. padding: EdgeInsets.symmetric(horizontal: 16.w),
  189. margin: EdgeInsets.only(top: 20.w),
  190. child: Row(
  191. children: [
  192. Container(
  193. margin: EdgeInsets.only(right: 8.w),
  194. child: Image(
  195. image: Assets.images.iconRecordLogo.provider(),
  196. width: 45.w,
  197. height: 48.w),
  198. ),
  199. Obx(() {
  200. return Text(
  201. controller.currentStatus.value.desc,
  202. style: TextStyle(color: ColorName.white, fontSize: 17.w),
  203. );
  204. }),
  205. ],
  206. ),
  207. );
  208. }
  209. Widget _buildRecordAnim() {
  210. return Obx(() {
  211. return AnimatedOpacity(
  212. opacity:
  213. controller.currentStatus.value == RecordStatus.recording ? 1 : 0,
  214. duration: const Duration(milliseconds: 520),
  215. child: SizedBox(
  216. width: 360.w,
  217. height: 180.w,
  218. child: Lottie.asset(Assets.anim.animRecordingLottie)),
  219. );
  220. });
  221. }
  222. Widget _buildRecordControl() {
  223. return Stack(
  224. alignment: Alignment.bottomCenter,
  225. children: [
  226. Container(
  227. padding: EdgeInsets.symmetric(horizontal: 24.w, vertical: 30.w),
  228. decoration: BoxDecoration(
  229. color: "#4A4F67".color,
  230. borderRadius: BorderRadius.only(
  231. topLeft: Radius.circular(40.w),
  232. topRight: Radius.circular(40.w)),
  233. ),
  234. child: Row(
  235. children: [
  236. GestureDetector(
  237. onTap: controller.onCancelClick,
  238. child: Obx(() {
  239. return Image(
  240. image: controller.currentStatus.value.cancelButtonImage,
  241. width: 56.w,
  242. height: 56.w);
  243. }),
  244. ),
  245. const Spacer(),
  246. GestureDetector(
  247. onTap: controller.onSaveClick,
  248. child: Obx(() {
  249. return Image(
  250. image: controller.currentStatus.value.saveButtonImage,
  251. width: 56.w,
  252. height: 56.w);
  253. }),
  254. ),
  255. ],
  256. ),
  257. ),
  258. Column(
  259. children: [
  260. GestureDetector(
  261. onTap: () {
  262. controller.onActionClick();
  263. },
  264. child: Obx(
  265. () => Image(
  266. image: controller.currentStatus.value.actionButtonImage,
  267. width: 92.w,
  268. height: 92.w),
  269. )),
  270. Padding(
  271. padding: EdgeInsets.only(top: 10.w, bottom: 35.w),
  272. child: Obx(() => Text(
  273. formatDuration(controller.currentDuration.value),
  274. style: TextStyle(
  275. color: ColorName.white,
  276. fontSize: 16.w,
  277. ),
  278. )),
  279. )
  280. ],
  281. )
  282. ],
  283. );
  284. }
  285. Widget _buildBottomGradient() {
  286. return Container(
  287. height: 0.38.sh,
  288. decoration: BoxDecoration(
  289. gradient: LinearGradient(
  290. begin: Alignment.topCenter,
  291. end: Alignment.bottomCenter,
  292. colors: [
  293. "#006177F2".color,
  294. "#806177F2".color,
  295. ],
  296. ),
  297. ),
  298. );
  299. }
  300. String formatDuration(double value) {
  301. int hour = (value / 3600).floor();
  302. int minute = ((value - hour * 3600) / 60).floor();
  303. int second = (value - hour * 3600 - minute * 60).floor();
  304. return '${hour.toString().padLeft(2, '0')}:${minute.toString().padLeft(2, '0')}:${second.toString().padLeft(2, '0')}';
  305. }
  306. }