Compare commits

..

13 Commits

19 changed files with 208 additions and 158 deletions

View File

@ -22,20 +22,27 @@ class HttpError extends StatelessWidget {
"assets/images/error.svg", "assets/images/error.svg",
height: 200, height: 200,
), ),
const SizedBox(height: 20), const SizedBox(height: 30),
Text( Text(
errMsg ?? '请求异常', errMsg ?? '请求异常',
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
), ),
const SizedBox(height: 30), const SizedBox(height: 20),
OutlinedButton.icon( FilledButton.tonal(
onPressed: () { onPressed: () {
fn!(); fn!();
}, },
icon: const Icon(Icons.arrow_forward_outlined, size: 20), style: ButtonStyle(
label: Text(btnText ?? '点击重试'), backgroundColor: MaterialStateProperty.resolveWith((states) {
) return Theme.of(context).colorScheme.primary.withAlpha(20);
}),
),
child: Text(
btnText ?? '点击重试',
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
),
], ],
), ),
), ),

View File

@ -3,7 +3,7 @@ import 'package:pilipala/utils/utils.dart';
class StatDanMu extends StatelessWidget { class StatDanMu extends StatelessWidget {
final String? theme; final String? theme;
final int? danmu; final dynamic danmu;
final String? size; final String? size;
const StatDanMu({Key? key, this.theme, this.danmu, this.size}) const StatDanMu({Key? key, this.theme, this.danmu, this.size})

View File

@ -3,7 +3,7 @@ import 'package:pilipala/utils/utils.dart';
class StatView extends StatelessWidget { class StatView extends StatelessWidget {
final String? theme; final String? theme;
final int? view; final dynamic view;
final String? size; final String? size;
const StatView({Key? key, this.theme, this.view, this.size}) const StatView({Key? key, this.theme, this.view, this.size})

View File

@ -1,6 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../models/model_rec_video_item.dart';
import 'stat/danmu.dart';
import 'stat/view.dart';
import '../../http/dynamics.dart'; import '../../http/dynamics.dart';
import '../../http/search.dart'; import '../../http/search.dart';
import '../../http/user.dart'; import '../../http/user.dart';
@ -322,19 +325,31 @@ class VideoStat extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return RichText( return Row(
children: [
StatView(
theme: 'gray',
view: videoItem.stat.view,
),
const SizedBox(width: 8),
StatDanMu(
theme: 'gray',
danmu: videoItem.stat.danmu,
),
if (videoItem is RecVideoItemModel) ...<Widget>[
const Spacer(),
RichText(
maxLines: 1, maxLines: 1,
text: TextSpan( text: TextSpan(
style: TextStyle( style: TextStyle(
fontSize: MediaQuery.textScalerOf(context) fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
.scale(Theme.of(context).textTheme.labelSmall!.fontSize!),
color: Theme.of(context).colorScheme.outline, color: Theme.of(context).colorScheme.outline,
), ),
children: [ text: Utils.formatTimestampToRelativeTime(videoItem.pubdate)),
TextSpan(text: '${Utils.numFormat(videoItem.stat.view)}观看'),
TextSpan(text: '${Utils.numFormat(videoItem.stat.danmu)}弹幕'),
],
), ),
const SizedBox(width: 4),
]
],
); );
} }
} }

View File

@ -130,7 +130,7 @@ class VideoHttp {
} }
return {'status': true, 'data': list}; return {'status': true, 'data': list};
} else { } else {
return {'status': false, 'data': []}; return {'status': false, 'data': [], 'msg': res.data['message']};
} }
} catch (err) { } catch (err) {
return {'status': false, 'data': [], 'msg': err}; return {'status': false, 'data': [], 'msg': err};

View File

@ -9,7 +9,6 @@ import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/pages/home/index.dart'; import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/main/index.dart'; import 'package:pilipala/pages/main/index.dart';
import 'package:pilipala/pages/rcmd/view.dart';
import 'controller.dart'; import 'controller.dart';
import 'widgets/bangumu_card_v.dart'; import 'widgets/bangumu_card_v.dart';
@ -199,7 +198,10 @@ class _BangumiPageState extends State<BangumiPage>
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => {}, fn: () {
_futureBuilderFuture =
_bangumidController.queryBangumiListFeed();
},
); );
} }
} else { } else {
@ -208,7 +210,6 @@ class _BangumiPageState extends State<BangumiPage>
}, },
), ),
), ),
const LoadingMore()
], ],
), ),
); );

