123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- 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<StatefulWidget> createState() => _PageState();
- }
- class _PageState extends State<DurationPage> {
- ValueNotifier<DateTime> _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<RestClient>().getSportTargetIndex().asStream().map((event) => event.data).last,
- builder: (BuildContext context, AsyncSnapshot<SportTargetIndex> snapshot) => snapshot.connectionState != ConnectionState.done
- ? RequestLoadingWidget()
- : CustomScrollView(
- slivers: <Widget>[
- // 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: <Widget>[
- 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: <Widget>[
- 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>[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: <Widget>[
- Row(
- children: <Widget>[
- 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: <Widget>[
- 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: <Widget>[
- 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: <Widget>[
- 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: <Widget>[
- 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: <Widget>[
- Center(
- child: ValueListenableBuilder<DateTime>(
- valueListenable: _valueNotifierDate,
- builder: (_, time, ___) {
- return Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- 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<List<_DataItem>>(
- future: createFuture(time),
- builder: (BuildContext context, AsyncSnapshot<List<_DataItem>> 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: <Widget>[
- 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: <Widget>[
- // 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: <Widget>[
- 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: <Widget>[
- 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: <Widget>[
- 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<RestClient>().sportTargetReward(item.id);
- ToastUtil.show("领取成功");
- });
- }
- : null,
- )
- ],
- ),
- );
- },
- crossAxisSpacing: 12.0,
- mainAxisSpacing: 12.0,
- staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
- ),
- ),
- const SizedBox(
- height: 50.0,
- ),
- ],
- ),
- ),
- )
- ],
- ),
- ),
- );
- }
- Future<List<_DataItem>> createFuture(DateTime time) async {
- const List<String> 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<RestClient>().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});
- }
|