kidd3166 3 年之前
父節點
當前提交
e5c51188f6

+ 3 - 0
lib/bean/sport_index.dart

@@ -162,6 +162,9 @@ class Today {
   String strengthLabel() {
       return strengthToLabel(consume);
   }
+
+
+  int value(String type) => type == "consume" ? consume : duration;
 }
 
 const strengthArr = ["低强度" , "强度适中" ,"高强度"];

+ 4 - 0
lib/bean/sport_target.dart

@@ -56,4 +56,8 @@ class SportTarget {
 
     return data;
   }
+
+  int get valueTarget => type == "consume" ? consume : durationMinute;
+
+  String get label => type == "consume" ? "卡" : "分钟";
 }

+ 5 - 2
lib/bean/sport_target_day.dart

@@ -1,5 +1,3 @@
-
-
 class SportTargetDay {
   int id;
   int userId;
@@ -55,4 +53,9 @@ class SportTargetDay {
     data['duration_target_minute'] = this.durationTargetMinute;
     return data;
   }
+
+  int get value => type == "consume" ? consume : durationMinute;
+  int get valueTarget => type == "consume" ? consumeTarget : durationTargetMinute;
+
+  String get label => type == "consume" ? "卡" : "分钟";
 }

+ 7 - 1
lib/pages/home/consume_page.dart

