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