home.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. import 'dart:async';
  2. import 'dart:convert' as convert;
  3. import 'package:fast/constants.dart';
  4. import 'package:fast/model/model.dart';
  5. import 'package:fast/utils/api.dart';
  6. import 'package:fast/utils/global.dart';
  7. import 'package:fast/utils/http_utils.dart';
  8. import 'package:fast/utils/size_fit.dart';
  9. import 'package:fast/view/component/challenge_checkin.dart';
  10. import 'package:fast/view/component/change_time.dart';
  11. import 'package:fast/view/component/header.dart';
  12. import 'package:fast/view/component/share.dart';
  13. import 'package:flutter/material.dart';
  14. import 'package:flutter/services.dart';
  15. import 'package:shared_preferences/shared_preferences.dart';
  16. import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
  17. import 'component/challenge_checkout.dart';
  18. import 'component/eat.dart';
  19. import 'component/loading.dart';
  20. import 'component/fast.dart';
  21. import 'package:intl/intl.dart';
  22. class HomeScreen extends StatefulWidget {
  23. const HomeScreen({Key? key}) : super(key: key);
  24. @override
  25. State<HomeScreen> createState() => HomeScreenState();
  26. }
  27. GlobalKey eatKey = GlobalKey();
  28. GlobalKey<FastState> fastKey = GlobalKey<FastState>();
  29. class HomeScreenState extends State<HomeScreen>
  30. with SingleTickerProviderStateMixin, WidgetsBindingObserver {
  31. late AnimationController controller;
  32. late Animation animation0;
  33. late Animation animation1;
  34. double topOffset = -40;
  35. double bottomOffset = 0;
  36. double bottom = 0;
  37. bool showEating = false;
  38. bool showFasting = false;
  39. bool showLoading = true;
  40. bool hasPopPage = false;
  41. Map<String, dynamic>? onlineObj;
  42. Timer? timerUpdate;
  43. String? strSysTime;
  44. List<dynamic> list = [];
  45. @override
  46. void initState() {
  47. super.initState();
  48. var zone = DateTime.now().timeZoneOffset;
  49. WidgetsBinding.instance?.addObserver(this);
  50. Global().fastKey = fastKey;
  51. Global().homePage = this;
  52. loadCache();
  53. getConfig();
  54. getDatas();
  55. // getSystemTime();
  56. // getFastStatus();
  57. // getBalance();
  58. // getOnlineUser();
  59. controller = AnimationController(
  60. vsync: this, duration: const Duration(milliseconds: 2000));
  61. controller.addListener(() {
  62. setState(() {});
  63. });
  64. animation0 = Tween(begin: 0.0, end: 1.0).animate(
  65. CurvedAnimation(parent: controller, curve: const Interval(0.05, 0.2)));
  66. animation1 = Tween(begin: 0.0, end: 1.0).animate(
  67. CurvedAnimation(parent: controller, curve: const Interval(0.825, 1)));
  68. Timer(const Duration(milliseconds: 200), () {
  69. controller.forward();
  70. setState(() {
  71. topOffset = 0;
  72. bottomOffset = bottom;
  73. });
  74. });
  75. Timer(const Duration(seconds: 1), () {
  76. if (Global().userBean != null) {
  77. showShare();
  78. }
  79. });
  80. }
  81. @override
  82. void didChangeAppLifecycleState(AppLifecycleState state) {
  83. switch (state) {
  84. case AppLifecycleState.resumed:
  85. getDatas();
  86. break;
  87. case AppLifecycleState.inactive:
  88. break;
  89. case AppLifecycleState.paused:
  90. break;
  91. case AppLifecycleState.detached:
  92. break;
  93. }
  94. }
  95. Future loadCache() async {
  96. final prefs = await SharedPreferences.getInstance();
  97. String? temp = prefs.getString('userInfo');
  98. if (temp != null) {
  99. Map<String, dynamic> data = convert.jsonDecode(temp);
  100. UserBean bean = UserBean.fromJson(data);
  101. Global().userBean = bean;
  102. }
  103. }
  104. void getDatas() async {
  105. List list = await Future.wait([
  106. getSystemTime(),
  107. getFastStatus(),
  108. getBalance(),
  109. getOnlineUser(),
  110. getUserInfo()
  111. ]);
  112. if (list[1] != null) {
  113. FastBean fastBean = list[1];
  114. if (fastBean.ongoing == false) {
  115. Global().currentFast = null;
  116. showFastContent();
  117. return;
  118. }
  119. Global().currentFast = fastBean;
  120. if (fastBean.needConfirm) {
  121. showCheckout(true);
  122. return;
  123. }
  124. int t =
  125. DateTime.now().millisecondsSinceEpoch ~/ 1000 + Global().timeSeconds;
  126. if (fastBean.mode == 'CHALLENGER' && fastBean.status == 'DOING') {
  127. int index = fastBean.currentDayIndex! - 1;
  128. if (t >= fastBean.startTime! &&
  129. fastBean.checkinDays![index].checkinTime == null) {
  130. bool supertimeout = t - fastBean.startTime! >= 3600 * 24;
  131. showCheckin(false);
  132. if (supertimeout) {
  133. return;
  134. }
  135. }
  136. if (t + 1 < fastBean.startTime!) {
  137. setState(() {
  138. showEating = true;
  139. showFasting = false;
  140. showLoading = false;
  141. });
  142. return;
  143. }
  144. }
  145. showFastContent();
  146. }
  147. }
  148. @override
  149. void dispose() {
  150. controller.dispose();
  151. super.dispose();
  152. }
  153. checkUpdate() {
  154. setState(() {
  155. showEating = false;
  156. showFasting = false;
  157. showLoading = true;
  158. });
  159. Timer(const Duration(seconds: 2), () {
  160. getDatas();
  161. });
  162. }
  163. Future getConfig() async {
  164. Map<String, dynamic> data = await HttpUtils.get(Api.serverConfig);
  165. Global().thirdLogin = data['thirdparty_login'];
  166. Global().pushEnable = false; //data['push_enable'];
  167. Global().payEnable = data['pay_enable'];
  168. }
  169. Future getSystemTime() async {
  170. Map<String, dynamic> data = await HttpUtils.get(Api.serverTime);
  171. TimeBean timeBean = TimeBean.fromJson(data);
  172. // respo.
  173. var now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
  174. Global().timeSeconds = timeBean.server_ts! - now;
  175. showSystemTime();
  176. return timeBean;
  177. // var ts = respone.server_ts;
  178. }
  179. Future showCheckin(bool abandon) async {
  180. if (hasPopPage) {
  181. return;
  182. }
  183. hasPopPage = true;
  184. int timestamp = serverTime().millisecondsSinceEpoch ~/ 1000;
  185. Map<String, dynamic> data =
  186. await HttpUtils.get(Api.check, params: {"time": timestamp});
  187. showDialog(
  188. context: context,
  189. barrierDismissible: false,
  190. barrierColor: Colors.transparent,
  191. useSafeArea: false,
  192. builder: (BuildContext context) {
  193. return FastCheckin(
  194. abandon: abandon,
  195. supertimeout: data['checkin_status'] == 'TIMEOUT_EXIT',
  196. fast: Global().currentFast!,
  197. timestamp: timestamp,
  198. checkInfo: data,
  199. );
  200. });
  201. }
  202. Future showCheckout(bool abandon) async {
  203. if (hasPopPage) {
  204. return;
  205. }
  206. hasPopPage = true;
  207. int timestamp = serverTime().millisecondsSinceEpoch ~/ 1000;
  208. Map<String, dynamic> data =
  209. await HttpUtils.get(Api.check, params: {"time": timestamp});
  210. showDialog(
  211. context: context,
  212. barrierDismissible: false,
  213. barrierColor: Colors.transparent,
  214. useSafeArea: false,
  215. builder: (BuildContext context) {
  216. return FastCheckout(
  217. abandon: abandon,
  218. supertimeout: data['checkout_status'] == 'TIMEOUT_EXIT',
  219. fast: Global().currentFast!,
  220. timestamp: timestamp,
  221. checkInfo: data,
  222. );
  223. });
  224. }
  225. void closeCheckPop() {
  226. hasPopPage = false;
  227. getDatas();
  228. }
  229. void showSystemTime() {
  230. if (timerUpdate != null) {
  231. timerUpdate!.cancel();
  232. }
  233. timerUpdate = Timer.periodic(const Duration(seconds: 1), (e) {
  234. int milliseconds = DateTime.now().millisecondsSinceEpoch;
  235. milliseconds = milliseconds + Global().timeSeconds * 1000;
  236. DateTime dt = DateTime.fromMillisecondsSinceEpoch(milliseconds);
  237. if (mounted) {
  238. setState(() {
  239. strSysTime = DateFormat('yyyy-MM-dd HH:mm:ss').format(dt);
  240. });
  241. }
  242. });
  243. }
  244. Future getFastStatus() async {
  245. Map<String, dynamic> data = await HttpUtils.get(Api.current);
  246. FastBean fastBean = FastBean.fromJson(data);
  247. setState(() {
  248. if (fastBean.ongoing!) {
  249. list = data['notify_points'];
  250. } else {
  251. list = [];
  252. }
  253. });
  254. return fastBean;
  255. // var ts = respone.server_ts;
  256. }
  257. Future getBalance() async {
  258. Map<String, dynamic> data = await HttpUtils.get(Api.balance);
  259. Global().balance = data['rjv_balance'];
  260. return data;
  261. }
  262. Future getOnlineUser() async {
  263. Map<String, dynamic> data = await HttpUtils.get(Api.onlineUsers);
  264. setState(() {
  265. onlineObj = data;
  266. });
  267. return data;
  268. // Global().balance = data['rjv_balance'];
  269. }
  270. Future getUserInfo() async {
  271. Map<String, dynamic> data = await HttpUtils.get(Api.userInfo);
  272. UserBean bean = UserBean.fromJson(data);
  273. Global().userBean = bean;
  274. final prefs = await SharedPreferences.getInstance();
  275. await prefs.setString('userInfo', convert.jsonEncode(data));
  276. String? temp = prefs.getString('userInfo');
  277. Map<String, dynamic> bb = convert.jsonDecode(temp!);
  278. print(bb.toString());
  279. return data;
  280. }
  281. void eatEnd() {
  282. setState(() {
  283. showEating = false;
  284. showFasting = false;
  285. showLoading = true;
  286. });
  287. showCheckin(false);
  288. Timer(const Duration(seconds: 3), () {
  289. getDatas();
  290. });
  291. }
  292. void showLogin() {}
  293. showFastContent() {
  294. setState(() {
  295. showEating = false;
  296. showFasting = true;
  297. showLoading = false;
  298. });
  299. Timer(const Duration(milliseconds: 200), () {
  300. if (fastKey.currentContext != null) {
  301. FastState seekBar = fastKey.currentState as FastState;
  302. seekBar.updateProgress();
  303. }
  304. });
  305. }
  306. @override
  307. Widget build(BuildContext context) {
  308. SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
  309. // final Controller c = Get.put(Controller());
  310. SizeFit.initialize(context);
  311. var size = MediaQuery.of(context).size;
  312. EdgeInsets safePadding = MediaQuery.of(context).padding;
  313. bottom = safePadding.bottom;
  314. return Scaffold(
  315. body: Stack(
  316. children: [
  317. AnimatedPositioned(
  318. duration: const Duration(milliseconds: 300),
  319. top: topOffset,
  320. child: Opacity(
  321. opacity: animation0.value,
  322. child: Header(isIndexPage: true),
  323. )),
  324. Container(
  325. margin: EdgeInsets.only(top: 180.px, bottom: bottom),
  326. // alignment: Alignment.center,
  327. color: kBgColor,
  328. child: Stack(children: [
  329. Column(
  330. mainAxisSize: MainAxisSize.max,
  331. children: [
  332. if (showFasting)
  333. Expanded(
  334. child: ClipRect(
  335. clipBehavior: Clip.hardEdge,
  336. child: Container(
  337. alignment: Alignment.topCenter,
  338. margin: EdgeInsets.only(
  339. bottom: 20.px,
  340. top: size.height > 667.px ? 30.px : 10.px),
  341. color: kBgColor,
  342. child: Transform.scale(
  343. alignment: Alignment.topCenter,
  344. scale: Global().scale,
  345. child: Fast(
  346. key: fastKey,
  347. )),
  348. ),
  349. )),
  350. if (showEating)
  351. Expanded(
  352. child: Container(
  353. alignment: Alignment.topCenter,
  354. margin: EdgeInsets.only(bottom: 20.px),
  355. color: kBgColor,
  356. child: Transform.scale(
  357. alignment: Alignment.topCenter,
  358. scale: Global().scale,
  359. child: Eat(
  360. key: eatKey,
  361. )))),
  362. if (showLoading)
  363. Expanded(
  364. child: Container(
  365. alignment: Alignment.topCenter,
  366. margin: EdgeInsets.only(top: 50.px),
  367. color: kBgColor,
  368. child: Loading())),
  369. ],
  370. ),
  371. Positioned(
  372. left: 0,
  373. right: 0,
  374. bottom: 60.px,
  375. child: Column(
  376. children: [
  377. if (onlineObj != null)
  378. Opacity(
  379. opacity: animation1.value,
  380. child: Stack(
  381. alignment: AlignmentDirectional.topStart,
  382. children: [
  383. bottomAvatar(4, const Color(0xCC080C1A)),
  384. bottomAvatar(3, const Color(0x99080C1A)),
  385. bottomAvatar(2, const Color(0x66080C1A)),
  386. bottomAvatar(1, const Color(0x33080C1A)),
  387. bottomAvatar(0, const Color(0x00080C1A)),
  388. Container(
  389. margin: EdgeInsets.fromLTRB(
  390. 12 * 4.px + 24.px + 8.px, 1.px, 0, 0),
  391. height: 22.px,
  392. child: Text(
  393. '当前' +
  394. onlineObj!['user_count'].toString() +
  395. '人在线',
  396. style: TextStyle(
  397. color: const Color(0x66FFFFFF),
  398. fontSize: 14.px,
  399. height: 1.4),
  400. ),
  401. )
  402. ],
  403. ),
  404. ),
  405. SizedBox(
  406. height: 24.px,
  407. )
  408. ],
  409. ))
  410. ])),
  411. Positioned(
  412. left: 20.px,
  413. top: 200.px,
  414. child: GestureDetector(
  415. onTap: () {
  416. showTimelist(); //调表界面
  417. },
  418. child: Container(
  419. width: 60.px,
  420. height: 36.px,
  421. alignment: Alignment.center,
  422. decoration: BoxDecoration(
  423. color: const Color(0x1AC4CCDA),
  424. borderRadius: BorderRadius.all(Radius.circular(12.px))),
  425. child: Text(
  426. '调表',
  427. style: TextStyle(
  428. color: Colors.white,
  429. fontSize: 14.px,
  430. fontWeight: FontWeight.bold),
  431. ),
  432. ),
  433. ))
  434. /*Positioned(
  435. left: 0,
  436. top: 50,
  437. right: 0,
  438. height: list.isEmpty
  439. ? 30.px
  440. : list.length == 1
  441. ? 100.px
  442. : 200.px,
  443. child: Opacity(
  444. opacity: 1.0,
  445. child: Container(
  446. color: const Color(0xddf5deb3),
  447. padding: const EdgeInsets.only(left: 20, right: 20),
  448. child: Column(
  449. crossAxisAlignment: CrossAxisAlignment.end,
  450. children: [
  451. Row(
  452. children: [
  453. GestureDetector(
  454. child: const Text('请选择'),
  455. onTap: () {
  456. showPicker();
  457. },
  458. ),
  459. SizedBox(
  460. width: 20.px,
  461. ),
  462. GestureDetector(
  463. onTap: () {
  464. updateTimes(0);
  465. },
  466. child: const Text('重置'),
  467. ),
  468. if (strSysTime != null)
  469. Expanded(
  470. child: Text(
  471. '系统时间:${strSysTime!}',
  472. textAlign: TextAlign.right,
  473. style: TextStyle(fontSize: 8.px),
  474. ))
  475. ],
  476. ),
  477. Expanded(
  478. child: SingleChildScrollView(
  479. child: Column(
  480. crossAxisAlignment: CrossAxisAlignment.end,
  481. children: [
  482. ...List<Widget>.generate(list.length, (i) {
  483. return Column(
  484. mainAxisAlignment: MainAxisAlignment.end,
  485. crossAxisAlignment: CrossAxisAlignment.end,
  486. children: [
  487. ...List<Widget>.generate(
  488. list[i]['contents'].length, (index) {
  489. String strColor = list[i]['contents']
  490. [index]['fColor'];
  491. strColor = strColor.substring(2, 10);
  492. int value =
  493. int.parse(strColor, radix: 16);
  494. return Text(
  495. list[i]['contents'][index]['content'],
  496. textAlign: TextAlign.right,
  497. style: TextStyle(
  498. fontSize: 8.px,
  499. color: Color(value)),
  500. );
  501. }),
  502. Text(
  503. '--------------------------------------',
  504. style: TextStyle(
  505. color: Colors.black,
  506. fontSize: 8.px),
  507. )
  508. ],
  509. );
  510. })
  511. ],
  512. ),
  513. ))
  514. ],
  515. )))),*/
  516. ],
  517. ),
  518. );
  519. }
  520. showTimelist() {
  521. showDialog(
  522. context: context,
  523. barrierDismissible: false,
  524. useSafeArea: false,
  525. barrierColor: Colors.transparent,
  526. builder: (BuildContext context) {
  527. return ChangeTime(list: list,callback: (){
  528. getDatas();
  529. },);
  530. });
  531. }
  532. DateTime serverTime() {
  533. int milliseconds = DateTime.now().millisecondsSinceEpoch;
  534. milliseconds = milliseconds + Global().timeSeconds * 1000;
  535. return DateTime.fromMillisecondsSinceEpoch(milliseconds);
  536. }
  537. showPicker() {
  538. DatePicker.showDatePicker(context,
  539. showTitleActions: true,
  540. currentTime: serverTime(),
  541. theme: const DatePickerTheme(
  542. headerColor: Colors.orange,
  543. backgroundColor: Colors.white,
  544. itemStyle: TextStyle(
  545. color: Colors.black, fontWeight: FontWeight.bold, fontSize: 18),
  546. doneStyle: TextStyle(color: Colors.white, fontSize: 16)),
  547. onConfirm: (date) {
  548. DatePicker.showTimePicker(context,
  549. showTitleActions: true,
  550. currentTime: serverTime(),
  551. theme: const DatePickerTheme(
  552. headerColor: Colors.orange,
  553. backgroundColor: Colors.white,
  554. itemStyle: TextStyle(
  555. color: Colors.black,
  556. fontWeight: FontWeight.bold,
  557. fontSize: 18),
  558. doneStyle: TextStyle(color: Colors.white, fontSize: 16)),
  559. onConfirm: (date2) {
  560. DateTime dt = DateTime.parse(date.year.toString() +
  561. '-' +
  562. (date.month.toString()).padLeft(2, '0') +
  563. '-' +
  564. (date.day.toString()).padLeft(2, '0') +
  565. 'T' +
  566. (date2.hour.toString()).padLeft(2, '0') +
  567. ':' +
  568. (date2.minute.toString()).padLeft(2, '0') +
  569. ':' +
  570. (date2.second.toString()).padLeft(2, '0'));
  571. int seconds = (dt.millisecondsSinceEpoch -
  572. DateTime.now().millisecondsSinceEpoch) ~/
  573. 1000;
  574. updateTimes(seconds);
  575. });
  576. // int seconds = (date.millisecondsSinceEpoch -
  577. // DateTime.now().millisecondsSinceEpoch) ~/
  578. // 1000;
  579. // updateTimes(seconds);
  580. });
  581. // DatePicker.showDateTimePicker(context,
  582. // showTitleActions: true,
  583. // currentTime: serverTime(),
  584. // theme: const DatePickerTheme(
  585. // headerColor: Colors.orange,
  586. // backgroundColor: Colors.white,
  587. // itemStyle: TextStyle(
  588. // color: Colors.black, fontWeight: FontWeight.bold, fontSize: 18),
  589. // doneStyle: TextStyle(color: Colors.white, fontSize: 16)),
  590. // onConfirm: (date) {
  591. // int seconds = (date.millisecondsSinceEpoch -
  592. // DateTime.now().millisecondsSinceEpoch) ~/
  593. // 1000;
  594. // updateTimes(seconds);
  595. // });
  596. }
  597. Future updateTimes(seconds) async {
  598. Map<String, dynamic> data =
  599. await HttpUtils.get(Api.fixTime, params: {"fix": seconds});
  600. getDatas();
  601. }
  602. showShare() {
  603. // showDialog(
  604. // context: context,
  605. // barrierDismissible: false,
  606. // barrierColor: const Color(0xF2000D1F),
  607. // builder: (BuildContext context) {
  608. // return const Share();
  609. // });
  610. }
  611. bottomAvatar(int index, Color color) {
  612. if (onlineObj!['recent_users'].length > index) {
  613. return Container(
  614. width: 24.px,
  615. height: 24.px,
  616. margin: EdgeInsets.fromLTRB(index * 12.px, 0, 0, 0),
  617. child: Stack(
  618. children: [
  619. ClipOval(
  620. child: Image.network(
  621. onlineObj!['recent_users'][index]['avatar'],
  622. width: 24.px,
  623. height: 24.px,
  624. fit: BoxFit.cover,
  625. ),
  626. ),
  627. Container(
  628. width: 24.px,
  629. height: 24.px,
  630. decoration: BoxDecoration(
  631. color: color,
  632. shape: BoxShape.circle,
  633. border: Border.all(color: const Color(0xFF000D26))),
  634. )
  635. ],
  636. ),
  637. );
  638. }
  639. return SizedBox(
  640. width: 0.px,
  641. height: 0.px,
  642. );
  643. }
  644. }