@@ -31,11 +31,13 @@ class _PageState extends State<ConsumePage> with InjectApi {
   ValueNotifier<DateTime> _valueNotifierDate = ValueNotifier(DateTime.now());
   ValueNotifier<DateTime> _valueNotifierNow = ValueNotifier(DateTime.now());
   PageController _pageController;
+  ScrollController _scrollController;
 
   @override
   void initState() {
     super.initState();
     _pageController = PageController(initialPage: 0);
+    _scrollController = ScrollController();
     changeTab();
   }
 
@@ -47,6 +49,7 @@ class _PageState extends State<ConsumePage> with InjectApi {
     _valueNotifierSportDetail?.dispose();
     _valueNotifierDate?.dispose();
     _valueNotifierNow?.dispose();
+    _scrollController?.dispose();
   }
 
   @override
@@ -54,11 +57,13 @@ class _PageState extends State<ConsumePage> with InjectApi {
     final double tabHeader = 100.0;
     final double statusBarHeight = MediaQuery.of(context).padding.top;
     final double pinnedHeaderHeight = tabHeader + statusBarHeight;
+    final double headerHeight = 240.0;
     return Scaffold(
       backgroundColor: Colors.white,
       body: Stack(
         children: <Widget>[
           extended.NestedScrollView(
+            controller: _scrollController,
             pinnedHeaderSliverHeightBuilder: () {
               return pinnedHeaderHeight;
             },
@@ -72,7 +77,7 @@ class _PageState extends State<ConsumePage> with InjectApi {
                 SliverToBoxAdapter(
                   child: Container(
                     width: 240.0,
-                    height: 240.0,
+                    height: headerHeight,
                     child: Align(
                       alignment: Alignment.bottomCenter,
                       child: CustomPaint(
@@ -186,6 +191,7 @@ class _PageState extends State<ConsumePage> with InjectApi {
                                             : InkWell(
                                                 onTap: () {
                                                   if (_valueNotifierSportDetail.value == null) return;
+                                                  _scrollController.animateTo(headerHeight, duration: Duration(milliseconds: 500), curve: Curves.linear);
                                                   _tab.value = e;
                                                   _valueNotifierDate.value = DateTime.now();
                                                   _pageController.jumpToPage(0);

+ 5 - 5
lib/pages/home/duration_page.dart

@@ -85,15 +85,15 @@ class _PageState extends State<DurationPage> {
                             child: CircularPercentIndicator(
                               radius: 140.0,
                               lineWidth: 12.0,
-                              percent: min(1.0, 1.0 * (snapshot.data?.today?.durationMinute ?? 0) / snapshot.data?.today?.durationTargetMinute ?? 0),
+                              percent: min(1.0, 1.0 * (snapshot.data?.today?.value ?? 0) / snapshot.data?.today?.valueTarget ?? 0.01),
                               center: Column(
                                 children: <Widget>[
                                   Text(
-                                    "${snapshot.data?.today?.durationMinute ?? 0}",
+                                    "${snapshot.data?.today?.value ?? 0}",
                                     style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 40.0),
                                   ),
                                   Text(
-                                    "分钟",
+                                    "${snapshot.data?.today?.label}",
                                     style: Theme.of(context).textTheme.subtitle2,
                                     strutStyle: fixedLine,
                                   )
@@ -118,7 +118,7 @@ class _PageState extends State<DurationPage> {
                           Padding(
                             padding: const EdgeInsets.symmetric(vertical: 12.0),
                             child: Text(
-                              "运动目标:${snapshot.data?.today?.durationTargetMinute ?? 0} 分钟",
+                              "运动目标:${snapshot.data?.today?.value ?? 0} ${snapshot.data?.today?.label}",
                               style: Theme.of(context).textTheme.subtitle1,
                             ),
                           ),
@@ -155,7 +155,7 @@ class _PageState extends State<DurationPage> {
                                         style: Theme.of(context).textTheme.subtitle1,
                                       ),
                                       Text(
-                                        "${snapshot.data?.today?.durationTargetMinute ?? 0}分钟",
+                                        "${snapshot.data?.today?.valueTarget ?? 0}${snapshot.data?.today?.label}",
                                         style: Theme.of(context).textTheme.bodyText2,
                                       )
                                     ],

+ 56 - 36
lib/pages/home/home_info_page.dart

@@ -150,12 +150,29 @@ class _PageState extends ViewStateLifecycle<HomeInfoPage, SportIndexModel> with
             // ),
             SliverToBoxAdapter(
               child: Container(
+                height: 250,
                 child: Column(
                   children: <Widget>[
-                    Image.network(
-                      "http://static.ouj.com/hiyd/ddb0170b2edb875baafad8eb05883cf4_size351x182_30730.png",
-                      height: 182,
-                    ),
+                    Container(
+                        height: 182,
+                        child: Selector<Bluetooth, BluetoothDevice>(
+                            selector: (_, bluetooth) => bluetooth.device,
+                            builder: (_, device, ___) {
+                              return device == null
+                                  ? CachedNetworkImage(
+                                      height: 182,
+                                      imageUrl: "http://static.ouj.com/hiyd/fb337b03b0929085f1d07c036cd40ec4_size750x281_115600.png",
+                                    )
+                                  : StreamBuilder<BluetoothDeviceState>(
+                                      stream: device.state,
+                                      initialData: BluetoothDeviceState.connecting,
+                                      builder: (c, snapshot) => CachedNetworkImage(
+                                            height: 182,
+                                            imageUrl: snapshot.data == BluetoothDeviceState.connected
+                                                ? "http://static.ouj.com/hiyd/a856a17e1cd2006a6cd6e7df6b7f1357_size750x285_116051.png"
+                                                : "http://static.ouj.com/hiyd/fb337b03b0929085f1d07c036cd40ec4_size750x281_115600.png",
+                                          ));
+                            })),
                     Space(
                       height: 12,
                     ),
@@ -329,37 +346,40 @@ class _PageState extends ViewStateLifecycle<HomeInfoPage, SportIndexModel> with
                         padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
                         child: Row(
                           children: <Widget>[
-                            CircularPercentIndicator(
-                              radius: 100.0,
-                              lineWidth: 10.0,
-                              percent: min(1.0, 1.0 * (model?.data?.today?.duration ?? 0) / (model.data?.target?.durationMinute ?? 0.01)),
-                              center: Column(
-                                children: <Widget>[
-                                  SizedBox(
-                                    height: 10.0,
-                                  ),
-                                  Text(
-                                    "${model.data?.today?.duration ?? 0}",
-                                    style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 26.0),
-                                    strutStyle: fixedLine,
-                                  ),
-                                  Text(
-                                    "分钟",
-                                    style: Theme.of(context).textTheme.subtitle2,
-                                    strutStyle: fixedLine,
-                                  )
-                                ],
-                                mainAxisSize: MainAxisSize.min,
-                              ),
-                              animation: true,
-                              animationDuration: 1000,
-                              animateFromLastPercent: true,
-                              startAngle: 5,
-                              backgroundColor: Color(0xfff1f1f1),
-                              circularStrokeCap: CircularStrokeCap.round,
-                              rotateLinearGradient: true,
-                              linearGradient: LinearGradient(
-                                colors: <Color>[Color(0xff8DF7FF), Color(0xff16A2FF)],
+                            Padding(
+                              padding: const EdgeInsets.symmetric(vertical: 3.0),
+                              child: CircularPercentIndicator(
+                                radius: 100.0,
+                                lineWidth: 10.0,
+                                percent: min(1.0, 1.0 * (model?.data?.today?.value(model.data?.target?.type) ?? 0) / (model.data?.target?.valueTarget ?? 0.01)),
+                                center: Column(
+                                  children: <Widget>[
+                                    SizedBox(
+                                      height: 10.0,
+                                    ),
+                                    Text(
+                                      "${model.data?.today?.value(model.data?.target?.type) ?? 0}",
+                                      style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 26.0),
+                                      strutStyle: fixedLine,
+                                    ),
+                                    Text(
+                                      "${model.data?.target?.label}",
+                                      style: Theme.of(context).textTheme.subtitle2,
+                                      strutStyle: fixedLine,
+                                    )
+                                  ],
+                                  mainAxisSize: MainAxisSize.min,
+                                ),
+                                animation: true,
+                                animationDuration: 1000,
+                                animateFromLastPercent: true,
+                                startAngle: 5,
+                                backgroundColor: Color(0xfff1f1f1),
+                                circularStrokeCap: CircularStrokeCap.round,
+                                rotateLinearGradient: true,
+                                linearGradient: LinearGradient(
+                                  colors: <Color>[Color(0xff8DF7FF), Color(0xff16A2FF)],
+                                ),
                               ),
                             ),
                             SizedBox(
@@ -369,7 +389,7 @@ class _PageState extends ViewStateLifecycle<HomeInfoPage, SportIndexModel> with
                               crossAxisAlignment: CrossAxisAlignment.start,
                               children: <Widget>[
                                 Text(
-                                  "今日目标:${model.data?.target?.durationMinute ?? 0} 分钟",
+                                  "今日目标:${model.data?.target?.valueTarget ?? 0} ${model.data?.target?.label}",
                                   style: Theme.of(context).textTheme.subtitle1,
                                 ),
                                 SizedBox(

+ 103 - 94
lib/pages/home/sport_history_page.dart

@@ -20,6 +20,7 @@ import 'package:sport/services/api/resp.dart';
 import 'package:sport/utils/DateFormat.dart';
 import 'package:sport/widgets/appbar.dart';
 import 'package:sport/widgets/decoration.dart';
+import 'package:sport/widgets/error.dart';
 import 'package:sport/widgets/loading.dart';
 import 'package:sport/widgets/misc.dart';
 import 'package:sport/widgets/space.dart';
@@ -35,15 +36,16 @@ class SportHistoryPage extends StatefulWidget {
 
 class _PageState extends State<SportHistoryPage> with TickerProviderStateMixin {
   ScrollController _controller;
+  TabController _tabController;
   double _expandedHeight = 230.0;
   int _brightness = 0;
 
   @override
   void initState() {
     super.initState();
+    _tabController = TabController(length: 2, vsync: this);
     _controller = ScrollController()
       ..addListener(() {
-        print("${_controller.position.pixels}  --- ${_expandedHeight}");
         if (_controller.position.pixels >= _expandedHeight / 2) {
           if (_brightness == 0) {
             setState(() {
@@ -61,6 +63,13 @@ class _PageState extends State<SportHistoryPage> with TickerProviderStateMixin {
   }
 
   @override
+  void dispose() {
+    _tabController?.dispose();
+    _controller?.dispose();
+    super.dispose();
+  }
+
+  @override
   Widget build(BuildContext context) {
     final double tabHeader = 40.0;
     final double statusBarHeight = MediaQuery.of(context).padding.top;
@@ -72,16 +81,13 @@ class _PageState extends State<SportHistoryPage> with TickerProviderStateMixin {
             tabHeader;
     return Scaffold(
       backgroundColor: Colors.white,
-      body: DefaultTabController(
-        length: 2,
-        child: extended.NestedScrollView(
+      body: extended.NestedScrollView(
           controller: _controller,
           pinnedHeaderSliverHeightBuilder: () {
             return pinnedHeaderHeight;
           },
           innerScrollPositionKeyBuilder: () {
-            TabController tabController = DefaultTabController.of(context);
-            String index = 'Tab${tabController.index}';
+            String index = 'Tab${_tabController?.index}';
             return Key(index);
           },
           headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
@@ -171,6 +177,7 @@ class _PageState extends State<SportHistoryPage> with TickerProviderStateMixin {
                           margin: EdgeInsets.only(top: 10.0),
                           height: 36.0,
                           child: TabBar(
+                            controller: _tabController,
                             isScrollable: true,
                             labelPadding: EdgeInsets.symmetric(horizontal: 20),
                             indicatorWeight: 3,
@@ -188,7 +195,9 @@ class _PageState extends State<SportHistoryPage> with TickerProviderStateMixin {
               )
             ];
           },
-          body: TabBarView(children: [
+          body: TabBarView(
+              controller: _tabController,
+              children: [
             NestedScrollViewInnerScrollPositionKeyWidget(
               const Key('Tab0'),
               _DataPage(details: widget.details),
@@ -199,7 +208,6 @@ class _PageState extends State<SportHistoryPage> with TickerProviderStateMixin {
             )
           ]),
         ),
-      ),
     );
   }
 }
@@ -269,7 +277,7 @@ class _DataPageState extends State<_DataPage> with InjectApi {
         Divider(),
         _row("datasummary_icon_squat", "下蹲频率", "${sum.crouchRate}", "次/分钟"),
         _row("datasummary_icon_jump", "跳跃频率", "${sum.jumpRate}", "次/分钟"),
-        _row("datasummary_icon_steps", "游戏步数", "${sum.stepRate}", "步"),
+        _row("datasummary_icon_steps", "游戏步数", "${sum.stepCount}", "步"),
       ]),
     );
   }
@@ -323,105 +331,106 @@ class _ListPageState extends ViewStateLifecycle<_ListPage, SportHistoryModel> {
       decoration: BoxDecoration(color: color, shape: BoxShape.circle, boxShadow: [BoxShadow(color: color, blurRadius: 5, offset: Offset(0, 0))]),
     );
 
-    return Scaffold(
-      backgroundColor: Colors.white,
-      body: ProviderWidget<SportHistoryModel>(
+    return TimelineTheme(
+      data: TimelineThemeData(lineColor: const Color(0xffFFC400), strokeWidth: 1),
+      child: ProviderWidget<SportHistoryModel>(
           model: model,
           onModelReady: (model) => model.initData(),
           builder: (_, model, __) {
             var list = model.list;
+            if(list.isEmpty)
+              return RequestErrorWidget(null, msg: "暂无记录",);
             var map = Map.fromIterable(list,
                 key: (key) => key.tag,
                 value: (value) {
                   return list.where((item) => item.tag == value.tag).toList();
                 });
-            // print("$list");
+            // print("11111111111111111111 $list");
             // print("$map");
-            return TimelineTheme(
-                data: TimelineThemeData(lineColor: const Color(0xffFFC400), strokeWidth: 1),
-                child: Timeline(
-                  padding: EdgeInsets.all(12.0),
-                  indicatorSize: 12.0,
-                  events: map.keys.map((e) {
-                    var gameList = map[e];
-                    return TimelineEventDisplay(
-                        child: Column(
-                          crossAxisAlignment: CrossAxisAlignment.start,
-                          children: <Widget>[
-                            Padding(
-                              padding: const EdgeInsets.fromLTRB(12.0, 0, 12.0, 6.0),
-                              child: Text(
-                                e,
-                                style: Theme.of(context).textTheme.bodyText2,
-                                strutStyle: fixedLine,
-                              ),
-                            ),
-                            Column(
-                              children: gameList
-                                  .map((item) => Container(
-                                        margin: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
-                                        padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
-                                        decoration: card(),
-                                        child: Row(
-                                          children: <Widget>[
-                                            ConstrainedBox(
-                                              constraints: BoxConstraints(minWidth: 80.0),
-                                              child: Column(
-                                                children: <Widget>[
-                                                  Text(
-                                                    item.mode == 0 ? "闯关模式" : item.mode == 1 ? "匹配模式" : "好友模式",
-                                                    style: Theme.of(context).textTheme.headline3,
-                                                  ),
-                                                  const SizedBox(
-                                                    height: 3.0,
-                                                  ),
-                                                  Text(
-                                                    "${DateFormat.formatCreateAtHHmm(item.createdAt)}",
-                                                    style: Theme.of(context).textTheme.bodyText2,
-                                                  ),
-                                                ],
+            return Timeline(
+              primary: true,
+              padding: EdgeInsets.fromLTRB(12.0, 24.0, 12.0, 12.0),
+              indicatorSize: 12.0,
+              events: map.keys.map((e) {
+                var gameList = map[e];
+                return TimelineEventDisplay(
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: <Widget>[
+                        Padding(
+                          padding: const EdgeInsets.fromLTRB(12.0, 0, 12.0, 6.0),
+                          child: Text(
+                            e,
+                            style: Theme.of(context).textTheme.bodyText2,
+                          ),
+                        ),
+                        Column(
+                          children: gameList
+                              .map((item) => Container(
+                                    margin: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
+                                    padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
+                                    decoration: card(),
+                                    child: Row(
+                                      children: <Widget>[
+                                        ConstrainedBox(
+                                          constraints: BoxConstraints(minWidth: 80.0),
+                                          child: Column(
+                                            children: <Widget>[
+                                              Text(
+                                                item.mode == 0 ? "闯关模式" : item.mode == 1 ? "匹配模式" : "好友模式",
+                                                style: Theme.of(context).textTheme.headline3,
                                               ),
+                                              const SizedBox(
+                                                height: 3.0,
+                                              ),
+                                              Text(
+                                                "${DateFormat.formatCreateAtHHmm(item.createdAt)}",
+                                                style: Theme.of(context).textTheme.bodyText2,
+                                              ),
+                                            ],
+                                          ),
+                                        ),
+                                        Container(
+                                          margin: const EdgeInsets.symmetric(horizontal: 16.0),
+                                          height: 70.0,
+                                          child: DashedRect(color: Color(0xff979797), strokeWidth: 0.5, gap: 3.0),
+                                        ),
+                                        Column(
+                                          crossAxisAlignment: CrossAxisAlignment.start,
+                                          children: <Widget>[
+                                            Text(
+                                              "评分:${item.score}",
+                                              style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
                                             ),
-                                            Container(
-                                              margin: const EdgeInsets.symmetric(horizontal: 16.0),
-                                              height: 70.0,
-                                              child: DashedRect(color: Color(0xff979797), strokeWidth: 0.5, gap: 3.0),
+                                            const SizedBox(
+                                              height: 3.0,
+                                            ),
+                                            Text(
+                                              "时长:${(item.duration ?? 0) ~/ 60}分${(item.duration ?? 0) % 60}秒",
+                                              style: Theme.of(context).textTheme.subtitle1,
+                                            ),
+                                            const SizedBox(
+                                              height: 3.0,
+                                            ),
+                                            Text(
+                                              "消耗:${item.consume} 卡",
+                                              style: Theme.of(context).textTheme.subtitle1,
                                             ),
-                                            Column(
-                                              crossAxisAlignment: CrossAxisAlignment.start,
-                                              children: <Widget>[
-                                                Text(
-                                                  "评分:${item.score}",
-                                                  style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
-                                                ),
-                                                const SizedBox(
-                                                  height: 3.0,
-                                                ),
-                                                Text(
-                                                  "时长:${(item.duration ??0) ~/ 60}分${(item.duration ??0) % 60}秒",
-                                                  style: Theme.of(context).textTheme.subtitle1,
-                                                ),
-                                                const SizedBox(
-                                                  height: 3.0,
-                                                ),
-                                                Text(
-                                                  "消耗:${item.consume} 卡",
-                                                  style: Theme.of(context).textTheme.subtitle1,
-                                                ),
-                                              ],
-                                            )
                                           ],
-                                        ),
-                                      ))
-                                  .toList(),
-                            )
-                          ],
-                        ),
-                        indicatorSize: 9.0,
-                        indicator: dot);
-                  }).toList(),
-                  anchor: IndicatorPosition.top,
-                ));
+                                        )
+                                      ],
+                                    ),
+                                  ))
+                              .toList(),
+                        )
+                      ],
+                    ),
+                    indicatorSize: 9.0,
+                    indicatorOffset: Offset(0, 3.5),
+                    indicator: dot);
+              }).toList(),
+              anchor: IndicatorPosition.top,
+            );
           }),
     );
   }

+ 2 - 2
lib/pages/home/step_page.dart

@@ -230,7 +230,7 @@ class _PageState extends State<StepPage> with TickerProviderStateMixin, InjectAp
                                                     height: 10,
                                                   ),
                                                   Text(
-                                                    "运动总公里",
+                                                    "运动总距离",
                                                     style: Theme.of(context).textTheme.subtitle1,
                                                   ),
                                                   Space(
@@ -239,7 +239,7 @@ class _PageState extends State<StepPage> with TickerProviderStateMixin, InjectAp
                                                   RichText(
                                                     text: TextSpan(style: Theme.of(context).textTheme.subtitle2, children: <InlineSpan>[
                                                       TextSpan(
-                                                          text: '${_value == null ? ".." : "${(_value.sum.distance ~/ 100)}"}',
+                                                          text: '${_value == null ? ".." : "${((_value.sum.stepDaily + _value.sum.stepGame) * .6).toStringAsFixed(1)}"}',
                                                           style: Theme.of(context).textTheme.subtitle2.copyWith(fontWeight: FontWeight.bold, fontSize: 25)),
                                                       TextSpan(text: ' 米', style: Theme.of(context).textTheme.subtitle1),
                                                     ]),

+ 3 - 3
lib/pages/home/strength_page.dart

@@ -217,9 +217,9 @@ class _PageState extends State<StrengthPage> with InjectApi {
                                     return GestureDetector(
                                         behavior: HitTestBehavior.opaque,
                                         onTap: () {
-                                          _valueNotifierIndex.value = index;
-                                          var page = max(0, strengthArr.indexOf(strengthToLabel(list[index].data)));
-                                          _swiperController?.move(page);
+                                          // _valueNotifierIndex.value = index;
+                                          // var page = max(0, strengthArr.indexOf(strengthToLabel(list[index].data)));
+                                          // _swiperController?.move(page);
                                         },
                                         child: Column(
                                           mainAxisAlignment: MainAxisAlignment.end,

+ 1 - 2
lib/provider/bluetooth.dart

@@ -211,11 +211,10 @@ class Bluetooth with ChangeNotifier, InjectApi {
         _online = true;
         flutterBlue.stopScan();
         ToastUtil.show("${device?.name} 已连接");
+        _stateController.add(true);
 
         await discoverServices(device);
         await Future.delayed(Duration(seconds: 2));
-        _stateController.add(true);
-
         await queryDeviceInfo();
         await Future.delayed(Duration(seconds: 1));
         await queryDeviceData();