import 'dart:math'; import 'dart:ui'; import 'package:dartin/dartin.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:sport/bean/sport_target_index.dart'; import 'package:sport/pages/home/duration_setting_page.dart'; import 'package:sport/router/navigator_util.dart'; import 'package:sport/services/api/rest_client.dart'; import 'package:sport/utils/date.dart'; import 'package:sport/utils/toast.dart'; import 'package:sport/widgets/appbar.dart'; import 'package:sport/widgets/button_primary.dart'; import 'package:sport/widgets/circular_percent_indicator.dart'; import 'package:sport/widgets/decoration.dart'; import 'package:sport/widgets/dialog/request_dialog.dart'; import 'package:sport/widgets/image.dart'; import 'package:sport/widgets/loading.dart'; import 'package:sport/widgets/misc.dart'; import 'package:sport/widgets/space.dart'; var _succColor = const Color(0xff5498FF); var _failColor = const Color(0xffFF5B1D); class DurationPage extends StatefulWidget { @override State createState() => _PageState(); } class _PageState extends State { ValueNotifier _valueNotifierDate = ValueNotifier(DateTime.now()); PageController _pageController; @override void initState() { super.initState(); _pageController = PageController(initialPage: 0); } @override void dispose() { _pageController?.dispose(); super.dispose(); _valueNotifierDate?.dispose(); } @override Widget build(BuildContext context) { var _dot = Container( width: 5, height: 5, decoration: BoxDecoration(shape: BoxShape.circle, color: _succColor), ); var _dotFailed = Container( width: 5, height: 5, decoration: BoxDecoration(shape: BoxShape.circle, color: _failColor), ); return Scaffold( body: FutureBuilder( future: inject().getSportTargetIndex().asStream().map((event) => event.data).last, builder: (BuildContext context, AsyncSnapshot snapshot) => snapshot.connectionState != ConnectionState.done ? RequestLoadingWidget() : CustomScrollView( slivers: [ // SizeBox(), // SliverToBoxAdapter( // child: Space(height: 20.0,), // ), buildSliverAppBar(context, "运动目标", backgroundColor: Theme.of(context).scaffoldBackgroundColor, actions: [ IconButton( icon: Image.asset( "lib/assets/img/setgoals_icon_set.png", width: 22.0, ), highlightColor: Colors.red, onPressed: () async { await NavigatorUtil.goPage(context, (context) => DurationSettingPage()); setState(() {}); }, ) ]), SliverToBoxAdapter( child: Container( margin: const EdgeInsets.symmetric(horizontal: 12.0), padding: const EdgeInsets.only(top:20.0,bottom: 10.0,left: 16.0,right: 16.0), decoration: circular(), child: Column( children: [ Center( child: CircularPercentIndicator( radius: 140.0, lineWidth: 12.0, percent: 1.0 * (snapshot.data?.today?.value ?? 0) / snapshot.data?.today?.valueTarget ?? 0.01, center: Column( children: [ Text( "${snapshot.data?.today?.value ?? 0}", style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 40.0, fontFamily: "DIN"), ), Text( "${snapshot.data?.today?.label}", style: Theme.of(context).textTheme.subtitle2, strutStyle: fixedLine, ) ], mainAxisSize: MainAxisSize.min, ), animation: true, animationDuration: 1000, animateFromLastPercent: true, startAngle: 200.0, arcType: ArcType.CUSTOM, backgroundColor: Color(0xfff1f1f1), circularStrokeCap: CircularStrokeCap.round, rotateLinearGradient: true, linearGradient: LinearGradient( colors: [Color(0xff8DF7FF), Color(0xff16A2FF)], ), ), ), SizedBox( width: 15.0, ), Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), child: Text( "运动目标:${snapshot.data?.target?.valueTarget ?? 0} ${snapshot.data?.today?.label}", style: Theme.of(context).textTheme.subtitle1, ), ), Divider(), Padding( padding: const EdgeInsets.symmetric(vertical: 12.0), child: Column( children: [ Row( children: [ Text( "目标状态", style: Theme.of(context).textTheme.subtitle1, ), snapshot.data?.today?.finish == true ? Text( "已达标", style: Theme.of(context).textTheme.bodyText2.copyWith(color: _succColor), ) : Text( "未达标", style: Theme.of(context).textTheme.bodyText2.copyWith(color: _failColor), ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, ), const SizedBox( height: 8.0, ), Row( children: [ Text( "今日目标", style: Theme.of(context).textTheme.subtitle1, ), Text( "${snapshot.data?.today?.valueTarget ?? 0}${snapshot.data?.today?.label}", style: Theme.of(context).textTheme.bodyText2, ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, ), const SizedBox( height: 8.0, ), Row( children: [ Text( "累计消耗", style: Theme.of(context).textTheme.subtitle1, ), Text( "${snapshot.data?.today?.consume ?? 0}卡", style: Theme.of(context).textTheme.bodyText2, ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, ), const SizedBox( height: 8.0, ), Row( children: [ Text( "本月达标天数", style: Theme.of(context).textTheme.subtitle1, ), Text( "${snapshot.data?.target?.monthFinish ?? 0}天", style: Theme.of(context).textTheme.bodyText2, ) ], mainAxisAlignment: MainAxisAlignment.spaceBetween, ) ], )) ], ), ), ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(12.0, 16.0 , 12.0,12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "达标记录", style: Theme.of(context).textTheme.headline1.copyWith(fontSize: 16.0), ), const SizedBox( height: 16.0, ), Container( padding: const EdgeInsets.all(12.0), decoration: circular(), height: 406.0, child: Column( children: [ Center( child: ValueListenableBuilder( valueListenable: _valueNotifierDate, builder: (_, time, ___) { return Row( mainAxisSize: MainAxisSize.min, children: [ GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { _pageController?.nextPage(duration: Duration(milliseconds: 500), curve: Curves.linear); }, child: Padding( padding: const EdgeInsets.all(18.0), child: arrowLeft(), ), ), SizedBox( width: 30, ), Text( "${time.year}年${'${time.month}'.padLeft(2, '0')}月", style: Theme.of(context).textTheme.bodyText2.copyWith(color: Color(0xff333333)), strutStyle: fixedLine, ), SizedBox( width: 30, ), GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { if (_pageController?.page == 0.0) { return; } _pageController?.previousPage(duration: Duration(milliseconds: 500), curve: Curves.linear); }, child: Padding( padding: const EdgeInsets.all(18.0), child: arrowRight(), ), ), ], ); }), ), Expanded( child: PageView.builder( reverse: true, itemCount: 10240, controller: _pageController, onPageChanged: (page) { DateTime next = offsetDate(2, -page); _valueNotifierDate.value = next; }, itemBuilder: (context, index) { DateTime time = offsetDate(2, -index); return FutureBuilder>( future: createFuture(time), builder: (BuildContext context, AsyncSnapshot> snapshot) { var _value = snapshot?.data; return snapshot.connectionState != ConnectionState.done ? RequestLoadingWidget() : Padding( padding: const EdgeInsets.all(12.0), child: GridView.builder( physics: NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 7, ), itemBuilder: (_, index) { var item = _value[index]; return Center( child: item.today == true ? Container( padding: const EdgeInsets.all(6.0), decoration: BoxDecoration(shape: BoxShape.circle, color: Theme.of(context).accentColor), child: Text("${item.title}", style: Theme.of(context).textTheme.subtitle1.copyWith(color: Colors.white)), ) : Stack( children: [ Text("${item.title}", style: item.enable ? Theme.of(context).textTheme.bodyText2 : Theme.of(context).textTheme.subtitle1), if (item.state > 0) Align( alignment: Alignment.bottomCenter, child: Padding( child: item.state == 2 ? _dot : _dotFailed, padding: const EdgeInsets.only(bottom: 4.0), )) ], alignment: Alignment.center, ) // Stack( // children: [ // Text("${item.title}", // style: item.enable // ? Theme.of(context).textTheme.bodyText2 // : Theme.of(context).textTheme.subtitle1), // Image.asset("lib/assets/img/date_state_day.png") // ], // alignment: Alignment.center, // ) // : Image.asset("lib/assets/img/date_state_select.png") ); }, itemCount: 49, ), ); }); }, ), ), Divider(), SizedBox( height: 5, ), Row( children: [ SizedBox( width: 16, ), _dot, SizedBox( width: 6, ), Text( "运动达标", style: Theme.of(context).textTheme.bodyText1, strutStyle: fixedLine, ), SizedBox( width: 45, ), _dotFailed, SizedBox( width: 6, ), Text( "运动不达标", style: Theme.of(context).textTheme.bodyText1, strutStyle: fixedLine, ), ], ) ], ), ), ], ), ), ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(12.0, 0.0 , 12.0,12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "本月达标奖励", style: Theme.of(context).textTheme.headline1.copyWith(fontSize: 16.0), ), const SizedBox( height: 16.0, ), Container( decoration: circular(), padding: const EdgeInsets.fromLTRB(12.0, 20.0, 12.0, 12.0), child: StaggeredGridView.countBuilder( padding: EdgeInsets.zero, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), crossAxisCount: 3, itemCount: snapshot.data?.rewards?.length, itemBuilder: (BuildContext context, int index) { var item = snapshot.data?.rewards[index]; if (item == null) return Container(); return Center( child: Column( children: [ Image.asset("lib/assets/img/reward_icon_${item.days}day.png"), const SizedBox( height: 5.0, ), Text( "领取${item.score}积分", style: Theme.of(context).textTheme.subtitle2, ), const SizedBox( height: 12.0, ), PrimaryButton( width: 65.0, height: 30.0, content: item.status == "finish" ? "领取" : item.status == "received" ? "已领取" : "未完成", callback: item.status == "finish" ? () async { await request(context, () async { await inject().sportTargetReward(item.id); ToastUtil.show("领取成功"); }); } : null, ) ], ), ); }, crossAxisSpacing: 12.0, mainAxisSpacing: 12.0, staggeredTileBuilder: (int index) => StaggeredTile.fit(1), ), ), const SizedBox( height: 50.0, ), ], ), ), ) ], ), ), ); } Future> createFuture(DateTime time) async { const List week = ["日", "一", "二", "三", "四", "五", "六"]; List<_DataItem> items = []; for (var d in week) { items.add(_DataItem(d, 0)); } DateTime today = DateTime.now(); int todayday = today.day; DateTime now = DateTime(time.year, time.month, time.day); DateTime next = DateTime(time.year, time.month + 1, time.day); int inDays = next.difference(time).inDays; // print("11111111111111111 ${now} ${now.weekday} ${now} ${inDays}"); if (now.weekday != 7) { for (var i = 0; i < now.weekday; i++) { items.add(_DataItem("", 0)); } } for (var i = 0; i < inDays; i++) { bool lastDay = false; if (now.month == today.month && i + 1 > todayday) { lastDay = true; } items.add( _DataItem("${i + 1}", 0, enable: lastDay, today: now.month == today.month && todayday == i + 1, tag: "${now.year}-${now.month.toString().padLeft(2, '0')}-${(i + 1).toString().padLeft(2, '0')}"), ); } int end = now.weekday - 1 + inDays; for (var i = end; i < 49; i++) { items.add(_DataItem("", 0)); } var records = await inject().getSportTargetRecord(now.year, now.month); records?.results?.forEach((element) { for (var item in items) { if (item.tag == element.createdAt) { item.state = element.finish == true ? 2 : 1; } } }); return items; } } class _DataItem { final String tag; final String title; final bool enable; final bool today; int state; _DataItem(this.title, this.state, {this.enable = true, this.tag, this.today}); }