1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300 |
- import 'dart:math';
- import 'package:cached_network_image/cached_network_image.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter_blue/flutter_blue.dart';
- import 'package:flutter_easyrefresh/easy_refresh.dart';
- import 'package:provider/provider.dart';
- import 'package:shared_preferences/shared_preferences.dart';
- import 'package:sport/bean/game.dart' as game;
- import 'package:sport/bean/game.dart';
- import 'package:sport/bean/sport_detail.dart';
- import 'package:sport/bean/sport_index.dart';
- import 'package:sport/bean/user.dart';
- import 'package:sport/constant/ui.dart' show ui_padding, ui_margin_list;
- import 'package:sport/pages/game/detail_bottom.dart';
- import 'package:sport/pages/game/game_detail.dart';
- import 'package:sport/pages/game/game_info.dart';
- import 'package:sport/pages/home/consume_page.dart';
- import 'package:sport/pages/home/duration_page.dart';
- import 'package:sport/pages/home/guide_page.dart';
- import 'package:sport/pages/home/sport_history_all_page.dart';
- import 'package:sport/pages/home/sport_history_page.dart';
- import 'package:sport/pages/home/sport_list_page.dart';
- import 'package:sport/pages/home/step_page.dart';
- import 'package:sport/pages/home/strength_page.dart';
- import 'package:sport/provider/bluetooth.dart';
- import 'package:sport/provider/lib/provider_widget.dart';
- import 'package:sport/provider/lib/view_state_lifecycle.dart';
- import 'package:sport/provider/sport_index_model.dart';
- import 'package:sport/provider/user_model.dart';
- import 'package:sport/router/navigator_util.dart';
- import 'package:sport/router/routes.dart';
- import 'package:sport/widgets/button_primary.dart';
- import 'package:sport/widgets/circular_percent_indicator.dart';
- import 'package:sport/widgets/decoration.dart';
- import 'package:sport/widgets/dialog/search_device.dart';
- import 'package:sport/widgets/dialog/share_popup.dart';
- import 'package:sport/widgets/error.dart';
- import 'package:sport/widgets/game_run.dart';
- import 'package:sport/widgets/image.dart';
- import 'package:sport/widgets/loading.dart';
- import 'package:sport/widgets/misc.dart';
- import 'package:sport/widgets/progress_bar.dart';
- import 'package:sport/widgets/space.dart';
- import 'package:sport/widgets/wave_painter.dart';
- class HomeInfoPage extends StatefulWidget {
- @override
- State<StatefulWidget> createState() => _PageState();
- }
- class _PageState extends ViewStateLifecycle<HomeInfoPage, SportIndexModel> with AutomaticKeepAliveClientMixin {
- String _rank;
- ValueNotifier<bool> _valueNotifierGuide = ValueNotifier(false);
- static const String GUIDE = "guide";
- EasyRefreshController _easyRefreshController;
- Bluetooth bluetooth;
- @override
- void initState() {
- super.initState();
- _easyRefreshController = EasyRefreshController();
- loadSetting();
- initList();
- bluetooth = Provider.of<Bluetooth>(context, listen: false);
- }
- void loadSetting() async {
- SharedPreferences preferences = await SharedPreferences.getInstance();
- _valueNotifierGuide.value = preferences.getBool(GUIDE) ?? true;
- }
- @override
- SportIndexModel createModel() => SportIndexModel(context);
- refresh() async {
- _rank = null;
- model.refresh();
- if (bluetooth?.isConnected == true) {
- bluetooth.queryDeviceStep();
- await Future.delayed(Duration(seconds: 5));
- model.refresh();
- }
- }
- initList() {
- model.valueNotifier.addListener(() {
- print("list--------------------------${model.valueNotifier.value}");
- if (model.valueNotifier.value.length > 0) {
- Navigator.push(context, new PopRoute(child: sharePopup(model.valueNotifier.value)));
- }
- });
- }
- @override
- Widget build(BuildContext context) {
- super.build(context);
- const _margin = EdgeInsets.fromLTRB(ui_padding, ui_padding, ui_padding, 0.0);
- return Scaffold(
- appBar: AppBar(
- titleSpacing: 0.0,
- backgroundColor: Theme.of(context).scaffoldBackgroundColor,
- title: _buildDeviceInfoWidget(),
- ),
- body: ProviderWidget<SportIndexModel>(
- model: this.model,
- onModelReady: (v) => v.initData(),
- builder: (BuildContext context, SportIndexModel model, Widget child) => EasyRefresh.custom(
- controller: _easyRefreshController,
- onRefresh: () => refresh(),
- header: buildClassicalHeader(),
- slivers: <Widget>[
- // // 暂时测试
- // if (model.isIdle && value.data != null)
- // SliverToBoxAdapter(
- // child: Stack(
- // fit: StackFit.passthrough,
- // children: <Widget>[
- // CustomPaint(
- // painter: _HeaderBackground(),
- // child: Container(
- // height: 116,
- // ),
- // ),
- // Container(
- // margin: EdgeInsets.fromLTRB(ui_padding, 4.0, ui_padding, 10.0),
- // decoration: card(),
- // height: 156,
- // child: _buildSportWidget(value.data),
- // )
- // ],
- // ),
- // ),
- // if (model.isIdle && value.data != null)
- // SliverToBoxAdapter(
- // child: _buildTopWidget(value.data),
- // ),
- if (model.isBusy)
- SliverToBoxAdapter(
- child: RequestLoadingWidget(),
- ),
- // if (value.data?.lastGame != null)
- // SliverToBoxAdapter(
- // child: _buildSportHistoryWidget(value.data.lastGame),
- // ),
- // SliverToBoxAdapter(
- // child: ValueListenableBuilder<bool>(
- // builder: (BuildContext context, value, Widget child) => value ? _buildGuideWidget() : Container(), valueListenable: _valueNotifierGuide),
- // ),
- SliverToBoxAdapter(
- child: Container(
- height: 250,
- child: Column(
- children: <Widget>[
- Container(
- height: 182,
- child: Selector<Bluetooth, BluetoothDevice>(
- selector: (_, bluetooth) => bluetooth.device,
- builder: (_, device, ___) {
- return device == null
- ? CachedNetworkImage(
- height: 182,
- imageUrl: "http://static.ouj.com/hiyd/fb337b03b0929085f1d07c036cd40ec4_size750x281_115600.png",
- )
- : StreamBuilder<BluetoothDeviceState>(
- stream: device.state,
- initialData: BluetoothDeviceState.connecting,
- builder: (c, snapshot) => CachedNetworkImage(
- height: 182,
- imageUrl: snapshot.data == BluetoothDeviceState.connected
- ? "http://static.ouj.com/hiyd/a856a17e1cd2006a6cd6e7df6b7f1357_size750x285_116051.png"
- : "http://static.ouj.com/hiyd/fb337b03b0929085f1d07c036cd40ec4_size750x281_115600.png",
- ));
- })),
- Space(
- height: 12,
- ),
- Selector<Bluetooth, BluetoothDevice>(
- selector: (_, bluetooth) => bluetooth.device,
- builder: (_, device, ___) {
- return device != null
- ? PrimaryButton(
- content: "开始运动",
- width: 174,
- height: 40,
- // bold: true,
- callback: () {
- showDialog(context: context, child: SportListPage());
- },
- )
- : PrimaryButton(
- content: "添加设备",
- width: 174,
- height: 40,
- callback: () {
- showDialog(context: context, child: SearchDeviceDialog());
- },
- );
- }),
- Space(
- height: 12,
- ),
- ],
- ),
- ),
- ),
- SliverToBoxAdapter(
- child: Container(
- margin: _margin,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: <Widget>[
- Expanded(
- child: GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => StepPage()),
- behavior: HitTestBehavior.opaque,
- child: Container(
- decoration: circular(),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- RichText(
- text: TextSpan(style: DefaultTextStyle.of(context).style, children: <InlineSpan>[
- WidgetSpan(
- alignment: PlaceholderAlignment.middle,
- child: Image.asset(
- 'lib/assets/img/home_title_steps.png',
- ),
- ),
- TextSpan(text: '\t今日步数', style: Theme.of(context).textTheme.subtitle1)
- ]),
- ),
- Padding(
- padding: const EdgeInsets.all(20.0),
- child: Center(
- child: Row(
- children: <Widget>[
- Text(
- "${model.data?.today?.step ?? 0}",
- style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 26.0),
- strutStyle: fixedLine,
- ),
- Text(
- "步",
- style: Theme.of(context).textTheme.subtitle2,
- strutStyle: fixedLine,
- )
- ],
- crossAxisAlignment: CrossAxisAlignment.end,
- mainAxisSize: MainAxisSize.min,
- ),
- ),
- )
- ],
- ),
- padding: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0),
- ),
- ),
- ),
- SizedBox(
- width: 12.0,
- ),
- Expanded(
- child: GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => ConsumePage()),
- behavior: HitTestBehavior.opaque,
- child: Container(
- decoration: circular(),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- RichText(
- text: TextSpan(style: DefaultTextStyle.of(context).style, children: <InlineSpan>[
- WidgetSpan(
- alignment: PlaceholderAlignment.middle,
- child: Image.asset(
- 'lib/assets/img/home_title_consume.png',
- ),
- ),
- TextSpan(text: '\t今日消耗', style: Theme.of(context).textTheme.subtitle1)
- ]),
- ),
- Padding(
- padding: const EdgeInsets.all(20.0),
- child: Center(
- child: Row(
- children: <Widget>[
- Text(
- "${model.data?.today?.consume ?? 0}",
- style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 26.0),
- strutStyle: fixedLine,
- ),
- Text(
- "卡",
- style: Theme.of(context).textTheme.subtitle2,
- strutStyle: fixedLine,
- )
- ],
- crossAxisAlignment: CrossAxisAlignment.end,
- mainAxisSize: MainAxisSize.min,
- ),
- ),
- )
- ],
- ),
- padding: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 0),
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- SliverToBoxAdapter(
- child: GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => DurationPage()),
- child: Container(
- margin: _margin,
- decoration: circular(),
- child: Column(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.all(8.0),
- child: Row(
- children: <Widget>[
- RichText(
- text: TextSpan(style: DefaultTextStyle.of(context).style, children: <InlineSpan>[
- WidgetSpan(
- alignment: PlaceholderAlignment.middle,
- child: Image.asset(
- 'lib/assets/img/home_title_duration.png',
- ),
- ),
- TextSpan(text: '\t运动目标', style: Theme.of(context).textTheme.subtitle1)
- ]),
- ),
- arrowRight4()
- ],
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- ),
- ),
- Divider(
- height: 0.5,
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
- child: Row(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 3.0),
- child: CircularPercentIndicator(
- radius: 100.0,
- lineWidth: 10.0,
- percent: 1.0 * (model?.data?.today?.value(model.data?.target?.type) ?? 0) / (model.data?.target?.valueTarget ?? 0.01),
- center: Column(
- children: <Widget>[
- SizedBox(
- height: 10.0,
- ),
- Text(
- "${model.data?.today?.value(model.data?.target?.type) ?? 0}",
- style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 26.0),
- strutStyle: fixedLine,
- ),
- Text(
- "${model.data?.target?.label}",
- style: Theme.of(context).textTheme.subtitle2,
- strutStyle: fixedLine,
- )
- ],
- mainAxisSize: MainAxisSize.min,
- ),
- animation: true,
- animationDuration: 1000,
- animateFromLastPercent: true,
- startAngle: 200.0,
- arcType: ArcType.CUSTOM,
- backgroundColor: Color(0xfff1f1f1),
- circularStrokeCap: CircularStrokeCap.round,
- rotateLinearGradient: true,
- linearGradient: LinearGradient(
- colors: <Color>[Color(0xff8DF7FF), Color(0xff16A2FF)],
- ),
- ),
- ),
- SizedBox(
- width: 15.0,
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text(
- "今日目标:${model.data?.target?.valueTarget ?? 0} ${model.data?.target?.label}",
- style: Theme.of(context).textTheme.subtitle1,
- ),
- SizedBox(
- height: 8.0,
- ),
- Text(
- "月达标天数:${model.data?.target?.monthFinish ?? 0}天",
- style: Theme.of(context).textTheme.subtitle1,
- )
- ],
- )
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- SliverToBoxAdapter(
- child: GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => StrengthPage()),
- child: Container(
- margin: _margin,
- decoration: circular(),
- child: Column(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.all(8.0),
- child: Row(
- children: <Widget>[
- RichText(
- text: TextSpan(style: DefaultTextStyle.of(context).style, children: <InlineSpan>[
- WidgetSpan(
- alignment: PlaceholderAlignment.middle,
- child: Image.asset(
- 'lib/assets/img/home_title_strength.png',
- ),
- ),
- TextSpan(text: '\t运动强度', style: Theme.of(context).textTheme.subtitle1)
- ]),
- ),
- arrowRight4()
- ],
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- ),
- ),
- Divider(
- height: 0.5,
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
- child: Row(
- children: <Widget>[
- CircularProgressBar(
- percent: (model.data?.today?.strength ?? 0) / 12.0,
- center: Column(
- children: <Widget>[
- SizedBox(
- height: 10.0,
- ),
- Text(
- "${model.data?.today?.strength?.toStringAsFixed(1) ?? 0}",
- style: Theme.of(context).textTheme.headline2.copyWith(fontSize: 26.0),
- strutStyle: fixedLine,
- ),
- Text(
- "卡/分",
- style: Theme.of(context).textTheme.subtitle2,
- strutStyle: fixedLine,
- )
- ],
- mainAxisSize: MainAxisSize.min,
- ),
- ),
- SizedBox(
- width: 15.0,
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text(
- "强度评级:${model.data?.today?.strengthLabel()}",
- style: Theme.of(context).textTheme.subtitle1,
- ),
- SizedBox(
- height: 8.0,
- ),
- Text(
- "已经运动:${(model.data?.today?.duration ?? 0) == 0 ? '无' : "${model.data?.today?.duration}分钟"}",
- style: Theme.of(context).textTheme.subtitle1,
- )
- ],
- )
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- SliverToBoxAdapter(
- child: Container(
- padding: EdgeInsets.fromLTRB(12.0,16.0, 12.0,4.0),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: <Widget>[
- Text(
- "今日运动",
- style: Theme.of(context).textTheme.headline1.copyWith(fontSize: 16.0),
- ),
- GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => SportHistoryAllPage()),
- child: RichText(
- text: TextSpan(style: DefaultTextStyle.of(context).style, children: <InlineSpan>[
- TextSpan(text: '更多\t', style: Theme.of(context).textTheme.bodyText1),
- WidgetSpan(
- alignment: PlaceholderAlignment.middle,
- child: arrowRight4(),
- ),
- ]),
- ),
- ),
- ],
- )),
- ),
- // if(model.data?.records?.isNotEmpty == true)
- SliverPadding(
- padding: const EdgeInsets.symmetric(horizontal: ui_padding),
- sliver: SliverList(
- delegate: SliverChildBuilderDelegate((content, index) {
- if (index == 0) {
- return _buildSportRecord(RecordsToday(id: -1, name: "跑步训练", userCount: 144234, cover: "lib/assets/img/home_game_run.png"), null, 0);
- }
- var item = model.data?.records[index - 1];
- var game = model.data?.games?.firstWhere((element) => element.id == item.gameId);
- return GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => SportHistoryPage(game)), child: _buildSportRecord(item, game, 1));
- }, childCount: (model.data?.records?.length ?? 0) + 1),
- )),
- // SliverToBoxAdapter(
- // child: Container(
- // margin: const EdgeInsets.fromLTRB(ui_padding, 14.0, ui_padding, 14.0),
- // decoration: circular(),
- // child: RequestErrorWidget(
- // null,
- // assets: RequestErrorWidget.ASSETS_NO_MOTION,
- // msg: "您还未进行任何运动",
- // ))),
- // if (value.data?.games != null)
- // SliverToBoxAdapter(
- // child: _buildLabelWidget("SPORTS"),
- // ),
- // if (value.data?.games != null)
- // SliverPadding(
- // padding: const EdgeInsets.symmetric(horizontal: ui_padding),
- // sliver: SliverGrid(
- // gridDelegate:
- // SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, childAspectRatio: 170.0 / 226),
- // delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
- // return InkWell(
- // onTap: () => NavigatorUtil.goGameDetails(context, details: value.data.games[index]),
- // child: _buildSportItemWidget(value.data.games[index]));
- // }, childCount: value.data.games.length),
- // ),
- // ),
- // if (value.data?.rank != null)
- // SliverToBoxAdapter(
- // child: Padding(
- // padding: const EdgeInsets.only(top: 12.0),
- // child: Row(
- // children: <Widget>[
- // Expanded(child: _buildLabelWidget("CHARTS")),
- // PopupMenuButton(
- // onSelected: (v) {
- // value.game(v);
- // },
- // itemBuilder: (BuildContext context) {
- // return divideMenus(value.data.games.map((e) => menuItemSelected(e.id, e.name, e.id == value.gameId)).toList());
- // },
- // child: Row(
- // mainAxisSize: MainAxisSize.min,
- // children: <Widget>[
- // Text(
- // value.data.games.where((element) => element.id == value.gameId).map((e) => e.name).first,
- // style: Theme.of(context).textTheme.bodyText1,
- // ),
- // Padding(
- // padding: const EdgeInsets.all(6.0),
- // child: arrowBottom(),
- // )
- // ],
- // ),
- // ),
- // SizedBox(
- // width: 12,
- // ),
- // NotificationListener<AreaNotification>(
- // onNotification: (n) {
- // _rank = n.rank;
- // request(context, () async {
- // await value.area(
- // n.all ? null : n.provinceId, n.all ? null : n.province ? null : n.cityId, n.all ? null : n.province ? null : n.districtId);
- // });
- // return true;
- // },
- // child: AreaPage(
- // area: _rank,
- // ),
- // )
- // ],
- // ),
- // ),
- // ),
- // if (value.data?.rank != null)
- // SliverToBoxAdapter(
- // child: _buildRankWidget(value.data.rank),
- // ),
- // if (value.data?.rank != null)
- // SliverPadding(
- // padding: const EdgeInsets.symmetric(horizontal: ui_padding),
- // sliver: SliverList(
- // delegate: SliverChildBuilderDelegate((content, index) {
- // return (value.data.rank.records.length - 3) > index
- // ? _buildRankItemWidget(value.data.rank.records[index + 3], index)
- // : _buildRankItemWidget(null, index);
- // }, childCount: 7),
- // )),
- // if (value.data?.rank != null)
- // SliverToBoxAdapter(
- // child: Center(
- // child: InkWell(
- // onTap: () {
- // NavigatorUtil.goRankDetails(context, value.data.rank.rank.gameId, 1);
- // },
- // child: Padding(
- // padding: const EdgeInsets.all(16.0),
- // child: Text(
- // "查看完整榜单",
- // style: Theme.of(context).textTheme.bodyText1.copyWith(color: Color(0xffcecece)),
- // ),
- // ),
- // )),
- // ),
- SliverToBoxAdapter(
- child: SizedBox(
- height: 12,
- ),
- ),
- ],
- ),
- ),
- );
- }
- @override
- bool get wantKeepAlive => true;
- Widget _buildDeviceInfoWidget() {
- return Padding(
- padding: const EdgeInsets.only(left: ui_padding),
- child: Selector<Bluetooth, BluetoothDevice>(
- selector: (_, bluetooth) => bluetooth.device,
- builder: (_, device, ___) {
- return device == null ? _buildDeviceInfoConnectFailWidget() : _buildDeviceInfoStateWidget(device);
- }),
- );
- }
- Widget _buildDeviceInfoStateWidget(BluetoothDevice device) {
- return StreamBuilder<BluetoothDeviceState>(
- stream: device.state,
- initialData: BluetoothDeviceState.connecting,
- builder: (c, snapshot) => _buildDeviceInfoConnectedWidget(snapshot.data == BluetoothDeviceState.connected));
- }
- Widget _buildDeviceInfoConnectedWidget(bool connect) {
- const Color _color = Color(0xffFF5B1D);
- return GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () => NavigatorUtil.go(context, Routes.deviceInfo),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: <Widget>[
- Row(
- children: <Widget>[
- Container(
- width: 10,
- height: 10,
- decoration: BoxDecoration(shape: BoxShape.circle, color: connect ? Color(0xff00DC42) : _color),
- ),
- SizedBox(
- width: 6.0,
- ),
- Text("设备:${bluetooth?.device?.name}", style: Theme.of(context).textTheme.subtitle1, strutStyle: StrutStyle(forceStrutHeight: true)),
- ],
- ),
- ValueListenableBuilder(
- valueListenable: Provider.of<Bluetooth>(context, listen: false).electricityNotifier,
- builder: (_, data, ___) => Container(
- padding: EdgeInsets.fromLTRB(15.0, 6.0, 10.0, 6.0),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.only(topLeft: Radius.circular(30), bottomLeft: Radius.circular(30)),
- border: Border.all(
- color: Theme.of(context).scaffoldBackgroundColor,
- width: .5,
- ),
- ),
- child: Row(
- children: <Widget>[
- Stack(
- alignment: Alignment.bottomCenter,
- children: <Widget>[
- Image.asset(
- "lib/assets/img/battery.png",
- color: const Color(0xff241D19),
- ),
- Container(
- width: 5.5,
- height: 8 * (data / 100),
- margin: EdgeInsets.only(bottom: 2, right: 0.5),
- decoration: BoxDecoration(color: const Color(0xff241D19)),
- ),
- ],
- ),
- const SizedBox(
- width: 5,
- ),
- Text(
- "$data%",
- style: Theme.of(context).textTheme.subtitle1,
- )
- ],
- ),
- )),
- ],
- ));
- }
- Widget _buildDeviceInfoConnectFailWidget() {
- const Color _color = Color(0xffFF5B1D);
- return Row(
- children: <Widget>[
- Container(
- width: 10,
- height: 10,
- decoration: BoxDecoration(shape: BoxShape.circle, color: _color),
- ),
- SizedBox(
- width: 6.0,
- ),
- Text("未连接设备",
- style: TextStyle(
- color: _color,
- fontSize: 14,
- ),
- strutStyle: StrutStyle(forceStrutHeight: true)),
- ],
- );
- }
- Widget _buildDeviceWidget() {
- return Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: <Widget>[
- Image.asset("lib/assets/img/home_image_connect.png"),
- Space(
- height: 8,
- ),
- Text(
- "请先连接设备鞋子",
- style: Theme.of(context).textTheme.bodyText1,
- ),
- Space(
- height: 12,
- ),
- PrimaryButton(
- content: "搜索设备",
- width: 132,
- height: 35,
- callback: () {
- showDialog(context: context, child: SearchDeviceDialog());
- },
- )
- ],
- );
- }
- Widget _buildTopWidget(SportIndex item) {
- return Stack(
- fit: StackFit.passthrough,
- children: <Widget>[
- CustomPaint(
- painter: _HeaderBackground(),
- child: Container(
- height: 116,
- ),
- ),
- Container(
- margin: EdgeInsets.fromLTRB(ui_padding, 4.0, ui_padding, 10.0),
- decoration: card(),
- height: 156,
- child: Selector<Bluetooth, BluetoothDevice>(
- selector: (_, bluetooth) => bluetooth.device,
- builder: (_, device, ___) {
- return device != null ? _buildSportWidget(item) : _buildDeviceWidget();
- }),
- )
- ],
- );
- }
- Widget _buildSportWidget(SportIndex item) {
- return InkWell(
- onTap: () => NavigatorUtil.go(context, Routes.sportDetail),
- child: Stack(
- alignment: Alignment.center,
- children: <Widget>[
- Row(
- children: <Widget>[
- Expanded(
- flex: 5,
- child: Padding(
- padding: const EdgeInsets.all(16.0),
- child: ValueListenableBuilder(
- valueListenable: Provider.of<UserModel>(context, listen: false).durationTarget,
- builder: (_, v, __) => ProgressManager(min(.9, v <= 0 ? 0 : item.duration / v))),
- )),
- Expanded(
- flex: 6,
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text(
- "今日已运动",
- style: Theme.of(context).textTheme.subtitle1,
- ),
- SizedBox(
- height: 5,
- ),
- RichText(
- text: TextSpan(style: Theme.of(context).textTheme.subtitle2, children: <InlineSpan>[
- TextSpan(text: '${item.duration}', style: Theme.of(context).textTheme.subtitle2.copyWith(fontWeight: FontWeight.bold, fontSize: 40)),
- TextSpan(text: '分钟'),
- ]),
- ),
- SizedBox(
- height: 5,
- ),
- Text("共消耗 ${item.consume} kal", style: Theme.of(context).textTheme.bodyText1),
- SizedBox(
- height: 5,
- ),
- Text(item.beyond > 0 ? "已超越了${item.beyond}人,请再接再厉" : "${item.inspire}", style: Theme.of(context).textTheme.bodyText1),
- ],
- ),
- )
- ],
- ),
- Positioned(
- right: 0,
- child: Image.asset("lib/assets/img/home_icon_details.png"),
- )
- ],
- ),
- );
- }
- Widget _buildSportRecord(RecordsToday item, GameInfoData game, int type) {
- return Container(
- margin: const EdgeInsets.only(top: ui_padding),
- decoration: circular(),
- child: Column(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.fromLTRB(ui_padding, 14.0, ui_padding, 14.0),
- child: Row(
- children: <Widget>[
- item.cover?.startsWith("http") == true
- ? GestureDetector(
- onTap: () => NavigatorUtil.goPage(context, (context) => GameDetailsPage(game)),
- child: ClipRRect(
- child: CachedNetworkImage(
- width: 50,
- height: 50,
- imageUrl: item.cover ?? '',
- fit: BoxFit.cover,
- ),
- // 也可控件一边圆角大小
- borderRadius: new BorderRadius.all(Radius.circular(6.0)),
- ),
- )
- : Image.asset(
- item.cover,
- width: 50.0,
- height: 50.0,
- ),
- SizedBox(
- width: ui_padding,
- ),
- Expanded(
- child: Column(
- children: <Widget>[
- Text(item.name, style: Theme.of(context).textTheme.headline1.copyWith(fontSize: 16.0)),
- const SizedBox(
- height: 6.0,
- ),
- Text(
- "${item.userCount}人在练",
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ],
- crossAxisAlignment: CrossAxisAlignment.start,
- )),
- PrimaryButton(
- width: 72,
- height: 35,
- content: type == 0 ? "跑步" : "继续",
- callback: type == 0
- ? () {
- startRun(context);
- }
- : () => startGame(context, game),
- )
- ],
- ),
- ),
- Divider(
- height: 0.5,
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(ui_padding, 15.0, ui_padding, 15.0),
- child: Row(
- children: <Widget>[
- Column(
- children: <Widget>[
- Text(type == 0 ? "38.0" : "${item.durationTotalMinute}", style: Theme.of(context).textTheme.headline1),
- const SizedBox(
- height: 2.0,
- ),
- Text(
- type == 0 ? "总里程(公里)" : "总时长(分钟)",
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ],
- ),
- Column(
- children: <Widget>[
- type == 0
- ? RichText(
- text: TextSpan(style: Theme.of(context).textTheme.headline1, children: <InlineSpan>[
- TextSpan(text: "30′"),
- WidgetSpan(
- alignment: PlaceholderAlignment.bottom,
- child: Padding(
- padding: const EdgeInsets.only(bottom: 1.0),
- child: Text("38″", style: Theme.of(context).textTheme.subtitle1.copyWith(fontWeight: FontWeight.w600)),
- ))
- ]),
- )
- : Text("${item.todayScoreMax.toStringAsFixed(1)}", style: Theme.of(context).textTheme.headline1),
- const SizedBox(
- height: 2.0,
- ),
- Text(
- type == 0 ? "总时长" : "今日最高评分",
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ],
- ),
- Column(
- children: <Widget>[
- type == 0
- ? RichText(
- text: TextSpan(style: Theme.of(context).textTheme.headline1, children: <InlineSpan>[
- TextSpan(text: "12′"),
- WidgetSpan(
- alignment: PlaceholderAlignment.bottom,
- child: Padding(
- padding: const EdgeInsets.only(bottom: 1.0),
- child: Text("38″", style: Theme.of(context).textTheme.subtitle1.copyWith(fontWeight: FontWeight.w600)),
- ),
- )
- ]),
- )
- : Text("${item.times}", style: Theme.of(context).textTheme.headline1),
- const SizedBox(
- height: 2.0,
- ),
- Text(
- type == 0 ? "平均配速" : "运动次数(次)",
- style: Theme.of(context).textTheme.bodyText1,
- ),
- ],
- )
- ],
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- ),
- ),
- ],
- ));
- }
- Widget _buildRankWidget(RankInfo rankInfo) {
- return Column(
- children: <Widget>[
- if (rankInfo?.user != null)
- GestureDetector(
- onTap: () => NavigatorUtil.goRankPeopleDetails(context, details: rankInfo.user),
- child: Container(
- margin: EdgeInsets.all(ui_padding),
- padding: EdgeInsets.all(ui_padding),
- decoration: card(),
- child: Row(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.only(right: 8),
- child: Text(
- "${rankInfo.user.position}",
- ),
- ),
- if (rankInfo.user.up != 0 && rankInfo.user.upNew != 0)
- Padding(
- padding: const EdgeInsets.only(right: 8),
- child: Image.asset("lib/assets/img/rand_icon_${rankInfo.user.up >= 0 ? 'top' : 'down'}.png"),
- ),
- Padding(
- padding: const EdgeInsets.only(right: 10.0),
- child: CircleAvatar(backgroundImage: userAvatarProvider(rankInfo?.user?.userAvatar), radius: 22),
- ),
- Expanded(
- child: Text(
- rankInfo.user.userName,
- style: Theme.of(context).textTheme.subtitle1,
- ),
- ),
- Text(
- "${rankInfo.user.score.toStringAsFixed(1)}分",
- style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
- ),
- ],
- ),
- ),
- ),
- Center(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- crossAxisAlignment: CrossAxisAlignment.end,
- children: <Widget>[
- Container(width: 94, child: rankInfo.records.length >= 2 ? _buildRankHeaderWidget(rankInfo.records[1], 2) : _buildRankHeaderWidget(null, 2)),
- Container(width: 120, child: rankInfo.records.length >= 1 ? _buildRankHeaderWidget(rankInfo.records[0], 1) : _buildRankHeaderWidget(null, 1)),
- Container(width: 94, child: rankInfo.records.length >= 3 ? _buildRankHeaderWidget(rankInfo.records[2], 3) : _buildRankHeaderWidget(null, 3)),
- ],
- ),
- ),
- Space(
- height: 10,
- ),
- Divider(
- indent: 12.0,
- endIndent: 12.0,
- )
- ],
- );
- }
- Widget _buildRankHeaderWidget(User item, int rank) {
- return InkWell(
- onTap: item == null ? null : () => NavigatorUtil.goRankPeopleDetails(context, details: item),
- child: Column(
- children: <Widget>[
- rank == 1
- ? Stack(
- alignment: Alignment.center,
- children: <Widget>[
- CircleAvatar(backgroundImage: userAvatarProvider(item == null ? "" : item.userAvatar), radius: 46.0),
- Image.asset(
- "lib/assets/img/rank_image_no$rank.png",
- )
- ],
- )
- : Stack(
- alignment: Alignment.topCenter,
- children: <Widget>[
- Positioned(top: 3, child: CircleAvatar(backgroundImage: userAvatarProvider(item == null ? "" : item.userAvatar), radius: 35.0)),
- Image.asset(
- "lib/assets/img/rank_image_no$rank.png",
- )
- ],
- ),
- Space(
- height: 6,
- ),
- Text(
- item == null ? "虚位以待" : item.userName,
- style: Theme.of(context).textTheme.subtitle1,
- maxLines: 1,
- ),
- Space(
- height: 4,
- ),
- Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[
- Text(
- item == null ? "" : "${item.score.toStringAsFixed(1)}分",
- style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
- ),
- ],
- ),
- ],
- ),
- );
- }
- Widget _buildLabelWidget(String title) {
- return Container(
- padding: EdgeInsets.fromLTRB(ui_padding, 10.0, ui_padding, 10.0),
- child: Text(
- title,
- style: Theme.of(context).textTheme.headline1,
- ));
- }
- Widget _buildSportItemWidget(game.GameInfoData item) {
- return Container(
- decoration: BoxDecoration(
- image: DecorationImage(
- image: CachedNetworkImageProvider(item.coverVertical),
- fit: BoxFit.cover,
- ),
- borderRadius: BorderRadius.all(Radius.circular(10.0))),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.end,
- children: <Widget>[
- Container(
- width: double.infinity,
- padding: EdgeInsets.fromLTRB(12.0, 12.0, 12.0, 12.0),
- decoration: BoxDecoration(
- gradient:
- LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0x00000000), Color(0x912c2c2c), Color(0xCF000000)]),
- borderRadius: BorderRadius.vertical(bottom: Radius.circular(10.0)),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: <Widget>[
- Text(
- item.name,
- style: Theme.of(context).textTheme.headline3.copyWith(color: Colors.white),
- ),
- Space(
- height: 5,
- ),
- if (item.tags != null)
- Wrap(
- spacing: 4,
- runSpacing: 4,
- children: item.tags.map((e) => gameTag(context, e)).toList(),
- ),
- Space(
- height: 5,
- ),
- Text(
- "${item.userCount}人在玩",
- style: Theme.of(context).textTheme.bodyText1.copyWith(color: Colors.white),
- ),
- ],
- ),
- ),
- ],
- ));
- }
- Widget _buildRankItemWidget(User item, int index) {
- return Column(
- children: <Widget>[
- InkWell(
- onTap: item == null ? null : () => NavigatorUtil.goRankPeopleDetails(context, details: item),
- child: Container(
- child: Row(
- children: <Widget>[
- Container(
- width: 24,
- child: Text(
- "${index + 4}",
- style: Theme.of(context).textTheme.bodyText2,
- ),
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(0, 6, 10.0, 6),
- child: CircleAvatar(
- backgroundColor: Colors.transparent, backgroundImage: userAvatarProvider(item == null ? "" : item.userAvatar ?? ""), radius: 22),
- ),
- Expanded(
- child: Text(
- item == null ? "虚位以待" : item.userName,
- style: Theme.of(context).textTheme.subtitle1,
- maxLines: 1,
- ),
- ),
- Text(
- item == null ? "" : "${item.score.toStringAsFixed(1)}分",
- style: Theme.of(context).textTheme.subtitle1.copyWith(color: Theme.of(context).accentColor),
- ),
- ],
- ),
- )),
- Divider(),
- ],
- );
- }
- Widget _buildGuideWidget() {
- return Container(
- decoration: card(),
- margin: ui_margin_list,
- child: GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () => NavigatorUtil.goPage(context, (context) => GuidePage()),
- child: Stack(children: <Widget>[
- Padding(
- padding: EdgeInsets.all(ui_padding),
- child: Row(
- children: <Widget>[
- Image.asset("lib/assets/img/home_image_guidance.png"),
- Space(
- width: 12,
- ),
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: <Widget>[
- Text(
- "新手指引",
- style: Theme.of(context).textTheme.headline3.copyWith(fontSize: 14.0),
- ),
- Space(
- height: 4,
- ),
- Text("帮助您快速了解并使用相关功能", style: Theme.of(context).textTheme.bodyText1),
- ],
- ),
- ),
- ],
- ),
- ),
- Positioned(
- right: 0,
- child: GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () async {
- SharedPreferences preferences = await SharedPreferences.getInstance();
- preferences.setBool(GUIDE, false);
- _valueNotifierGuide.value = false;
- },
- child: Padding(
- padding: const EdgeInsets.all(12.0),
- child: Image.asset("lib/assets/img/btn_close_small.png"),
- ),
- ),
- )
- ])),
- );
- }
- Widget _buildSportHistoryWidget(game.GameInfoData item) {
- return GameItem(
- type: 1,
- imgUrl: item.cover,
- name: item.name,
- time: item.playTime,
- id: item.id,
- duration: item.durationTotal,
- data: item,
- bold: true,
- );
- }
- }
- class _HeaderBackground extends CustomPainter {
- final Paint _paint = Paint()
- ..color = Color(0xff241D19)
- ..isAntiAlias = true;
- @override
- void paint(Canvas canvas, Size size) {
- Path path = Path();
- path.lineTo(size.width, 0);
- path.lineTo(size.width, size.height);
- path.lineTo(0, size.height / 3 * 2);
- path.close();
- canvas.drawPath(path, _paint);
- }
- @override
- bool shouldRepaint(CustomPainter oldDelegate) {
- return false;
- }
- }
|