View File

@ -192,22 +192,6 @@ class _DynamicsPageState extends State<DynamicsPage>
) )
], ],
), ),
// Obx(
// () => Visibility(
// visible: _dynamicsController.userLogin.value,
// child: Positioned(
// right: 4,
// top: 0,
// bottom: 0,
// child: IconButton(
// padding: EdgeInsets.zero,
// onPressed: () =>
// {feedBack(), _dynamicsController.resetSearch()},
// icon: const Icon(Icons.history, size: 21),
// ),
// ),
// ),
// ),
], ],
), ),
), ),
@ -229,7 +213,8 @@ class _DynamicsPageState extends State<DynamicsPage>
return Obx(() => UpPanel(_dynamicsController.upData.value)); return Obx(() => UpPanel(_dynamicsController.upData.value));
} else { } else {
return const SliverToBoxAdapter( return const SliverToBoxAdapter(
child: SizedBox(height: 80)); child: SizedBox(height: 80),
);
} }
} else { } else {
return const SliverToBoxAdapter( return const SliverToBoxAdapter(
@ -240,15 +225,6 @@ class _DynamicsPageState extends State<DynamicsPage>
} }
}, },
), ),
SliverToBoxAdapter(
child: Container(
height: 6,
color: Theme.of(context)
.colorScheme
.onInverseSurface
.withOpacity(0.5),
),
),
FutureBuilder( FutureBuilder(
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (context, snapshot) { builder: (context, snapshot) {

View File

@ -36,8 +36,7 @@ class _UpPanelState extends State<UpPanel> {
} }
upList.insert( upList.insert(
0, 0,
UpItem( UpItem(face: '', uname: '全部动态', mid: -1),
face: 'https://files.catbox.moe/8uc48f.png', uname: '全部动态', mid: -1),
); );
userInfo = userInfoCache.get('userInfoCache'); userInfo = userInfoCache.get('userInfoCache');
upList.insert( upList.insert(
@ -56,7 +55,7 @@ class _UpPanelState extends State<UpPanel> {
floating: true, floating: true,
pinned: false, pinned: false,
delegate: _SliverHeaderDelegate( delegate: _SliverHeaderDelegate(
height: 124, height: 126,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -121,6 +120,13 @@ class _UpPanelState extends State<UpPanel> {
], ],
), ),
), ),
Container(
height: 6,
color: Theme.of(context)
.colorScheme
.onInverseSurface
.withOpacity(0.5),
),
], ],
)), )),
); );
@ -171,6 +177,9 @@ class _UpPanelState extends State<UpPanel> {
}, },
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
if (data.mid == -1) {
return;
}
String heroTag = Utils.makeHeroTag(data.mid); String heroTag = Utils.makeHeroTag(data.mid);
Get.toNamed('/member?mid=${data.mid}', Get.toNamed('/member?mid=${data.mid}',
arguments: {'face': data.face, 'heroTag': heroTag}); arguments: {'face': data.face, 'heroTag': heroTag});
@ -198,11 +207,18 @@ class _UpPanelState extends State<UpPanel> {
backgroundColor: data.type == 'live' backgroundColor: data.type == 'live'
? Theme.of(context).colorScheme.secondaryContainer ? Theme.of(context).colorScheme.secondaryContainer
: Theme.of(context).colorScheme.primary, : Theme.of(context).colorScheme.primary,
child: NetworkImgLayer( child: data.face != ''
width: 49, ? NetworkImgLayer(
height: 49, width: 50,
height: 50,
src: data.face, src: data.face,
type: 'avatar', type: 'avatar',
)
: const CircleAvatar(
radius: 25,
backgroundImage: AssetImage(
'assets/images/noface.jpeg',
),
), ),
), ),
Padding( Padding(
@ -271,13 +287,11 @@ class UpPanelSkeleton extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Container( Container(
width: 49, width: 50,
height: 49, height: 50,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.onInverseSurface, color: Theme.of(context).colorScheme.onInverseSurface,
borderRadius: const BorderRadius.all( borderRadius: BorderRadius.circular(50),
Radius.circular(24),
),
), ),
), ),
Container( Container(

View File

@ -89,8 +89,7 @@ class _HotPageState extends State<HotPage> with AutomaticKeepAliveClientMixin {
if (data['status']) { if (data['status']) {
return Obx( return Obx(
() => SliverList( () => SliverList(
delegate: delegate: SliverChildBuilderDelegate((context, index) {
SliverChildBuilderDelegate((context, index) {
return VideoCardH( return VideoCardH(
videoItem: _hotController.videoList[index], videoItem: _hotController.videoList[index],
showPubdate: true, showPubdate: true,
@ -110,7 +109,12 @@ class _HotPageState extends State<HotPage> with AutomaticKeepAliveClientMixin {
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), fn: () {
setState(() {
_futureBuilderFuture =
_hotController.queryHotFeed('init');
});
},
); );
} }
} else { } else {

View File

@ -10,8 +10,7 @@ class LiveController extends GetxController {
int count = 12; int count = 12;
int _currentPage = 1; int _currentPage = 1;
RxInt crossAxisCount = 2.obs; RxInt crossAxisCount = 2.obs;
RxList<LiveItemModel> liveList = [LiveItemModel()].obs; RxList<LiveItemModel> liveList = <LiveItemModel>[].obs;
bool isLoadingMore = false;
bool flag = false; bool flag = false;
OverlayEntry? popupDialog; OverlayEntry? popupDialog;
Box setting = GStrorage.setting; Box setting = GStrorage.setting;
@ -39,7 +38,6 @@ class LiveController extends GetxController {
} }
_currentPage += 1; _currentPage += 1;
} }
isLoadingMore = false;
return res; return res;
} }

View File

@ -11,7 +11,6 @@ import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/overlay_pop.dart'; import 'package:pilipala/common/widgets/overlay_pop.dart';
import 'package:pilipala/pages/home/index.dart'; import 'package:pilipala/pages/home/index.dart';
import 'package:pilipala/pages/main/index.dart'; import 'package:pilipala/pages/main/index.dart';
import 'package:pilipala/pages/rcmd/index.dart';
import 'controller.dart'; import 'controller.dart';
import 'widgets/live_item.dart'; import 'widgets/live_item.dart';
@ -45,8 +44,8 @@ class _LivePageState extends State<LivePage>
() { () {
if (scrollController.position.pixels >= if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200) { scrollController.position.maxScrollExtent - 200) {
EasyThrottle.throttle('liveList', const Duration(seconds: 1), () { EasyThrottle.throttle('liveList', const Duration(milliseconds: 200),
_liveController.isLoadingMore = true; () {
_liveController.onLoad(); _liveController.onLoad();
}); });
} }
@ -108,24 +107,20 @@ class _LivePageState extends State<LivePage>
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => {}, fn: () {
setState(() {
_futureBuilderFuture =
_liveController.queryLiveList('init');
});
},
); );
} }
} else { } else {
// 缓存数据
if (_liveController.liveList.length > 1) {
return contentGrid(
_liveController, _liveController.liveList);
}
// 骨架屏
else {
return contentGrid(_liveController, []); return contentGrid(_liveController, []);
} }
}
}, },
), ),
), ),
LoadingMore(ctr: _liveController)
], ],
), ),
), ),

View File

@ -44,7 +44,7 @@ class _RcmdPageState extends State<RcmdPage>
if (scrollController.position.pixels >= if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 200) { scrollController.position.maxScrollExtent - 200) {
EasyThrottle.throttle( EasyThrottle.throttle(
'my-throttler', const Duration(milliseconds: 500), () { 'my-throttler', const Duration(milliseconds: 200), () {
_rcmdController.isLoadingMore = true; _rcmdController.isLoadingMore = true;
_rcmdController.onLoad(); _rcmdController.onLoad();
}); });
@ -113,6 +113,7 @@ class _RcmdPageState extends State<RcmdPage>
errMsg: data['msg'], errMsg: data['msg'],
fn: () { fn: () {
setState(() { setState(() {
_rcmdController.isLoadingMore = true;
_futureBuilderFuture = _futureBuilderFuture =
_rcmdController.queryRcmdFeed('init'); _rcmdController.queryRcmdFeed('init');
}); });
@ -125,7 +126,6 @@ class _RcmdPageState extends State<RcmdPage>
}, },
), ),
), ),
LoadingMore(ctr: _rcmdController),
], ],
), ),
), ),
@ -188,33 +188,3 @@ class _RcmdPageState extends State<RcmdPage>
); );
} }
} }
class LoadingMore extends StatelessWidget {
final dynamic ctr;
const LoadingMore({super.key, this.ctr});
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: Container(
height: MediaQuery.of(context).padding.bottom + 80,
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
child: GestureDetector(
onTap: () {
if (ctr != null) {
ctr!.isLoadingMore = true;
ctr!.onLoad();
}
},
child: Center(
child: Text(
'点击加载更多 👇',
style: TextStyle(
color: Theme.of(context).colorScheme.outline, fontSize: 13),
),
),
),
),
);
}
}

View File

@ -187,9 +187,13 @@ class _SearchPageState extends State<SearchPage> with RouteAware {
), ),
); );
} else { } else {
return HttpError( return CustomScrollView(
slivers: [
HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), fn: () => setState(() {}),
)
],
); );
} }
} else { } else {

View File

@ -105,7 +105,11 @@ class _SearchPanelState extends State<SearchPanel>
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), fn: () {
setState(() {
_searchPanelController.onSearch();
});
},
), ),
], ],
); );
@ -116,7 +120,11 @@ class _SearchPanelState extends State<SearchPanel>
slivers: [ slivers: [
HttpError( HttpError(
errMsg: '没有相关数据', errMsg: '没有相关数据',
fn: () => setState(() {}), fn: () {
setState(() {
_searchPanelController.onSearch();
});
},
), ),
], ],
); );

View File

@ -35,7 +35,7 @@ class SearchVideoPanel extends StatelessWidget {
padding: index == 0 padding: index == 0
? const EdgeInsets.only(top: 2) ? const EdgeInsets.only(top: 2)
: EdgeInsets.zero, : EdgeInsets.zero,
child: VideoCardH(videoItem: i), child: VideoCardH(videoItem: i, showPubdate: true),
); );
}, },
), ),
@ -70,7 +70,7 @@ class SearchVideoPanel extends StatelessWidget {
controller.selectedType.value = i['type']; controller.selectedType.value = i['type'];
ctr!.order.value = ctr!.order.value =
i['type'].toString().split('.').last; i['type'].toString().split('.').last;
SmartDialog.showLoading(msg: 'loooad'); SmartDialog.showLoading(msg: 'loading');
await ctr!.onRefresh(); await ctr!.onRefresh();
SmartDialog.dismiss(); SmartDialog.dismiss();
}, },
@ -202,7 +202,7 @@ class VideoPanelController extends GetxController {
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword!}');
ctr.duration.value = i['value']; ctr.duration.value = i['value'];
SmartDialog.showLoading(msg: 'loooad'); SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh(); await ctr.onRefresh();
SmartDialog.dismiss(); SmartDialog.dismiss();
}, },

View File

@ -18,6 +18,7 @@ import 'package:pilipala/utils/id_utils.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import '../related/index.dart';
import 'widgets/group_panel.dart'; import 'widgets/group_panel.dart';
class VideoIntroController extends GetxController { class VideoIntroController extends GetxController {
@ -478,11 +479,15 @@ class VideoIntroController extends GetxController {
// 重新获取视频资源 // 重新获取视频资源
final VideoDetailController videoDetailCtr = final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: heroTag); Get.find<VideoDetailController>(tag: heroTag);
final ReleatedController releatedCtr =
Get.find<ReleatedController>(tag: heroTag);
videoDetailCtr.bvid = bvid; videoDetailCtr.bvid = bvid;
videoDetailCtr.oid.value = aid; videoDetailCtr.oid.value = aid;
videoDetailCtr.cid.value = cid; videoDetailCtr.cid.value = cid;
videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.danmakuCid.value = cid;
videoDetailCtr.queryVideoUrl(); videoDetailCtr.queryVideoUrl();
releatedCtr.bvid = bvid;
releatedCtr.queryRelatedVideo();
// 重新请求评论 // 重新请求评论
try { try {
/// 未渲染回复组件时可能异常 /// 未渲染回复组件时可能异常

View File

@ -1,14 +1,22 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import '../../../../models/model_hot_video_item.dart';
class ReleatedController extends GetxController { class ReleatedController extends GetxController {
// 视频aid // 视频aid
String bvid = Get.parameters['bvid'] ?? ""; String bvid = Get.parameters['bvid'] ?? "";
// 推荐视频列表 // 推荐视频列表
List relatedVideoList = []; RxList relatedVideoList = <HotVideoItemModel>[].obs;
OverlayEntry? popupDialog; OverlayEntry? popupDialog;
Future<dynamic> queryRelatedVideo() => VideoHttp.relatedVideoList(bvid: bvid); Future<dynamic> queryRelatedVideo() async {
return VideoHttp.relatedVideoList(bvid: bvid).then((value) {
if (value['status']) {
relatedVideoList.value = value['data'];
}
return value;
});
}
} }

View File

@ -7,35 +7,58 @@ import 'package:pilipala/common/widgets/overlay_pop.dart';
import 'package:pilipala/common/widgets/video_card_h.dart'; import 'package:pilipala/common/widgets/video_card_h.dart';
import './controller.dart'; import './controller.dart';
class RelatedVideoPanel extends StatelessWidget { class RelatedVideoPanel extends StatefulWidget {
final ReleatedController _releatedController = const RelatedVideoPanel({super.key});
@override
State<RelatedVideoPanel> createState() => _RelatedVideoPanelState();
}
class _RelatedVideoPanelState extends State<RelatedVideoPanel>
with AutomaticKeepAliveClientMixin {
late ReleatedController _releatedController;
late Future _futureBuilder;
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
_releatedController =
Get.put(ReleatedController(), tag: Get.arguments?['heroTag']); Get.put(ReleatedController(), tag: Get.arguments?['heroTag']);
RelatedVideoPanel({super.key}); _futureBuilder = _releatedController.queryRelatedVideo();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context);
return FutureBuilder( return FutureBuilder(
future: _releatedController.queryRelatedVideo(), future: _futureBuilder,
builder: (BuildContext context, AsyncSnapshot snapshot) { builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) { if (snapshot.data == null) {
return const SliverToBoxAdapter(child: SizedBox()); return const SliverToBoxAdapter(child: SizedBox());
} }
if (snapshot.data!['status']) { if (snapshot.data!['status'] && snapshot.data != null) {
RxList relatedVideoList = _releatedController.relatedVideoList;
// 请求成功 // 请求成功
return SliverList( return Obx(
() => SliverList(
delegate: SliverChildBuilderDelegate((context, index) { delegate: SliverChildBuilderDelegate((context, index) {
if (index == snapshot.data['data'].length) { if (index == relatedVideoList.length) {
return SizedBox(height: MediaQuery.of(context).padding.bottom); return SizedBox(
height: MediaQuery.of(context).padding.bottom);
} else { } else {
return Material( return Material(
child: VideoCardH( child: VideoCardH(
videoItem: snapshot.data['data'][index], videoItem: relatedVideoList[index],
showPubdate: true, showPubdate: true,
longPress: () { longPress: () {
try { try {
_releatedController.popupDialog = _releatedController.popupDialog =
_createPopupDialog(snapshot.data['data'][index]); _createPopupDialog(_releatedController
.relatedVideoList[index]);
Overlay.of(context) Overlay.of(context)
.insert(_releatedController.popupDialog!); .insert(_releatedController.popupDialog!);
} catch (err) { } catch (err) {
@ -48,7 +71,9 @@ class RelatedVideoPanel extends StatelessWidget {
), ),
); );
} }
}, childCount: snapshot.data['data'].length + 1)); }, childCount: relatedVideoList.length + 1),
),
);
} else { } else {
// 请求错误 // 请求错误
return HttpError(errMsg: '出错了', fn: () {}); return HttpError(errMsg: '出错了', fn: () {});

View File

@ -28,7 +28,7 @@ class Utils {
} }
static String numFormat(dynamic number) { static String numFormat(dynamic number) {
if (number == null){ if (number == null) {
return '0'; return '0';
} }
if (number is String) { if (number is String) {
@ -63,6 +63,26 @@ class Utils {
} }
} }
// 完全相对时间显示
static String formatTimestampToRelativeTime(timeStamp) {
var difference = DateTime.now()
.difference(DateTime.fromMillisecondsSinceEpoch(timeStamp * 1000));
if (difference.inDays > 365) {
return '${difference.inDays ~/ 365}年前';
} else if (difference.inDays > 30) {
return '${difference.inDays ~/ 30}个月前';
} else if (difference.inDays > 0) {
return '${difference.inDays}天前';
} else if (difference.inHours > 0) {
return '${difference.inHours}小时前';
} else if (difference.inMinutes > 0) {
return '${difference.inMinutes}分钟前';
} else {
return '刚刚';
}
}
// 时间显示刚刚x分钟前 // 时间显示刚刚x分钟前
static String dateFormat(timeStamp, {formatType = 'list'}) { static String dateFormat(timeStamp, {formatType = 'list'}) {
// 当前时间 // 当前时间