Bläddra i källkod

fix:v1.3.1版本的UI

Primroses 3 år sedan
förälder
incheckning
9fe28f3af7

BIN
lib/assets/img/function_icon_run.png


BIN
lib/assets/img/function_icon_steps.png


BIN
lib/assets/img/function_icon_weight.png


BIN
lib/assets/img/game_icon_function.png


BIN
lib/assets/img/mall_bg_home.png


BIN
lib/assets/img/mall_img_card.png


BIN
lib/assets/img/rank_btn_myrank.png


BIN
lib/assets/img/rank_icon_first.png


BIN
lib/assets/img/rank_icon_second.png


BIN
lib/assets/img/rank_icon_third.png


+ 179 - 0
lib/bean/shop.dart

@@ -0,0 +1,179 @@
+class ShopIndex {
+  Shop shop;
+  List<Items> items;
+  ShopUser user;
+
+  ShopIndex({this.shop, this.items, this.user});
+
+  ShopIndex.fromJson(Map<String, dynamic> json) {
+    print(json);
+    shop = json['shop'] != null ? new Shop.fromJson(json['shop']) : null;
+    if (json['items'] != null) {
+      items = new List<Items>();
+      json['items'].forEach((v) {
+        items.add(new Items.fromJson(v));
+      });
+    }
+    user = json['user'] != null ? new ShopUser.fromJson(json['user']) : null;
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    if (this.shop != null) {
+      data['shop'] = this.shop.toJson();
+    }
+    if (this.items != null) {
+      data['items'] = this.items.map((v) => v.toJson()).toList();
+    }
+    if (this.user != null) {
+      data['user'] = this.user.toJson();
+    }
+    return data;
+  }
+}
+
+class Shop {
+  int id;
+  int gameId;
+  String name;
+  String type;
+
+  Shop({this.id, this.gameId, this.name, this.type});
+
+  Shop.fromJson(Map<String, dynamic> json) {
+    id = json['id'];
+    gameId = json['game_id'];
+    name = json['name'];
+    type = json['type'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['id'] = this.id;
+    data['game_id'] = this.gameId;
+    data['name'] = this.name;
+    data['type'] = this.type;
+    return data;
+  }
+}
+
+class Items {
+  int id;
+  int shopId;
+  int gameId;
+  String name;
+  String logo;
+  int price;
+  String detail;
+  int valid;
+
+  Items(
+      {this.id,
+        this.shopId,
+        this.gameId,
+        this.name,
+        this.logo,
+        this.price,
+        this.detail,
+        this.valid});
+
+  Items.fromJson(Map<String, dynamic> json) {
+    id = json['id'];
+    shopId = json['shop_id'];
+    gameId = json['game_id'];
+    name = json['name'];
+    logo = json['logo'];
+    price = json['price'];
+    detail = json['detail'];
+    valid = json['valid'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['id'] = this.id;
+    data['shop_id'] = this.shopId;
+    data['game_id'] = this.gameId;
+    data['name'] = this.name;
+    data['logo'] = this.logo;
+    data['price'] = this.price;
+    data['detail'] = this.detail;
+    data['valid'] = this.valid;
+    return data;
+  }
+}
+
+class ShopUser {
+  int score;
+
+  ShopUser({this.score});
+
+  ShopUser.fromJson(Map<String, dynamic> json) {
+    score = json['score'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['score'] = this.score;
+    return data;
+  }
+}
+
+class ScoreList {
+  List<ScoreListData> data;
+
+  ScoreList({this.data});
+
+  ScoreList.fromJson(Map<String, dynamic> json) {
+    if (json['data'] != null) {
+      data = new List<ScoreListData>();
+      json['data'].forEach((v) {
+        data.add(new ScoreListData.fromJson(v));
+      });
+    }
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    if (this.data != null) {
+      data['data'] = this.data.map((v) => v.toJson()).toList();
+    }
+    return data;
+  }
+}
+
+class ScoreListData {
+  int id;
+  int userId;
+  int score;
+  String from;
+  String detail;
+  String createdAt;
+
+  ScoreListData(
+      {this.id,
+        this.userId,
+        this.score,
+        this.from,
+        this.detail,
+        this.createdAt});
+
+  ScoreListData.fromJson(Map<String, dynamic> json) {
+    id = json['id'];
+    userId = json['user_id'];
+    score = json['score'];
+    from = json['from'];
+    detail = json['detail'];
+    createdAt = json['created_at'];
+  }
+
+  Map<String, dynamic> toJson() {
+    final Map<String, dynamic> data = new Map<String, dynamic>();
+    data['id'] = this.id;
+    data['user_id'] = this.userId;
+    data['score'] = this.score;
+    data['from'] = this.from;
+    data['detail'] = this.detail;
+    data['created_at'] = this.createdAt;
+    return data;
+  }
+}

+ 322 - 165
lib/pages/game/rank_detail.dart

@@ -1,10 +1,13 @@
 import 'dart:convert';
+import 'dart:io';
 
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:provider/provider.dart';
 import 'package:sport/bean/rank_game_info.dart';
 import 'package:sport/bean/user.dart';
+import 'package:sport/pages/my/shop_detail.dart';
 import 'package:sport/provider/user_model.dart';
 import 'package:sport/router/navigator_util.dart';
 import 'package:sport/router/routes.dart';
@@ -14,6 +17,9 @@ import 'package:sport/widgets/decoration.dart';
 import 'package:sport/widgets/image.dart';
 import 'package:sport/widgets/loading.dart';
 import 'package:sport/widgets/space.dart';
+import 'package:sport/widgets/persistent_header.dart';
+import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
+import 'package:shared_preferences/shared_preferences.dart';
 
 class RankDetailPage extends StatefulWidget {
   final String id;
@@ -27,12 +33,27 @@ class RankDetailPage extends StatefulWidget {
   }
 }
 
-class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
+class _RankDetailPageState extends State<RankDetailPage>
+    with TickerProviderStateMixin, InjectApi {
   bool _isLoading;
   RankGameInfoData _data;
   String _id;
-
+  ScrollController _controller = new ScrollController();
+  final ItemScrollController itemScrollController = ItemScrollController();
+  final ItemPositionsListener itemPositionsListener =
+      ItemPositionsListener.create();
+  TabController _tabController;
+  final List<String> _tabs = [
+    '世界榜',
+    '好友榜',
+  ];
   String _rank;
+  final List<String> rankImages = [
+    "",
+    "rank_icon_first.png",
+    "rank_icon_second.png",
+    "rank_icon_third.png",
+  ];
 
   @override
   void initState() {
@@ -45,14 +66,44 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
     } else {
       _isLoading = false;
     }
+    _tabController =
+        TabController(length: _tabs.length, initialIndex: 0, vsync: this)
+          ..addListener(() async {
+            SharedPreferences prefs = await SharedPreferences.getInstance();
+            String _scope = _tabController.index == 0 ? "world": "friend";
+            // if(_tabController.index == 0)
+            // print(_tabController.index);
+            _data = (await api.getRankGameInfo(widget.id,scope: _scope)).data;
+            if (_data.user != null && _data.user.position > 10) {
+              _data.records.add(_data.user);
+            } else if (_data.user == null) {
+              _data.records.add(new User(
+                  userName: prefs.getString("name"),
+                  userAvatar: prefs.getString("avatar")));
+            }
+          });
   }
 
+  // @override
+  // void dispose() {
+  //   _controller?.dispose();
+  // }
+
   // 缓存数据...
   initData() async {
+    SharedPreferences prefs = await SharedPreferences.getInstance();
     if (widget.type == "1") {
       api.getRankGameInfo(widget.id).then((data) {
         setState(() {
           _data = data.data;
+          print("${data.data.user}====================");
+          if (data.data.user != null && data.data.user.position > 10) {
+            _data.records.add(data.data.user);
+          } else if (data.data.user == null) {
+            _data.records.add(new User(
+                userName: prefs.getString("name"),
+                userAvatar: prefs.getString("avatar")));
+          }
           _isLoading = false;
         });
       });
@@ -60,39 +111,57 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
       api.getRankSportInfo(widget.id).then((data) {
         setState(() {
           _data = data.data;
+          print("${data.data.user}====================");
+          if (data.data.user != null && data.data.user.position > 10) {
+            _data.records.add(data.data.user);
+          } else if (data.data.user == null) {
+            _data.records.add(new User(
+                userName: prefs.getString("name"),
+                userAvatar: prefs.getString("avatar")));
+          }
           _isLoading = false;
         });
       });
     }
   }
 
-  area(bool all, bool province, int provinceId, int cityId) {
-    setState(() {
-      _isLoading = true;
-    });
-    if (widget.type == "1") {
-      api.getRankGameInfo(widget.id, provinceId: all ? null : provinceId, cityId: all ? null : province ? null : cityId).then((data) {
-        setState(() {
-          _data = data.data;
-          _isLoading = false;
-        });
-      });
-    } else {
-      api.getRankSportInfo(widget.id, provinceId: all ? null : provinceId, cityId: all ? null : province ? null : cityId).then((data) {
-        setState(() {
-          _data = data.data;
-          _isLoading = false;
-        });
-      });
-    }
-  }
+  // area(bool all, bool province, int provinceId, int cityId) {
+  //   setState(() {
+  //     _isLoading = true;
+  //   });
+  //   if (widget.type == "1") {
+  //     api
+  //         .getRankGameInfo(widget.id,
+  //             )
+  //         .then((data) {
+  //       setState(() {
+  //         _data = data.data;
+  //         _isLoading = false;
+  //       });
+  //     });
+  //   } else {
+  //     api
+  //         .getRankSportInfo(widget.id,
+  //             provinceId: all ? null : provinceId,
+  //             cityId: all ? null : province ? null : cityId)
+  //         .then((data) {
+  //       setState(() {
+  //         _data = data.data;
+  //         _isLoading = false;
+  //       });
+  //     });
+  //   }
+  // }
 
   initUser(int rank) {
     return User(position: rank, userName: '虚位以待', score: 0, id: 0);
   }
 
   Widget _buildRankWidget() {
-    dynamic user1 = initUser(1), user2 = initUser(2), user3 = initUser(3), user4;
+    dynamic user1 = initUser(1),
+        user2 = initUser(2),
+        user3 = initUser(3),
+        user4;
     if (_data != null && _data.records != null) {
       for (var i = 0; i < _data.records.length; i++) {
         var item = _data.records[i];
@@ -113,9 +182,21 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
             mainAxisAlignment: MainAxisAlignment.spaceEvenly,
             crossAxisAlignment: CrossAxisAlignment.end,
             children: <Widget>[
-              Container(width: 94, child: user2 != null ? _buildRankHeaderWidget(user2) : _buildRankHeaderWidget(initUser(2))),
-              Container(width: 120, child: user1 != null ? _buildRankHeaderWidget(user1) : _buildRankHeaderWidget(initUser(1))),
-              Container(width: 94, child: user3 != null ? _buildRankHeaderWidget(user3) : _buildRankHeaderWidget(initUser(3))),
+              Container(
+                  width: 94,
+                  child: user2 != null
+                      ? _buildRankHeaderWidget(user2)
+                      : _buildRankHeaderWidget(initUser(2))),
+              Container(
+                  width: 120,
+                  child: user1 != null
+                      ? _buildRankHeaderWidget(user1)
+                      : _buildRankHeaderWidget(initUser(1))),
+              Container(
+                  width: 94,
+                  child: user3 != null
+                      ? _buildRankHeaderWidget(user3)
+                      : _buildRankHeaderWidget(initUser(3))),
             ],
           ),
         ),
@@ -140,7 +221,10 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
               ? Stack(
                   alignment: Alignment.center,
                   children: <Widget>[
-                    CircleAvatar(backgroundImage: userAvatarProvider(user.userAvatar == null ? "" : user.userAvatar), radius: 46.0),
+                    CircleAvatar(
+                        backgroundImage: userAvatarProvider(
+                            user.userAvatar == null ? "" : user.userAvatar),
+                        radius: 46.0),
                     Image.asset(
                       "lib/assets/img/rank_image_no$rank.png",
                     )
@@ -149,7 +233,12 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
               : Stack(
                   alignment: Alignment.topCenter,
                   children: <Widget>[
-                    Positioned(top: 3, child: CircleAvatar(backgroundImage: userAvatarProvider(user.userAvatar == null ? "" : user.userAvatar), radius: 35.0)),
+                    Positioned(
+                        top: 3,
+                        child: CircleAvatar(
+                            backgroundImage: userAvatarProvider(
+                                user.userAvatar == null ? "" : user.userAvatar),
+                            radius: 35.0)),
                     Image.asset(
                       "lib/assets/img/rank_image_no$rank.png",
                     )
@@ -170,34 +259,35 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
         ],
       ),
       onTap: () {
-        if (user.id != 0) NavigatorUtil.goRankPeopleDetails(context, details: user);
+        if (user.id != 0)
+          NavigatorUtil.goRankPeopleDetails(context, details: user);
       },
     );
   }
 
   Widget _buildRankItemWidget(int number, User data) {
+    // print("lib/assets/img/${rankImages[number]}")
     return Column(
       children: <Widget>[
         InkWell(
           onTap: () {
             if (data is User) {
-              if (data.id != 0) NavigatorUtil.goRankPeopleDetails(context, details: data);
+              if (data.id != 0)
+                NavigatorUtil.goRankPeopleDetails(context, details: data);
             }
           },
           child: Container(
             padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
             child: Row(
               children: <Widget>[
-                Container(
-                  width: 20,
-                  child: Text(
-                    "$number",
-                    style: Theme.of(context).textTheme.bodyText2,
-                  ),
-                ),
+                _buildTitle(number, data.id != null),
                 Padding(
                   padding: const EdgeInsets.fromLTRB(0, 6, 10.0, 6),
-                  child: CircleAvatar(backgroundColor:Colors.transparent, backgroundImage: userAvatarProvider(data.userAvatar == null ? "" : data.userAvatar), radius: 22),
+                  child: CircleAvatar(
+                      backgroundColor: Colors.transparent,
+                      backgroundImage: userAvatarProvider(
+                          data.userAvatar == null ? "" : data.userAvatar),
+                      radius: 22),
                 ),
                 Expanded(
                   child: Text(
@@ -223,7 +313,7 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
   List<Widget> getRankItems() {
     List<Widget> rankItems = [];
     if (_data != null && _data.records != null) {
-      for (var i = 3; i < _data.records.length; i++) {
+      for (var i = 0; i < _data.records.length; i++) {
         var item = _data.records[i];
         rankItems.add(_buildRankItemWidget(i + 1, item));
       }
@@ -264,7 +354,8 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
                   ? _data.user.up != 0 && _data.user.upNew != 0
                       ? Padding(
                           padding: EdgeInsets.only(right: 8),
-                          child: Image.asset("lib/assets/img/rand_icon_${_data.user.up >= 0 ? 'top' : 'down'}.png"),
+                          child: Image.asset(
+                              "lib/assets/img/rand_icon_${_data.user.up >= 0 ? 'top' : 'down'}.png"),
                         )
                       : Container()
                   : Container(),
@@ -275,7 +366,12 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
                       return Row(
                         mainAxisSize: MainAxisSize.max,
                         children: <Widget>[
-                          CircleAvatar(backgroundImage: userAvatarProvider(model?.user?.avatar != null ? model.user.avatar : ""), radius: 22),
+                          CircleAvatar(
+                              backgroundImage: userAvatarProvider(
+                                  model?.user?.avatar != null
+                                      ? model.user.avatar
+                                      : ""),
+                              radius: 22),
                           SizedBox(
                             width: 10,
                           ),
@@ -295,7 +391,17 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
                   ),
                 ),
               ),
-              _data.user == null ? Text("暂无记录", style: Theme.of(context).textTheme.bodyText1,) : _data.rank.userCountMax < _data.user.position ? Text("暂未上榜", style: Theme.of(context).textTheme.bodyText1,) : _dataText(_data.rank, _data.user),
+              _data.user == null
+                  ? Text(
+                      "暂无记录",
+                      style: Theme.of(context).textTheme.bodyText1,
+                    )
+                  : _data.rank.userCountMax < _data.user.position
+                      ? Text(
+                          "暂未上榜",
+                          style: Theme.of(context).textTheme.bodyText1,
+                        )
+                      : _dataText(_data.rank, _data.user),
               Container(
                 width: 12.0,
                 height: 14.0,
@@ -316,13 +422,19 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
     var unit = _dataUnit(rank);
     if (rank != null) {
       if (rank.field == null || rank.field == "") {
-        return Text(user.score == null || user.score == 0 ? "" : "${user.score.toStringAsFixed(1)}$unit",
+        return Text(
+            user.score == null || user.score == 0
+                ? "暂无成绩"
+                : "${user.score.toStringAsFixed(1)}$unit",
             style: TextStyle(color: Color.fromRGBO(255, 196, 0, 1)));
       } else {
         if (rank.field == 'consume') {
-          return Text(user.consume == null ? "" : "${user.consume.round()}$unit", style: TextStyle(color: Color.fromRGBO(255, 196, 0, 1)));
+          return Text(
+              user.consume == null ? "" : "${user.consume.round()}$unit",
+              style: TextStyle(color: Color.fromRGBO(255, 196, 0, 1)));
         } else if (rank.field == 'duration') {
-          return Text(user.duration == null ? "" : "${user.duration}$unit", style: TextStyle(color: Color.fromRGBO(255, 196, 0, 1)));
+          return Text(user.duration == null ? "" : "${user.duration}$unit",
+              style: TextStyle(color: Color.fromRGBO(255, 196, 0, 1)));
         }
       }
     }
@@ -344,140 +456,185 @@ class _RankDetailPageState extends State<RankDetailPage> with InjectApi {
     return "";
   }
 
+  Widget _buildTitle(int number, bool isInRank) {
+    // 直接先未上榜的...
+    if (number > 10 || !isInRank)
+      return Container(
+        width: 40,
+        margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
+        child: Text(
+          "未上榜",
+          style: Theme.of(context).textTheme.bodyText2.copyWith(fontSize: 11.0),
+        ),
+      );
+    // 这里是 看是 前三 还是后七
+    if (number <= rankImages.length - 1 && rankImages[number] != null)
+      return Container(
+          margin: EdgeInsets.fromLTRB(0, 0, 5, 0),
+          width: 25.0,
+          child: Image.asset("lib/assets/img/${rankImages[number]}"));
+    else {
+      return Container(
+        width: 20,
+        margin: EdgeInsets.fromLTRB(5, 0, 5, 0),
+        child: Text(
+          "$number",
+          style: Theme.of(context).textTheme.bodyText2,
+        ),
+      );
+    }
+  }
+
   @override
   Widget build(BuildContext context) {
-    return Scaffold(
-        backgroundColor: Colors.white,
-        body: SingleChildScrollView(
-          child: Column(
-            children: <Widget>[
-              //header
-              Stack(
-                overflow: Overflow.visible,
-                children: <Widget>[
-                  Container(
+    return AnnotatedRegion<SystemUiOverlayStyle>(
+        value: SystemUiOverlayStyle.light,
+        child: Scaffold(
+            backgroundColor: Colors.white,
+            body: Stack(
+              fit: StackFit.expand,
+              children: <Widget>[
+                Align(
+                  alignment: Alignment.topCenter,
+                  child: Container(
                       width: MediaQuery.of(context).size.width,
                       height: MediaQuery.of(context).size.width * 611 / 1125,
-                      decoration: BoxDecoration(image: DecorationImage(image: AssetImage("lib/assets/img/rank_bg.png"), fit: BoxFit.fill)),
+                      decoration: BoxDecoration(
+                          image: DecorationImage(
+                              image: AssetImage("lib/assets/img/rank_bg.png"),
+                              fit: BoxFit.cover)),
                       child: SafeArea(
                         child: Align(
                           alignment: Alignment.centerLeft,
                           child: Padding(
                             padding: const EdgeInsets.symmetric(horizontal: 12),
-                            child: _data?.rank == null
-                                ? Container()
-                                : Column(
-                                    crossAxisAlignment: CrossAxisAlignment.start,
-                                    mainAxisSize: MainAxisSize.min,
-                                    children: <Widget>[
-                                      Padding(
-                                        padding: EdgeInsets.symmetric(vertical: 6.0),
-                                        child: Text(
-                                          "${_data.rank.name}",
-                                          style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.w600),
-                                        ),
-                                      ),
-                                      Padding(
-                                        padding: EdgeInsets.symmetric(vertical: 2.0),
-                                        child: Text(
-                                          "${_data.rank.introduce}",
-                                          style: Theme.of(context).textTheme.bodyText1,
-                                        ),
-                                      ),
-                                      Padding(
-                                        padding: EdgeInsets.symmetric(vertical: 2.0),
-                                        child: Text(
-                                          "${_data.rank.rateBegin} ~ ${_data.rank.rateEnd}",
-                                          style: Theme.of(context).textTheme.bodyText1,
-                                        ),
-                                      ),
-                                      SizedBox(
-                                        height: 10,
-                                      )
-                                    ],
-                                  ),
+                            child: Column(
+                              crossAxisAlignment: CrossAxisAlignment.start,
+                              mainAxisSize: MainAxisSize.min,
+                              children: <Widget>[],
+                            ),
                           ),
                         ),
                       )),
-                  if (_data != null) getUserRank(),
-                  Positioned(
-                      left: 0.0,
-                      top: 0.0,
-                      child: SafeArea(
-                        child: IconButton(
-                          icon: Image.asset("lib/assets/img/topbar_return_white.png"),
-                          onPressed: () {
-                            Navigator.pop(context);
-                          },
-                        ),
-                      )),
+                ),
+                if (!_isLoading)
+                  SafeArea(
+                    child: Padding(
+                      padding: EdgeInsets.fromLTRB(24.0, 36.0, 0, 0),
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        mainAxisSize: MainAxisSize.min,
+                        children: <Widget>[
+                          Padding(
+                            padding: EdgeInsets.symmetric(vertical: 6.0),
+                            child: Text(
+                              "${_data.rank.name}",
+                              style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 20,
+                                  fontWeight: FontWeight.w600),
+                            ),
+                          ),
+                          Padding(
+                            padding: EdgeInsets.symmetric(vertical: 2.0),
+                            child: Text(
+                              "${_data.rank.introduce}",
+                              style: Theme.of(context).textTheme.bodyText1,
+                            ),
+                          ),
+                          GestureDetector(
+                            onTap: (){
+                              itemScrollController.scrollTo(index: _data?.user?.position??_data.records.length-1, duration: Duration(microseconds: 10));
+                            },
+                              child: Container(
+                                  margin: EdgeInsets.fromLTRB(0.0, 12.0, 0, 0),
+                                  child: Image.asset(
+                                    "lib/assets/img/rank_btn_myrank.png",
+                                    width: 103.0,
+                                    height: 28.0,
+                                  ))),
+                        ],
+                      ),
+                    ),
+                  ),
+                if (_isLoading) Container(child: RequestLoadingWidget()),
+                Positioned(
+                    left: 0.0,
+                    top: 0.0,
+                    child: SafeArea(
+                      child: IconButton(
+                        icon: Image.asset(
+                            "lib/assets/img/topbar_return_white.png"),
+                        onPressed: () {
+                          Navigator.pop(context);
+                        },
+                      ),
+                    )),
+                Positioned(
+                    top: 0,
+                    right: 0,
+                    child: SafeArea(
+                      child: IconButton(
+                        icon: Image.asset("lib/assets/img/topbar_problom.png"),
+                        onPressed: () {
+                          if (_data == null) return;
+                          NavigatorUtil.go(context,
+                              "${Routes.rankIntroduce}?data=${Uri.encodeComponent(json.encode(_data))}");
+                        },
+                      ),
+                    )),
+                if (!_isLoading)
                   Positioned(
-                      top: 0,
+                      top: MediaQuery.of(context).size.width * 611 / 1125 - 10,
+                      left: 0,
                       right: 0,
-                      child: SafeArea(
-                        child: IconButton(
-                          icon: Image.asset("lib/assets/img/topbar_problom.png"),
-                          onPressed: () {
-                            if(_data == null)
-                              return;
-
-                            NavigatorUtil.go(context, "${Routes.rankIntroduce}?data=${Uri.encodeComponent(json.encode(_data))}");
-                          },
-                        ),
+                      bottom: 0,
+                      child: CustomScrollView(
+                        controller: _controller,
+                        slivers: <Widget>[
+                          SliverPersistentHeader(
+                            delegate: PersistentHeader(
+                                min: 60,
+                                max: 60,
+                                child: Container(
+                                  height: 80.0,
+                                  alignment: Alignment.center,
+                                  decoration: BoxDecoration(
+                                    borderRadius: BorderRadius.only(
+                                        topRight: Radius.circular(10.0),
+                                        topLeft: Radius.circular(10.0)),
+                                    color: Colors.white,
+                                  ),
+                                  padding:
+                                      EdgeInsets.only(bottom: 10, top: 10.0),
+                                  child: TabBar(
+                                    isScrollable: true,
+                                    indicatorPadding:
+                                        EdgeInsets.symmetric(horizontal: 8),
+                                    indicatorWeight: 3,
+                                    labelPadding:
+                                        EdgeInsets.symmetric(horizontal: 30),
+                                    controller: _tabController,
+                                    tabs:
+                                        _tabs.map((e) => Tab(text: e)).toList(),
+                                  ),
+                                )),
+                            pinned: true,
+                          ),
+                          SliverFillRemaining(
+                            child: ScrollablePositionedList.builder(
+                              itemCount: _data.records.length,
+                              itemBuilder: (context, index) {
+                                return _buildRankItemWidget(
+                                    index + 1, _data.records[index]);
+                              },
+                              itemScrollController: itemScrollController,
+                              itemPositionsListener: itemPositionsListener,
+                            ),
+                          ),
+                        ],
                       ))
-                ],
-              ),
-              if (!_isLoading)
-                Padding(
-                  padding: const EdgeInsets.only(top: 50.0),
-                  child: Row(
-                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                    children: <Widget>[
-                      Consumer<UserModel>(
-                        builder: (_, model, __) => model.user.city == null || _rank == "全国榜" || _rank == null
-                            ? Container()
-                            : Container(
-                                padding: EdgeInsets.symmetric(horizontal: 12.0),
-                                child: Row(
-                                  children: <Widget>[
-                                    Image.asset("lib/assets/img/rank_icon_position.png"),
-                                    SizedBox(
-                                      width: 6,
-                                    ),
-                                    Text(
-                                      "${_rank == '全省榜' ? model.user?.province : model.user?.city}",
-                                      style: Theme.of(context).textTheme.bodyText2,
-                                    )
-                                  ],
-                                ),
-                              ),
-                      ),
-                      NotificationListener<AreaNotification>(
-                        onNotification: (n) {
-                          _rank = n.rank;
-                          area(n.all, n.province, n.provinceId, n.cityId);
-                          return true;
-                        },
-                        child: AreaPage(
-                          area: _rank,
-                        ),
-                      )
-                    ],
-                  ),
-                ),
-              if (_isLoading)
-                Container(child: RequestLoadingWidget()),
-              if (!_isLoading)
-                Padding(
-                  padding: EdgeInsets.only(top: 12.0),
-                  child: _buildRankWidget(),
-                ),
-              if (!_isLoading)
-                Column(
-                  children: getRankItems(),
-                )
-            ],
-          ),
-        ));
+              ],
+            )));
   }
 }

+ 214 - 142
lib/pages/home/sport_list_page.dart

@@ -13,8 +13,11 @@ import 'package:sport/widgets/game_run.dart';
 import 'package:sport/widgets/loading.dart';
 import 'package:sport/widgets/misc.dart';
 
+import '../../widgets/game_run.dart';
+
 class SportListPage extends StatefulWidget {
-  SportListPage();
+  final ValueNotifier<int> index;
+  SportListPage({this.index});
 
   @override
   State<StatefulWidget> createState() => _PageState();
@@ -22,13 +25,18 @@ class SportListPage extends StatefulWidget {
 
 class _PageState extends State<SportListPage> with InjectApi {
   Future<RespList<GameInfoData>> _future;
-
+  ValueNotifier<int> index; // 渲染中间部分的
   @override
   void initState() {
     super.initState();
+    index = widget.index ?? ValueNotifier(0);
     _future = api.getGameAll();
   }
 
+  changeIndex(int newIndex) {
+    index.value = newIndex;
+  }
+
   @override
   Widget build(BuildContext context) {
     var _padding = const EdgeInsets.symmetric(vertical: 6.0);
@@ -38,148 +46,212 @@ class _PageState extends State<SportListPage> with InjectApi {
       child: Scaffold(
         backgroundColor: Colors.transparent.withOpacity(0.5),
         body: GestureDetector(
-          onTap: () => Navigator.maybePop(context),
-          behavior: HitTestBehavior.opaque,
-          child: Center(
-            child: Padding(
-              padding: const EdgeInsets.fromLTRB(0, 80.0, 0, 20.0),
-              child: Column(
-                children: <Widget>[
-                  Padding(
-                    padding: const EdgeInsets.all(12.0),
-                    child: Stack(
-                      alignment: Alignment.center,
-                      children: <Widget>[
-                        Image.asset(
-                          "lib/assets/img/mine_image_achievement.png",
-                          fit: BoxFit.fitWidth,
-                          width: 240,
-                        ),
-                        Text(
-                          "运动列表",
-                          style: Theme.of(context).textTheme.headline4,
-                          strutStyle: fixedLine,
-                        )
-                      ],
-                    ),
-                  ),
-                  Expanded(
-                    child: SingleChildScrollView(
-                      child: Padding(
-                        padding: const EdgeInsets.all(12.0),
-                        child: Column(
-                          children: <Widget>[
-                            Container(
-                              margin: _padding,
-                              child: GameRun(),
-                              decoration: circular(),
-                            ),
-                            FutureBuilder(
-                              future: _future,
-                              builder: (BuildContext context, AsyncSnapshot<RespList<GameInfoData>> snapshot) {
-                                if (snapshot.connectionState != ConnectionState.done) return RequestLoadingWidget();
-                                var list = snapshot.data?.results;
-                                return Column(
-                                    children: list
-                                        .map((e) => Padding(
-                                            padding: _padding,
-                                            child: GestureDetector(
-                                              onTap: () => NavigatorUtil.goPage(context, (context) => GameDetailsPage(e)),
-                                              child: ClipRRect(
-                                                  borderRadius: BorderRadius.circular(10.0),
-                                                  child: Container(
-                                                    color: Colors.white,
-                                                    child: Row(
-                                                      children: <Widget>[
-                                                        CachedNetworkImage(
-                                                          width: 90.0,
-                                                          height: 90.0,
-                                                          fit: BoxFit.cover,
-                                                          imageUrl: "${e.cover}",
-                                                        ),
-                                                        const SizedBox(
-                                                          width: 12.0,
-                                                        ),
-                                                        Expanded(
-                                                          child: Column(
-                                                            crossAxisAlignment: CrossAxisAlignment.start,
-                                                            children: <Widget>[
-                                                              Text(
-                                                                e.name,
-                                                                style: Theme.of(context).textTheme.headline3,
-                                                              ),
-                                                              const SizedBox(
-                                                                height: 3,
-                                                              ),
-                                                              Text(
-                                                                "${e.userCount}人在练",
-                                                                style: Theme.of(context).textTheme.bodyText1,
-                                                              ),
-                                                              const SizedBox(
-                                                                height: 5,
-                                                              ),
-                                                              Row(
-                                                                children: <Widget>[
-                                                                  Text(
-                                                                    "难度: ",
-                                                                    style: Theme.of(context).textTheme.bodyText1,
-                                                                  ),
-                                                                  RatingBarIndicator(
-                                                                    rating: e.difficulty / 20.0,
-                                                                    itemBuilder: (context, index) => Image.asset(
-                                                                      "lib/assets/img/con_icon_difficulty_normal.png",
-                                                                      color: const Color(0xffFFC400),
+            onTap: () => Navigator.maybePop(context),
+            behavior: HitTestBehavior.opaque,
+            child: ValueListenableBuilder(
+              valueListenable: index,
+              builder: (context, _index, _) {
+                return _index == 0
+                    ? Center(
+                        child: Padding(
+                          padding: const EdgeInsets.fromLTRB(0, 0.0, 0, 20.0),
+                          child: Column(
+                            children: <Widget>[
+                              GestureDetector(
+                                behavior: HitTestBehavior.opaque,
+                                onTap: () => Navigator.maybePop(context),
+                                child: Container(
+                                  alignment: Alignment.centerRight,
+                                  padding: const EdgeInsets.only(
+                                      bottom: 40.0, top: 20, right: 20.0),
+                                  child: Image.asset(
+                                      "lib/assets/img/btn_close_big.png"),
+                                ),
+                              ),
+                              Padding(
+                                padding: const EdgeInsets.all(12.0),
+                                child: Stack(
+                                  alignment: Alignment.center,
+                                  children: <Widget>[
+                                    Image.asset(
+                                      "lib/assets/img/mine_image_achievement.png",
+                                      fit: BoxFit.fitWidth,
+                                      width: 240,
+                                    ),
+                                    Text(
+                                      "运动列表",
+                                      style:
+                                          Theme.of(context).textTheme.headline4,
+                                      strutStyle: fixedLine,
+                                    )
+                                  ],
+                                ),
+                              ),
+                              Expanded(
+                                child: SingleChildScrollView(
+                                  child: Padding(
+                                    padding: const EdgeInsets.all(12.0),
+                                    child: Column(
+                                      children: <Widget>[
+                                        Container(
+                                          margin: _padding,
+                                          child: GameRun(changeIndex:changeIndex),
+                                          decoration: circular(),
+                                        ),
+                                        FutureBuilder(
+                                          future: _future,
+                                          builder: (BuildContext context,
+                                              AsyncSnapshot<
+                                                      RespList<GameInfoData>>
+                                                  snapshot) {
+                                            if (snapshot.connectionState !=
+                                                ConnectionState.done)
+                                              return RequestLoadingWidget();
+                                            var list = snapshot.data?.results;
+                                            return Column(
+                                                children: list
+                                                    .map((e) => Padding(
+                                                        padding: _padding,
+                                                        child: GestureDetector(
+                                                          onTap: () =>
+                                                              NavigatorUtil.goPage(
+                                                                  context,
+                                                                  (context) =>
+                                                                      GameDetailsPage(
+                                                                          e)),
+                                                          child: ClipRRect(
+                                                              borderRadius:
+                                                                  BorderRadius
+                                                                      .circular(
+                                                                          10.0),
+                                                              child: Container(
+                                                                color: Colors
+                                                                    .white,
+                                                                child: Row(
+                                                                  children: <
+                                                                      Widget>[
+                                                                    CachedNetworkImage(
+                                                                      width:
+                                                                          90.0,
+                                                                      height:
+                                                                          90.0,
+                                                                      fit: BoxFit
+                                                                          .cover,
+                                                                      imageUrl:
+                                                                          "${e.cover}",
+                                                                    ),
+                                                                    const SizedBox(
+                                                                      width:
+                                                                          12.0,
+                                                                    ),
+                                                                    Expanded(
+                                                                      child:
+                                                                          Column(
+                                                                        crossAxisAlignment:
+                                                                            CrossAxisAlignment.start,
+                                                                        children: <
+                                                                            Widget>[
+                                                                          Text(
+                                                                            e.name,
+                                                                            style:
+                                                                                Theme.of(context).textTheme.headline3,
+                                                                          ),
+                                                                          const SizedBox(
+                                                                            height:
+                                                                                3,
+                                                                          ),
+                                                                          Text(
+                                                                            "${e.userCount}人在练",
+                                                                            style:
+                                                                                Theme.of(context).textTheme.bodyText1,
+                                                                          ),
+                                                                          const SizedBox(
+                                                                            height:
+                                                                                5,
+                                                                          ),
+                                                                          Row(
+                                                                            children: <Widget>[
+                                                                              Text(
+                                                                                "难度: ",
+                                                                                style: Theme.of(context).textTheme.bodyText1,
+                                                                              ),
+                                                                              RatingBarIndicator(
+                                                                                rating: e.difficulty / 20.0,
+                                                                                itemBuilder: (context, index) => Image.asset(
+                                                                                  "lib/assets/img/con_icon_difficulty_normal.png",
+                                                                                  color: const Color(0xffFFC400),
+                                                                                ),
+                                                                                itemCount: 5,
+                                                                                itemSize: 14.0,
+                                                                                unratedColor: const Color(0xffCECECE),
+                                                                                direction: Axis.horizontal,
+                                                                              )
+                                                                            ],
+                                                                          )
+                                                                        ],
+                                                                      ),
                                                                     ),
-                                                                    itemCount: 5,
-                                                                    itemSize: 14.0,
-                                                                    unratedColor: const Color(0xffCECECE),
-                                                                    direction: Axis.horizontal,
-                                                                  )
-                                                                ],
-                                                              )
-                                                            ],
-                                                          ),
-                                                        ),
-                                                        Container(
-                                                          width: 120.0,
-                                                          child: PositionedBottom(
-                                                            e,
-                                                            (v) {
-                                                              startGame(context, e);
-                                                            },
-                                                            height: 35.0,
-                                                            width: 93.0,
-                                                            textStyle: TextStyle(
-                                                              color: Colors.white,
-                                                              fontSize: 14.0,
-                                                            ),
-                                                          ),
-                                                        )
-                                                      ],
-                                                    ),
-                                                  )),
-                                            )))
-                                        .toList());
-                              },
-                            )
-                          ],
+                                                                    Container(
+                                                                      width:
+                                                                          120.0,
+                                                                      child:
+                                                                          PositionedBottom(
+                                                                        e,
+                                                                        (v) {
+                                                                          startGame(
+                                                                              context,
+                                                                              e);
+                                                                        },
+                                                                        height:
+                                                                            35.0,
+                                                                        width:
+                                                                            93.0,
+                                                                        textStyle:
+                                                                            TextStyle(
+                                                                          color:
+                                                                              Colors.white,
+                                                                          fontSize:
+                                                                              14.0,
+                                                                        ),
+                                                                      ),
+                                                                    )
+                                                                  ],
+                                                                ),
+                                                              )),
+                                                        )))
+                                                    .toList());
+                                          },
+                                        )
+                                      ],
+                                    ),
+                                  ),
+                                ),
+                              ),
+                            ],
+                          ),
                         ),
-                      ),
-                    ),
-                  ),
-                  GestureDetector(
-                    behavior: HitTestBehavior.opaque,
-                    onTap: () => Navigator.maybePop(context),
-                    child: Padding(
-                      padding: const EdgeInsets.all(8.0),
-                      child: Image.asset("lib/assets/img/pop_share_chose.png"),
-                    ),
-                  ),
-                ],
-              ),
-            ),
-          ),
-        ),
+                      )
+                    : Center(
+                        child: Padding(
+                            padding: const EdgeInsets.fromLTRB(0, 0.0, 0, 20.0),
+                            child: Column(
+                              children: <Widget>[
+                                GestureDetector(
+                                  behavior: HitTestBehavior.opaque,
+                                  onTap: () => Navigator.maybePop(context),
+                                  child: Container(
+                                    alignment: Alignment.centerRight,
+                                    padding: const EdgeInsets.only(
+                                        bottom: 40.0, top: 20, right: 20.0),
+                                    child: Image.asset(
+                                        "lib/assets/img/btn_close_big.png"),
+                                  ),
+                                ),
+                                FunctionSet()
+                              ],
+                            )));
+              },
+            )),
       ),
     );
   }

+ 312 - 11
lib/pages/my/score_shop.dart

@@ -1,6 +1,18 @@
+import 'package:cached_network_image/cached_network_image.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:sport/bean/shop.dart';
+import 'package:sport/pages/my/shop_detail.dart';
+import 'package:sport/provider/lib/provider_widget.dart';
+import 'package:sport/provider/lib/view_state_lifecycle.dart';
+import 'package:sport/provider/shop_model.dart';
+import 'package:sport/provider/user_friend_model.dart';
+import 'package:sport/router/navigator_util.dart';
+import 'package:sport/router/routes.dart';
 import 'package:sport/widgets/appbar.dart';
+import 'package:sport/widgets/button_primary.dart';
+import 'package:sport/widgets/space.dart';
 
 class ScoreShopPage extends StatefulWidget {
   @override
@@ -10,19 +22,308 @@ class ScoreShopPage extends StatefulWidget {
   }
 }
 
-class _ScoreShopPageState extends State<ScoreShopPage> {
+class _ScoreShopPageState extends ViewStateLifecycle<ScoreShopPage, ShopModel>
+    with ChangeNotifier {
+  @override
+  ShopModel createModel() {
+    // TODO: implement createModel
+    return ShopModel();
+  }
+
+  @override
+  void dispose() {
+    // TODO: implement dispose
+    super.dispose();
+  }
+
   @override
   Widget build(BuildContext context) {
     // TODO: implement build
-    return Scaffold(
-        body: CustomScrollView(slivers: <Widget>[
-      buildSliverAppBar(context, "积分商城",
-          backgroundColor: Theme.of(context).scaffoldBackgroundColor),
-      SliverToBoxAdapter(
-        child: Center(
-          child: Text("正在开发敬请期待~!"),
-        ),
-      )
-    ]));
+    return AnnotatedRegion<SystemUiOverlayStyle>(
+        value: SystemUiOverlayStyle.light,
+        child: Scaffold(
+        backgroundColor: Colors.white,
+        body: ProviderWidget<ShopModel>(
+          onModelReady: (v) => v.init(),
+          model: model,
+          builder: (context, model, _) {
+            return Stack(
+              fit: StackFit.expand,
+              children: <Widget>[
+                Align(
+                  alignment: Alignment.topCenter,
+                  child: Container(
+                      width: MediaQuery.of(context).size.width,
+                      height: MediaQuery.of(context).size.width * 381 / 750,
+                      decoration: BoxDecoration(
+                          image: DecorationImage(
+                              image:
+                                  AssetImage("lib/assets/img/mall_bg_home.png"),
+                              fit: BoxFit.cover)),
+                      child: SafeArea(
+                        child: Align(
+                          alignment: Alignment.centerLeft,
+                          child: Padding(
+                            padding: const EdgeInsets.symmetric(horizontal: 12),
+                            child: Column(
+                              crossAxisAlignment: CrossAxisAlignment.start,
+                              mainAxisSize: MainAxisSize.min,
+                              children: <Widget>[],
+                            ),
+                          ),
+                        ),
+                      )),
+                ),
+                SafeArea(
+                    child: Column(
+                  children: <Widget>[
+                    Row(
+                      children: <Widget>[
+                        IconButton(
+                          icon: Image.asset(
+                              "lib/assets/img/topbar_return_white.png"),
+                          onPressed: () {
+                            Navigator.pop(context);
+                          },
+                        ),
+                        Text(
+                          "积分商城",
+                          style: TextStyle(
+                              color: Colors.white,
+                              fontSize: 18,
+                              fontWeight: FontWeight.w600),
+                        ),
+                        Expanded(
+                          child: GestureDetector(
+                            onTap: () {
+                              NavigatorUtil.goPage(
+                                  context, (context) => ShopDetailPage());
+                            },
+                            child: Container(
+                              padding: EdgeInsets.only(right: 12.0),
+                              alignment: Alignment.centerRight,
+                              child: Text("明细",
+                                  style: TextStyle(
+                                    color: Colors.white,
+                                    fontSize: 16,
+                                  )),
+                            ),
+                          ),
+                        )
+                      ],
+                    ),
+                    if (model.isIdle)
+                      Container(
+                        padding: EdgeInsets.all(20.0),
+                        child: Row(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          children: <Widget>[
+                            Text(
+                              "积分:",
+                              style: TextStyle(
+                                  fontSize: 16.0,
+                                  color: Theme.of(context).accentColor),
+                            ),
+                            Text(
+                              "${model.shop?.user?.score ?? 0}",
+                              style: TextStyle(
+                                  fontSize: 25.0,
+                                  color: Theme.of(context).accentColor,
+                                  fontWeight: FontWeight.w600),
+                            )
+                          ],
+                        ),
+                      ),
+                  ],
+                )),
+                Positioned(
+                  top: MediaQuery.of(context).size.width * 381 / 750 - 20,
+                  left: 0,
+                  right: 0,
+                  bottom: 0,
+                  child: Container(
+                      width: MediaQuery.of(context).size.width,
+                      height: double.infinity,
+                      padding: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0),
+                      decoration: BoxDecoration(
+                        color: Colors.white,
+                        borderRadius: BorderRadius.only(
+                            topLeft: Radius.circular(10.0),
+                            topRight: Radius.circular(10.0)),
+                      ),
+                      child: CustomScrollView(
+                        // shrinkWrap: true,
+                        // physics: NeverScrollableScrollPhysics(),
+                        slivers: <Widget>[
+                          // SliverToBoxAdapter(
+                          //   child: Row(
+                          //     mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                          //     children: <Widget>[
+                          //       Expanded(
+                          //         child: Container(
+                          //           decoration: BoxDecoration(
+                          //             borderRadius:
+                          //             BorderRadius.all(Radius.circular(10.0)),
+                          //             color: Colors.white,
+                          //             boxShadow: [
+                          //               BoxShadow(
+                          //                   offset: Offset(0.0, 0),
+                          //                   blurRadius: 5,
+                          //                   spreadRadius: 0,
+                          //                   color: Color.fromRGBO(0, 0, 0, 0.1))
+                          //             ],
+                          //           ),
+                          //           child: Column(
+                          //             children: <Widget>[
+                          //               Container(
+                          //                 margin: EdgeInsets.fromLTRB(
+                          //                     38.0, 25.0, 38.0, 18.0),
+                          //                 color: Colors.red,
+                          //                 height: 60.0,
+                          //               ),
+                          //               Container(
+                          //                 alignment: Alignment.center,
+                          //                 child: Text(
+                          //                   "改名卡30积分",
+                          //                   style: TextStyle(
+                          //                       color: Color(0xff333333),
+                          //                       fontSize: 14.0),
+                          //                 ),
+                          //               ),
+                          //               Space(
+                          //                 height: 12.0,
+                          //               ),
+                          //               Padding(
+                          //                 padding: EdgeInsets.fromLTRB(
+                          //                     15.0, 0, 15.0, 15.0),
+                          //                 child: PrimaryButton(
+                          //                   callback: () {},
+                          //                   content: "兑换",
+                          //                   height: 35.0,
+                          //                 ),
+                          //               )
+                          //             ],
+                          //           ),
+                          //         ),
+                          //       ),
+                          //       Space(
+                          //         width: 20.0,
+                          //       ),
+                          //       Expanded(
+                          //         child: Container(
+                          //           // height: 170.0,
+                          //           decoration: BoxDecoration(
+                          //             borderRadius:
+                          //             BorderRadius.all(Radius.circular(10.0)),
+                          //             color: Colors.white,
+                          //             boxShadow: [
+                          //               BoxShadow(
+                          //                   offset: Offset(0.0, 0),
+                          //                   blurRadius: 5,
+                          //                   spreadRadius: 0,
+                          //                   color: Color.fromRGBO(0, 0, 0, 0.1))
+                          //             ],
+                          //           ),
+                          //           child: Column(
+                          //             children: <Widget>[
+                          //               Container(
+                          //                 margin: EdgeInsets.fromLTRB(
+                          //                     38.0, 25.0, 38.0, 18.0),
+                          //                 color: Colors.red,
+                          //                 height: 60.0,
+                          //               ),
+                          //               Container(
+                          //                 alignment: Alignment.center,
+                          //                 child: Text(
+                          //                   "跑酷游戏金币1000",
+                          //                   style: TextStyle(
+                          //                       color: Color(0xff333333),
+                          //                       fontSize: 14.0),
+                          //                 ),
+                          //               ),
+                          //               Space(
+                          //                 height: 12.0,
+                          //               ),
+                          //               Padding(
+                          //                 padding: EdgeInsets.fromLTRB(
+                          //                     15.0, 0, 15.0, 15.0),
+                          //                 child: PrimaryButton(
+                          //                   callback: () {},
+                          //                   content: "兑换",
+                          //                   height: 35.0,
+                          //                 ),
+                          //               )
+                          //             ],
+                          //           ),
+                          //         ),
+                          //       ),
+                          //     ],
+                          //   ),
+                          // ),
+                          if(model.isIdle)
+                          SliverGrid(
+                            gridDelegate:
+                                SliverGridDelegateWithFixedCrossAxisCount(
+                                    crossAxisCount: 2,
+                                    crossAxisSpacing: 18,
+                                    mainAxisSpacing:18,
+                                    childAspectRatio: 157 / 181),
+                            delegate: SliverChildBuilderDelegate(
+                                (BuildContext context, int index) {
+                                  Items item = model?.shop?.items[index];
+                              return Container(
+                                decoration: BoxDecoration(
+                                  borderRadius:
+                                      BorderRadius.all(Radius.circular(10.0)),
+                                  color: Colors.white,
+                                  boxShadow: [
+                                    BoxShadow(
+                                        offset: Offset(0.0, 0),
+                                        blurRadius: 5,
+                                        spreadRadius: 0,
+                                        color: Color.fromRGBO(0, 0, 0, 0.1))
+                                  ],
+                                ),
+                                child: Column(
+                                  children: <Widget>[
+                                    Space(height: 10.0,),
+                                    CachedNetworkImage(
+                                      imageUrl: item?.logo,
+                                      width: 80.0,
+                                      height: 80.0,
+                                    ),
+                                    Container(
+                                      alignment: Alignment.center,
+                                      child: Text(
+                                        "${item?.name}",
+                                        style: TextStyle(
+                                            color: Color(0xff333333),
+                                            fontSize: 14.0),
+                                      ),
+                                    ),
+                                    Space(
+                                      height: 12.0,
+                                    ),
+                                    Padding(
+                                      padding: EdgeInsets.fromLTRB(
+                                          15.0, 0, 15.0, 15.0),
+                                      child: PrimaryButton(
+                                        callback: () {},
+                                        content: "兑换",
+                                        height: 35.0,
+                                      ),
+                                    )
+                                  ],
+                                ),
+                              );
+                            }, childCount: model?.shop?.items?.length??0),
+                          )
+                        ],
+                      )),
+                )
+              ],
+            );
+          },
+        )));
   }
 }

+ 93 - 0
lib/pages/my/shop_detail.dart

@@ -0,0 +1,93 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:sport/provider/lib/provider_widget.dart';
+import 'package:sport/provider/lib/view_state_lifecycle.dart';
+import 'package:sport/provider/shop_model.dart';
+import 'package:sport/widgets/appbar.dart';
+import 'package:sport/widgets/space.dart';
+
+class ShopDetailPage extends StatefulWidget {
+  @override
+  State<StatefulWidget> createState() {
+    // TODO: implement createState
+    return _ShopDetailPageState();
+  }
+}
+
+class _ShopDetailPageState
+    extends ViewStateLifecycle<ShopDetailPage, ScoreModel> {
+  Widget _buildListItem(String name, String create, int score) {
+    return Padding(
+        padding: EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 12.0),
+        child: Column(
+          children: <Widget>[
+            Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: <Widget>[
+                Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: <Widget>[
+                    Text(
+                      "$name",
+                      style:
+                          TextStyle(fontSize: 16.0, color: Color(0xff333333)),
+                    ),
+                    Space(
+                      height: 5.0,
+                    ),
+                    Text(
+                      "$create",
+                      style:
+                          TextStyle(color: Color(0xff999999), fontSize: 12.0),
+                    )
+                  ],
+                ),
+                Text(score > 0 ? "+$score 积分" : "-$score 积分",
+                    style: TextStyle(
+                      fontSize: 16.0,
+                      color: score < 0  ? Theme.of(context).accentColor : Color(0xffFF5B1D),
+                    )),
+              ],
+            ),
+            Space(
+              height: 10,
+            ),
+            Divider(),
+          ],
+        ));
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    // TODO: implement build
+    return Scaffold(
+        appBar: buildAppBar(context, title: "积分明细"),
+        backgroundColor: Colors.white,
+        body: ProviderWidget<ScoreModel>(
+          model: model,
+          onModelReady: (v) => v.loadData(),
+          builder: (_, model, __) {
+            return CustomScrollView(slivers: [
+              if (model.isIdle)
+                SliverList(
+                  delegate: SliverChildBuilderDelegate(
+                    (context, index) {
+                      return _buildListItem(
+                          model?.scoreList[index].detail,
+                          model?.scoreList[index].createdAt,
+                          model?.scoreList[index].score);
+                    },
+                    childCount: model?.scoreList?.length ?? 0,
+                  ),
+                ),
+            ]);
+          },
+        ));
+  }
+
+  @override
+  ScoreModel createModel() {
+    // TODO: implement createModel
+    return new ScoreModel();
+  }
+}

+ 99 - 52
lib/pages/my/user_info_page.dart

@@ -17,29 +17,38 @@ import 'package:sport/provider/user_model.dart';
 import 'package:sport/router/navigator_util.dart';
 import 'package:sport/router/routes.dart';
 import 'package:sport/services/api/inject_api.dart';
+import 'package:sport/utils/toast.dart';
 import 'package:sport/widgets/appbar.dart';
+import 'package:sport/widgets/button_primary.dart';
 import 'package:sport/widgets/city_picker.dart';
 import 'package:sport/widgets/city_picker_data.dart';
 import 'package:sport/widgets/dialog/alert_dialog.dart';
 import 'package:sport/widgets/dialog/request_dialog.dart';
 import 'package:sport/widgets/image.dart';
 import 'package:sport/widgets/list_tile.dart';
+import 'package:sport/widgets/space.dart';
 
 class UserInfoPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() => _PageState();
 }
 
-class _PageState extends State<UserInfoPage> with InjectLoginApi {
+class _PageState extends State<UserInfoPage> with InjectLoginApi,InjectApi {
   LoginInfoModel _loginInfoModel = inject();
   int _genderController = 1; // 默认选中男
   String _name; // 用户名
   File _lastCropped;
-
+  ValueNotifier<int> num;
   @override
   void initState() {
     // TODO: implement initState
     super.initState();
+    initNameCardCount();
+  }
+
+  initNameCardCount() async{
+    int _num = (await api.getCountNameCard()).data;
+    num = new ValueNotifier(_num);
   }
 
   @override
@@ -67,22 +76,27 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   title: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceBetween,
                     children: <Widget>[
-                      Text("头像",style: TextStyle(fontSize: 16.0),),
+                      Text(
+                        "头像",
+                        style: TextStyle(fontSize: 16.0),
+                      ),
                       Consumer<UserModel>(
                         builder: (_, model, __) {
                           // 没有头像就为空...
-                          return  model.user.avatar != null ? Container(
-                            width: 40.0,
-                            height: 40.0,
-                            child: CircleAvatar(
-                              radius: 100,
-                              backgroundImage: _lastCropped == null
-                                  ? NetworkImage(model.user.avatar)
-                                  : FileImage(
-                                      _lastCropped,
-                                    ),
-                            ),
-                          ):Container();
+                          return model.user.avatar != null
+                              ? Container(
+                                  width: 40.0,
+                                  height: 40.0,
+                                  child: CircleAvatar(
+                                    radius: 100,
+                                    backgroundImage: _lastCropped == null
+                                        ? NetworkImage(model.user.avatar)
+                                        : FileImage(
+                                            _lastCropped,
+                                          ),
+                                  ),
+                                )
+                              : Container();
                         },
                       )
                     ],
@@ -103,7 +117,10 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   title: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceBetween,
                     children: <Widget>[
-                      Text("用户名称",style: TextStyle(fontSize: 16.0),),
+                      Text(
+                        "用户名称",
+                        style: TextStyle(fontSize: 16.0),
+                      ),
                       Consumer<UserModel>(
                         builder: (_, model, __) {
                           return Text(model.user.name,
@@ -131,7 +148,10 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   title: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceBetween,
                     children: <Widget>[
-                      Text("性别",style: TextStyle(fontSize: 16.0),),
+                      Text(
+                        "性别",
+                        style: TextStyle(fontSize: 16.0),
+                      ),
                       Consumer<UserModel>(
                         builder: (_, model, __) {
                           return Text(model.user.gender == 1 ? "男" : "女",
@@ -161,7 +181,10 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   title: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceBetween,
                     children: <Widget>[
-                      Text("年龄",style: TextStyle(fontSize: 16.0),),
+                      Text(
+                        "年龄",
+                        style: TextStyle(fontSize: 16.0),
+                      ),
                       Consumer<UserModel>(
                         builder: (_, model, __) {
                           return Text(
@@ -197,7 +220,10 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   title: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceBetween,
                     children: <Widget>[
-                      Text("城市",style: TextStyle(fontSize: 16.0),),
+                      Text(
+                        "城市",
+                        style: TextStyle(fontSize: 16.0),
+                      ),
                       Consumer<UserModel>(
                         builder: (_, model, __) {
                           String province = model.user.province;
@@ -271,7 +297,10 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   title: Row(
                     mainAxisAlignment: MainAxisAlignment.spaceBetween,
                     children: <Widget>[
-                      Text("二维码名片",style: TextStyle(fontSize: 16.0),),
+                      Text(
+                        "二维码名片",
+                        style: TextStyle(fontSize: 16.0),
+                      ),
                       Container(
                         width: 22.0,
                         height: 22.0,
@@ -282,7 +311,8 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                   contentPadding: EdgeInsets.symmetric(horizontal: 0.0),
                   trailing: arrowRight5(),
                   onTap: () async {
-                    NavigatorUtil.goPage(context, (context) => UserFriendAddPage());
+                    NavigatorUtil.goPage(
+                        context, (context) => UserFriendAddPage());
                   },
                 ),
               ],
@@ -307,35 +337,10 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
               height: 200,
               child: Column(
                 children: <Widget>[
-                  Row(
-                    children: <Widget>[
-                      IconButton(
-                          onPressed: () {
-                            Navigator.of(context).pop();
-                          },
-                          icon: Text("取消")),
-                      Expanded(
-                          child: Center(
-                              child: Text(
-                        "修改用户名",
-                        style: Theme.of(context).textTheme.headline3,
-                      ))),
-                      IconButton(
-                          onPressed: () {
-//                            print(_controller.value);
-                            callBack(_controller.value);
-                            Navigator.of(context).pop();
-                          },
-                          icon: Text(
-                            "确认",
-                            style: Theme.of(context)
-                                .textTheme
-                                .subtitle1
-                                .copyWith(color: Theme.of(context).accentColor),
-                          )),
-                    ],
+//                   Divider(),
+                  Space(
+                    height: 30.0,
                   ),
-                  Divider(),
                   Padding(
                     padding: const EdgeInsets.all(16.0),
                     child: TextField(
@@ -345,13 +350,55 @@ class _PageState extends State<UserInfoPage> with InjectLoginApi {
                         maxLength: 10,
                         decoration: InputDecoration(
                             counterText: '',
-                            helperText: '用户名长度为2-10个字母,数字,中文',
+                            // helperText: '用户名长度为2-10个字母,数字,中文',
+                            hintText: "用户昵称七个字",
                             helperMaxLines: 1,
                             focusedBorder: UnderlineInputBorder(
-                              borderSide: BorderSide(
-                                  color: Theme.of(context).accentColor),
+                              borderSide: BorderSide(color: Color(0xffF1F1F1)),
                             ))),
                   ),
+                  Padding(
+                    padding: EdgeInsets.fromLTRB(20.0, 20.0, 20.0, 0),
+                    child: Row(
+                      children: <Widget>[
+                        Expanded(
+                          child: MainButton(
+                            type: "cancel",
+                            content: "取消",
+                            callback: () => {Navigator.of(context).pop()},
+                            height: 35.0,
+                            textColor: Color(0xff333333),
+                          ),
+                        ),
+                        Space(
+                          width: 12.0,
+                        ),
+                        Expanded(
+                          child: ValueListenableBuilder(
+                            valueListenable: num,
+                            builder: (context, index, child) {
+                              return MainButton(
+                                type: "confirm",
+                                content: "改名卡($index)",
+                                callback: () {
+                                  if (index > 0) {
+                                    callBack(_controller.value);
+                                    Navigator.of(context).pop();
+                                  }else{
+                                    ToastUtil.show("您没有改名卡喔~!");
+                                  }
+                                },
+                                height: 35.0,
+                                buttonColor: index <= 0
+                                    ? Color(0xffFFC400).withOpacity(0.3)
+                                    : Color(0xffFFC400),
+                              );
+                            },
+                          ),
+                        ),
+                      ],
+                    ),
+                  ),
                 ],
               ),
             ),

+ 32 - 0
lib/provider/shop_model.dart

@@ -0,0 +1,32 @@
+import 'package:flutter/cupertino.dart';
+import 'package:sport/bean/user_friend.dart';
+import 'package:sport/provider/lib/view_state_list_model.dart';
+import 'package:sport/services/api/inject_api.dart';
+import 'package:sport/bean/shop.dart';
+
+import 'lib/view_state_model.dart';
+import 'lib/view_state_refresh_list_model.dart';
+
+class ShopModel extends ViewStateModel with InjectApi {
+  ShopIndex shop;
+  init() async {
+    ShopIndex shopIndex = (await api.getShopIndex()).data;
+    // return shopIndex;
+    shop = shopIndex;
+    setIdle();
+    return shop;
+  }
+}
+
+class ScoreModel extends ViewStateRefreshListModel<ScoreListData> with InjectApi{
+  List<ScoreListData> scoreList;
+
+  @override
+  Future<List<ScoreListData>> loadData({int pageNum}) async{
+    // TODO: implement loadData
+      List<ScoreListData> _list = (await api.getScoreIndex()).data.data;
+      scoreList = _list;
+      setIdle();
+      return scoreList;
+  }
+}

+ 5 - 0
lib/router/routes.dart

@@ -10,6 +10,7 @@ import 'package:sport/pages/my/feedback_page.dart';
 import 'package:sport/pages/my/game_list_page.dart';
 import 'package:sport/pages/my/level_page.dart';
 import 'package:sport/pages/my/score_shop.dart';
+import 'package:sport/pages/my/shop_detail.dart';
 import 'package:sport/pages/setting/message_setting_page.dart';
 import 'package:sport/pages/social/chat_page.dart';
 import 'package:sport/pages/social/message_detail_page.dart';
@@ -68,6 +69,7 @@ class Routes {
   static String feedbackDetail = "/feedback_detail";
   static String gamelistpage = "/gamelistpage";
   static String scoreShopPage = "/scoreShopPage";
+  static String shopPageDetail = '/shopPageDetail';
 
   static void configureRoutes(Router router) {
     router.notFoundHandler = Handler(handlerFunc: (BuildContext context, Map<String, List<String>> params) {
@@ -149,5 +151,8 @@ class Routes {
     router.define(scoreShopPage, handler: Handler(handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
       return ScoreShopPage();
     }));
+    router.define(scoreShopPage, handler: Handler(handlerFunc: (BuildContext context, Map<String, List<Object>> params) {
+      return ShopDetailPage();
+    }));
   }
 }

+ 5 - 0
lib/services/Converter.dart

@@ -13,6 +13,7 @@ import 'package:sport/bean/post_user.dart';
 import 'package:sport/bean/rank_game_info.dart';
 import 'package:sport/bean/rank_info.dart';
 import 'package:sport/bean/share_info.dart';
+import 'package:sport/bean/shop.dart';
 import 'package:sport/bean/sport_detail.dart';
 import 'package:sport/bean/sport_index.dart';
 import 'package:sport/bean/sport_step.dart';
@@ -96,6 +97,10 @@ class Converter {
         return ShareInfo.fromJson(json) as T;
       case "Share":
         return Share.fromJson(json) as T;
+      case "ShopIndex":
+        return ShopIndex.fromJson(json) as T;
+      case "ScoreList":
+        return ScoreList.fromJson(json) as T;
     }
     return json as T;
   }

+ 14 - 2
lib/services/api/rest_client.dart

@@ -16,6 +16,7 @@ import 'package:sport/bean/post.dart';
 import 'package:sport/bean/rank_game_info.dart';
 import 'package:sport/bean/rank_info.dart';
 import 'package:sport/bean/share_info.dart';
+import 'package:sport/bean/shop.dart';
 import 'package:sport/bean/sport_detail.dart';
 import 'package:sport/bean/sport_index.dart';
 import 'package:sport/bean/sport_step.dart';
@@ -40,6 +41,9 @@ abstract class RestClient {
   @GET("/user/info")
   Future<RespData<UserInfo>> getUserInfo(@Query("id") String uid, {@DioOptions() Options options});
 
+  @GET("/user/countNameCard")
+  Future<RespData<int>> getCountNameCard();
+
   // ********************** 运动首页相关 *****************************
   @GET("/sport/index")
   Future<RespData<SportIndex>> getSportIndex();
@@ -347,9 +351,17 @@ abstract class RestClient {
 
   @GET("/rank/game")
   Future<RespData<RankGameInfoData>> getRankGameInfo(@Query("game_id") String id,
-      {@Query("province_id") int provinceId, @Query("city_id") int cityId, @Query("district_id") int districtId});
+      {@Query("scope") String scope});
 
   @GET("/rank/sport")
   Future<RespData<RankGameInfoData>> getRankSportInfo(@Query("rank_id") String id,
-      {@Query("province_id") int provinceId, @Query("city_id") int cityId, @Query("district_id") int districtId});
+      {@Query("scope") String scope});
+
+// ********************** 商城相关 *********************************
+
+  @GET("/shop/item")
+  Future<RespData<ShopIndex>> getShopIndex();
+
+  @GET("/score/record")
+  Future<RespData<ScoreList>> getScoreIndex();
 }

+ 58 - 14
lib/services/api/rest_client.g.dart

@@ -54,6 +54,24 @@ class _RestClient implements RestClient {
   }
 
   @override
+  getCountNameCard() async {
+    const _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    final Response<Map<String, dynamic>> _result = await _dio.request(
+        '/user/countNameCard',
+        queryParameters: queryParameters,
+        options: RequestOptions(
+            method: 'GET',
+            headers: <String, dynamic>{},
+            extra: _extra,
+            baseUrl: baseUrl),
+        data: _data);
+    final value = RespData<int>.fromJson(_result.data);
+    return value;
+  }
+
+  @override
   getSportIndex() async {
     const _extra = <String, dynamic>{};
     final queryParameters = <String, dynamic>{};
@@ -1898,15 +1916,10 @@ class _RestClient implements RestClient {
   }
 
   @override
-  getRankGameInfo(id, {provinceId, cityId, districtId}) async {
+  getRankGameInfo(id, {scope}) async {
     ArgumentError.checkNotNull(id, 'id');
     const _extra = <String, dynamic>{};
-    final queryParameters = <String, dynamic>{
-      r'game_id': id,
-      r'province_id': provinceId,
-      r'city_id': cityId,
-      r'district_id': districtId
-    };
+    final queryParameters = <String, dynamic>{r'game_id': id, r'scope': scope};
     queryParameters.removeWhere((k, v) => v == null);
     final _data = <String, dynamic>{};
     final Response<Map<String, dynamic>> _result = await _dio.request(
@@ -1923,15 +1936,10 @@ class _RestClient implements RestClient {
   }
 
   @override
-  getRankSportInfo(id, {provinceId, cityId, districtId}) async {
+  getRankSportInfo(id, {scope}) async {
     ArgumentError.checkNotNull(id, 'id');
     const _extra = <String, dynamic>{};
-    final queryParameters = <String, dynamic>{
-      r'rank_id': id,
-      r'province_id': provinceId,
-      r'city_id': cityId,
-      r'district_id': districtId
-    };
+    final queryParameters = <String, dynamic>{r'rank_id': id, r'scope': scope};
     queryParameters.removeWhere((k, v) => v == null);
     final _data = <String, dynamic>{};
     final Response<Map<String, dynamic>> _result = await _dio.request(
@@ -1947,6 +1955,42 @@ class _RestClient implements RestClient {
     return value;
   }
 
+  @override
+  getShopIndex() async {
+    const _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    final Response<Map<String, dynamic>> _result = await _dio.request(
+        '/shop/item',
+        queryParameters: queryParameters,
+        options: RequestOptions(
+            method: 'GET',
+            headers: <String, dynamic>{},
+            extra: _extra,
+            baseUrl: baseUrl),
+        data: _data);
+    final value = RespData<ShopIndex>.fromJson(_result.data);
+    return value;
+  }
+
+  @override
+  getScoreIndex() async {
+    const _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    final Response<Map<String, dynamic>> _result = await _dio.request(
+        '/score/record',
+        queryParameters: queryParameters,
+        options: RequestOptions(
+            method: 'GET',
+            headers: <String, dynamic>{},
+            extra: _extra,
+            baseUrl: baseUrl),
+        data: _data);
+    final value = RespData<ScoreList>.fromJson(_result.data);
+    return value;
+  }
+
   RequestOptions newRequestOptions(Options options) {
     if (options is RequestOptions) {
       return options;

+ 98 - 0
lib/widgets/button_primary.dart

@@ -88,3 +88,101 @@ class PrimaryButton extends StatelessWidget {
     );
   }
 }
+
+class MainButton extends StatelessWidget {
+  final VoidCallback callback;
+  final String content;
+  final double width;
+  final double height;
+  final double fontSize;
+  final Widget child;
+  final bool shadow;
+  final bool bold;
+  final Color buttonColor;
+  final Color textColor;
+  final String type; // cancel or confirm
+
+  MainButton({
+    @required this.callback,
+    @required this.content,
+    @required this.type,
+    this.child,
+    this.width = double.infinity,
+    this.height = 44,
+    this.fontSize = 28,
+    this.shadow = true,
+    this.bold = false,
+    this.buttonColor,
+    this.textColor,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    BoxDecoration cancelDecoration = BoxDecoration(
+      color: buttonColor,
+      shape: BoxShape.rectangle,
+      borderRadius: BorderRadius.all(Radius.circular(height / 2)),
+      boxShadow: [
+        BoxShadow(
+            offset: Offset(0.0, 3),
+            blurRadius: 3,
+            spreadRadius: 0,
+            color: Color(0xffF1F1F1))
+      ],
+      gradient: LinearGradient(
+        begin: Alignment.topCenter,
+        end: Alignment.bottomCenter,
+        colors: <Color>[Color(0xffF0F0F0), Color(0xffF6F6F6)],
+      ),
+    );
+
+    BoxDecoration confirmDecoration = BoxDecoration(
+      color: buttonColor,
+      shape: BoxShape.rectangle,
+      borderRadius: BorderRadius.all(Radius.circular(height / 2)),
+      boxShadow: buttonColor == null
+          ? [
+              BoxShadow(
+                  offset: Offset(0.0, 3),
+                  blurRadius: 3,
+                  spreadRadius: 0,
+                  color: Color(0x82FF9100))
+            ]
+          : null,
+      gradient: buttonColor == null
+          ? LinearGradient(
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+              colors: <Color>[Color(0xffFFC400), Color(0xffFFAA00)],
+            )
+          : null,
+    );
+
+    var map = {
+      "cancel": cancelDecoration,
+      "confirm": confirmDecoration,
+    };
+
+    return InkWell(
+      onTap: callback,
+      borderRadius: BorderRadius.all(Radius.circular(height / 2)),
+      child: Container(
+        width: width,
+        height: height,
+        alignment: Alignment.center,
+        decoration: map['$type'],
+        child: content?.isNotEmpty == true
+            ? Text(
+                content,
+                style: TextStyle(
+                    color: textColor != null ? textColor : Colors.white,
+                    fontSize:
+                        height >= 40 ? callback == null ? 14.0 : 16.0 : 14.0,
+                    fontWeight: bold ? FontWeight.w600 : FontWeight.normal),
+                strutStyle: fixedLine,
+              )
+            : child,
+      ),
+    );
+  }
+}

+ 163 - 39
lib/widgets/game_run.dart

@@ -2,10 +2,15 @@ import 'dart:io';
 import 'package:device_apps/device_apps.dart' as app;
 import 'package:android_intent/android_intent.dart';
 import 'package:android_intent/flag.dart';
+import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
+import 'package:sport/pages/home/sport_list_page.dart';
 import 'package:sport/utils/toast.dart';
 import 'package:sport/widgets/button_primary.dart';
 
+import 'image.dart';
+import 'image.dart';
+import 'image.dart';
 
 Future startRun(BuildContext context) async {
   var package = "com.ouj.hiyd";
@@ -13,7 +18,7 @@ Future startRun(BuildContext context) async {
 
   if (Platform.isAndroid) {
     var sport = await app.DeviceApps.getApp(package);
-    if(sport == null) {
+    if (sport == null) {
       ToastUtil.show("你还没安装 Hi运动 app");
       return;
     }
@@ -21,61 +26,180 @@ Future startRun(BuildContext context) async {
         action: "android.intent.action.MAIN",
         package: package,
         componentName: componentName,
-        flags: [
-          Flag.FLAG_ACTIVITY_NEW_TASK
-        ],
-        arguments: {
-
-        });
+        flags: [Flag.FLAG_ACTIVITY_NEW_TASK],
+        arguments: {});
     intent.launch();
   }
 }
 
 class GameRun extends StatelessWidget {
+  Function changeIndex;
+  GameRun({this.changeIndex});
+
   @override
   Widget build(BuildContext context) {
     return GestureDetector(
       behavior: HitTestBehavior.opaque,
-      onTap: () {},
+      onTap: () {
+        if (changeIndex != null) {
+          changeIndex(1);
+        } else {
+          showDialog(
+              context: context,
+              child: SportListPage(
+                index: ValueNotifier(1),
+              ));
+        }
+      },
       child: Row(
         children: <Widget>[
           Container(
-            width: 50.0,
-            height: 50.0,
-            margin: const EdgeInsets.all(12.0),
-            child: Image.asset("lib/assets/img/home_game_run.png"),
+              width: 50.0,
+              height: 50.0,
+              margin: const EdgeInsets.all(12.0),
+              // child: Image.asset("lib/assets/img/home_game_run.png"),
+              child: Image.asset("lib/assets/img/game_icon_function.png")),
+          // Expanded(
+          //   child: Column(
+          //     crossAxisAlignment: CrossAxisAlignment.start,
+          //     children: <Widget>[
+          // Text(
+          //   "跑步训练",
+          //   style: Theme.of(context)
+          //       .textTheme
+          //       .subtitle1
+          //       .copyWith(fontSize: 16.0, fontWeight: FontWeight.w600),
+          // ),
+          // SizedBox(
+          //   height: 3,
+          // ),
+          // Text("125514人在练",
+          //     style: Theme.of(context).textTheme.bodyText1, maxLines: 1),
+          // SizedBox(
+          //   height: 6,
+          // )
+          //     ],
+          //   ),
+          // ),
+          // Padding(
+          //   padding: const EdgeInsets.all(12.0),
+          //   child: PrimaryButton(
+          //     width: 93,
+          //     height: 35,
+          //     content: "开始跑步",
+          //     callback: () {
+          //       // startRun(context);
+          //     },
+          //   ),
+          // )
+          Text(
+            "小功能合集",
+            style: Theme.of(context)
+                .textTheme
+                .subtitle1
+                .copyWith(fontSize: 16.0, fontWeight: FontWeight.w600),
           ),
           Expanded(
-            child: Column(
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: <Widget>[
-                Text(
-                  "跑步训练",
-                  style: Theme.of(context).textTheme.subtitle1.copyWith(fontSize: 16.0, fontWeight: FontWeight.w600),
-                ),
-                SizedBox(
-                  height: 3,
-                ),
-                Text("125514人在练", style: Theme.of(context).textTheme.bodyText1, maxLines: 1),
-                SizedBox(
-                  height: 6,
-                )
-              ],
-            ),
-          ),
-          Padding(
-            padding: const EdgeInsets.all(12.0),
-            child: PrimaryButton(
-              width: 93,
-              height: 35,
-              content: "开始跑步",
-              callback: () {
-                startRun(context);
-              },
+              child: Padding(
+            padding: EdgeInsets.only(right: 12.0),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.end,
+              children: <Widget>[arrowRight4()],
             ),
-          )
+          ))
         ],
       ),
     );
   }
 }
+
+class FunctionSet extends StatelessWidget {
+  List map = [
+    {
+      "name": "户外跑步",
+      "url": "function_icon_run.png",
+      "callBack": () {},
+    },
+    {
+      "name": "实时计步",
+      "url": "function_icon_steps.png",
+      "callBack": () {},
+    },
+    {
+      "name": "体重检测",
+      "url": "function_icon_weight.png",
+      "callBack": () {},
+    }
+  ];
+
+  @override
+  Widget build(BuildContext context) {
+    return Expanded(
+      child: Padding(
+        padding: EdgeInsets.fromLTRB(15.0, 0, 15.0, 0),
+        child: GridView(
+          shrinkWrap: true,
+          physics: NeverScrollableScrollPhysics(),
+          padding: EdgeInsets.zero,
+          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+            crossAxisCount: 3,
+            crossAxisSpacing: 12.0,
+          ),
+          children: map
+              .map((e) => GestureDetector(
+                    onTap: () {
+                      e['callBack']();
+                    },
+                    child: Container(
+                      decoration: BoxDecoration(
+                          color: Colors.white,
+                          borderRadius: BorderRadius.all(Radius.circular(5.0))),
+                      child: Column(
+                        children: <Widget>[
+                          Padding(
+                            padding: EdgeInsets.fromLTRB(22.0, 12.0, 22.0, 8.0),
+                            child: Image.asset(
+                              "lib/assets/img/${e["url"]}",
+                              width: 56.0,
+                              height: 56.0,
+                            ),
+                          ),
+                          Text(
+                            "${e['name']}",
+                            style: TextStyle(color: Color(0xff000000)),
+                          )
+                        ],
+                      ),
+                    ),
+                  ))
+              .toList(),
+          // itemBuilder: (context, index) {
+          //   return Container(
+          //     decoration: BoxDecoration(
+          //         color: Colors.white,
+          //         borderRadius: BorderRadius.all(Radius.circular(5.0))),
+          //     height: 116,
+          //     child: Column(
+          //       children: <Widget>[
+          //         Padding(
+          //           padding: EdgeInsets.fromLTRB(22.0, 12.0, 22.0, 8.0),
+          //           child: Image.asset(
+          //             "lib/assets/img/function_icon_run.png",
+          //             width: 56.0,
+          //             height: 56.0,
+          //           ),
+          //         ),
+          //         Text(
+          //           "户外跑步",
+          //           style: TextStyle(color: Color(0xff000000)),
+          //         )
+          //       ],
+          //     ),
+          //   );
+          // },
+          // itemCount: 3,
+        ),
+      ),
+    );
+  }
+}

+ 1 - 0
pubspec.yaml

@@ -82,6 +82,7 @@ dependencies:
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^0.1.3
   azlistview: ^1.1.0 # 列表搜索
+  scrollable_positioned_list: ^0.1.10 # 锚点
 
 dev_dependencies:
   flutter_test: