diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index e726d26e..d68cc973 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/dialog.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/models/user/fav_folder.dart'; @@ -71,249 +72,274 @@ class _FavDetailPageState extends State { ) : const SizedBox.shrink(), ), - body: CustomScrollView( - physics: const AlwaysScrollableScrollPhysics(), - controller: _favDetailController.scrollController, - slivers: [ - SliverAppBar( - leading: _favDetailController.enableMultiSelect.value - ? IconButton( - tooltip: '取消', - onPressed: _favDetailController.handleSelect, - icon: const Icon(Icons.close_outlined), - ) - : null, - expandedHeight: 220 - MediaQuery.of(context).padding.top, - pinned: true, - title: _favDetailController.enableMultiSelect.value - ? Text( - '已选: ${_favDetailController.checkedCount.value}', - ) - : Obx( - () => AnimatedOpacity( - opacity: _favDetailController.titleCtr.value ? 1 : 0, - curve: Curves.easeOut, - duration: const Duration(milliseconds: 500), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _favDetailController.item.value.title ?? '', - style: Theme.of(context).textTheme.titleMedium, + body: refreshIndicator( + onRefresh: () async { + await _favDetailController.onRefresh(); + }, + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: _favDetailController.scrollController, + slivers: [ + SliverAppBar( + leading: _favDetailController.enableMultiSelect.value + ? IconButton( + tooltip: '取消', + onPressed: _favDetailController.handleSelect, + icon: const Icon(Icons.close_outlined), + ) + : null, + expandedHeight: 220 - MediaQuery.of(context).padding.top, + pinned: true, + title: _favDetailController.enableMultiSelect.value + ? Text( + '已选: ${_favDetailController.checkedCount.value}', + ) + : Obx( + () => AnimatedOpacity( + opacity: + _favDetailController.titleCtr.value ? 1 : 0, + curve: Curves.easeOut, + duration: const Duration(milliseconds: 500), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _favDetailController.item.value.title ?? '', + style: + Theme.of(context).textTheme.titleMedium, + ), + Text( + '共${_favDetailController.item.value.mediaCount}条视频', + style: + Theme.of(context).textTheme.labelMedium, + ) + ], + ), + ), + ), + actions: _favDetailController.enableMultiSelect.value + ? [ + TextButton( + style: TextButton.styleFrom( + visualDensity: + VisualDensity(horizontal: -2, vertical: -2), + ), + onPressed: () => + _favDetailController.handleSelect(true), + child: const Text('全选'), + ), + TextButton( + style: TextButton.styleFrom( + visualDensity: + VisualDensity(horizontal: -2, vertical: -2), + ), + onPressed: () => Utils.onCopyOrMove( + context: context, + isCopy: true, + ctr: _favDetailController, + mediaId: _favDetailController.mediaId, + ), + child: Text( + '复制', + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onSurfaceVariant, ), - Text( - '共${_favDetailController.item.value.mediaCount}条视频', - style: Theme.of(context).textTheme.labelMedium, - ) - ], - ), - ), - ), - actions: _favDetailController.enableMultiSelect.value - ? [ - TextButton( - style: TextButton.styleFrom( - visualDensity: - VisualDensity(horizontal: -2, vertical: -2), - ), - onPressed: () => - _favDetailController.handleSelect(true), - child: const Text('全选'), - ), - TextButton( - style: TextButton.styleFrom( - visualDensity: - VisualDensity(horizontal: -2, vertical: -2), - ), - onPressed: () => Utils.onCopyOrMove( - context: context, - isCopy: true, - ctr: _favDetailController, - mediaId: _favDetailController.mediaId, - ), - child: Text( - '复制', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .onSurfaceVariant, ), ), - ), - TextButton( - style: TextButton.styleFrom( - visualDensity: - VisualDensity(horizontal: -2, vertical: -2), - ), - onPressed: () => Utils.onCopyOrMove( - context: context, - isCopy: false, - ctr: _favDetailController, - mediaId: _favDetailController.mediaId, - ), - child: Text( - '移动', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .onSurfaceVariant, + TextButton( + style: TextButton.styleFrom( + visualDensity: + VisualDensity(horizontal: -2, vertical: -2), + ), + onPressed: () => Utils.onCopyOrMove( + context: context, + isCopy: false, + ctr: _favDetailController, + mediaId: _favDetailController.mediaId, + ), + child: Text( + '移动', + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onSurfaceVariant, + ), ), ), - ), - TextButton( - style: TextButton.styleFrom( - visualDensity: - VisualDensity(horizontal: -2, vertical: -2), + TextButton( + style: TextButton.styleFrom( + visualDensity: + VisualDensity(horizontal: -2, vertical: -2), + ), + onPressed: () => + _favDetailController.onDelChecked(context), + child: Text( + '删除', + style: TextStyle( + color: Theme.of(context).colorScheme.error), + ), ), - onPressed: () => - _favDetailController.onDelChecked(context), - child: Text( - '删除', - style: TextStyle( - color: Theme.of(context).colorScheme.error), + const SizedBox(width: 6), + ] + : [ + IconButton( + tooltip: '搜索', + onPressed: () => + Get.toNamed('/favSearch', arguments: { + 'type': 0, + 'mediaId': int.parse(mediaId), + 'searchType': SearchType.fav, + }), + icon: const Icon(Icons.search_outlined), ), - ), - const SizedBox(width: 6), - ] - : [ - IconButton( - tooltip: '搜索', - onPressed: () => - Get.toNamed('/favSearch', arguments: { - 'type': 0, - 'mediaId': int.parse(mediaId), - 'searchType': SearchType.fav, - }), - icon: const Icon(Icons.search_outlined), - ), - // IconButton( - // onPressed: () {}, - // icon: const Icon(Icons.more_vert), - // ), - Obx( - () => _favDetailController.isOwner.value - ? PopupMenuButton( - icon: const Icon(Icons.more_vert), - itemBuilder: (context) => [ - PopupMenuItem( - onTap: () { - Get.toNamed( - '/createFav', - parameters: {'mediaId': mediaId}, - )?.then((res) { - if (res is FavFolderItemData) { - _favDetailController.item.value = - res; - } - }); - }, - child: Text('编辑信息'), - ), - PopupMenuItem( - onTap: () { - UserHttp.cleanFav(mediaId: mediaId) - .then((data) { - if (data['status']) { - SmartDialog.showToast('清除成功'); - Future.delayed( - const Duration( - milliseconds: 200), () { - _favDetailController.onReload(); - }); - } else { - SmartDialog.showToast(data['msg']); - } - }); - }, - child: Text('清除失效内容'), - ), - if (!Utils.isDefault( - _favDetailController.item.value.attr ?? - 0)) + // IconButton( + // onPressed: () {}, + // icon: const Icon(Icons.more_vert), + // ), + Obx( + () => _favDetailController.isOwner.value + ? PopupMenuButton( + icon: const Icon(Icons.more_vert), + itemBuilder: (context) => [ PopupMenuItem( onTap: () { - showConfirmDialog( - context: context, - title: '确定删除该收藏夹?', - onConfirm: () { - Get.back(); - UserHttp.deleteFolder( - mediaIds: [mediaId]) - .then((data) { - if (data['status']) { - SmartDialog.showToast('删除成功'); - Get.back(result: true); - } else { - SmartDialog.showToast( - data['msg']); - } - }); - }, - ); + Get.toNamed( + '/createFav', + parameters: {'mediaId': mediaId}, + )?.then((res) { + if (res is FavFolderItemData) { + _favDetailController.item.value = + res; + } + }); }, - child: Text( - '删除', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .error, + child: Text('编辑信息'), + ), + PopupMenuItem( + onTap: () { + UserHttp.cleanFav(mediaId: mediaId) + .then((data) { + if (data['status']) { + SmartDialog.showToast('清除成功'); + Future.delayed( + const Duration( + milliseconds: 200), () { + _favDetailController.onReload(); + }); + } else { + SmartDialog.showToast( + data['msg']); + } + }); + }, + child: Text('清除失效内容'), + ), + if (!Utils.isDefault(_favDetailController + .item.value.attr ?? + 0)) + PopupMenuItem( + onTap: () { + showConfirmDialog( + context: context, + title: '确定删除该收藏夹?', + onConfirm: () { + Get.back(); + UserHttp.deleteFolder( + mediaIds: [mediaId]) + .then((data) { + if (data['status']) { + SmartDialog.showToast( + '删除成功'); + Get.back(result: true); + } else { + SmartDialog.showToast( + data['msg']); + } + }); + }, + ); + }, + child: Text( + '删除', + style: TextStyle( + color: Theme.of(context) + .colorScheme + .error, + ), ), ), - ), - ], - ) - : const SizedBox.shrink(), - ), - const SizedBox(width: 6), - ], - flexibleSpace: FlexibleSpaceBar( - background: Container( - padding: EdgeInsets.only( - top: kTextTabBarHeight + - MediaQuery.of(context).padding.top + - 10, - left: 14, - right: 20, - ), - child: SizedBox( - height: 110, - child: Obx( - () => Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Hero( - tag: _favDetailController.heroTag, - child: NetworkImgLayer( - width: 180, - height: 110, - src: _favDetailController.item.value.cover, + ], + ) + : const SizedBox.shrink(), + ), + const SizedBox(width: 6), + ], + flexibleSpace: FlexibleSpaceBar( + background: Container( + padding: EdgeInsets.only( + top: kTextTabBarHeight + + MediaQuery.of(context).padding.top + + 10, + left: 14, + right: 20, + ), + child: SizedBox( + height: 110, + child: Obx( + () => Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Hero( + tag: _favDetailController.heroTag, + child: NetworkImgLayer( + width: 180, + height: 110, + src: _favDetailController.item.value.cover, + ), ), - ), - const SizedBox(width: 14), - Expanded( - child: SizedBox( - height: 110, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 4), - Text( - _favDetailController.item.value.title ?? - '', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .titleMedium! - .fontSize, - fontWeight: FontWeight.bold), - ), - if (_favDetailController - .item.value.intro?.isNotEmpty == - true) + const SizedBox(width: 14), + Expanded( + child: SizedBox( + height: 110, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), Text( - _favDetailController.item.value.intro ?? + _favDetailController.item.value.title ?? + '', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .titleMedium! + .fontSize, + fontWeight: FontWeight.bold), + ), + if (_favDetailController + .item.value.intro?.isNotEmpty == + true) + Text( + _favDetailController + .item.value.intro ?? + '', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .labelSmall! + .fontSize, + color: Theme.of(context) + .colorScheme + .outline), + ), + const SizedBox(height: 4), + Text( + _favDetailController + .item.value.upper?.name ?? '', style: TextStyle( fontSize: Theme.of(context) @@ -324,47 +350,35 @@ class _FavDetailPageState extends State { .colorScheme .outline), ), - const SizedBox(height: 4), - Text( - _favDetailController - .item.value.upper?.name ?? - '', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - color: Theme.of(context) - .colorScheme - .outline), - ), - const Spacer(), - if (_favDetailController.item.value.attr != - null) - Text( - '共${_favDetailController.item.value.mediaCount}条视频 · ${Utils.isPublicText(_favDetailController.item.value.attr ?? 0)}', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - color: Theme.of(context) - .colorScheme - .outline), - ), - ], + const Spacer(), + if (_favDetailController + .item.value.attr != + null) + Text( + '共${_favDetailController.item.value.mediaCount}条视频 · ${Utils.isPublicText(_favDetailController.item.value.attr ?? 0)}', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .labelSmall! + .fontSize, + color: Theme.of(context) + .colorScheme + .outline), + ), + ], + ), ), ), - ), - ], + ], + ), ), ), ), ), ), - ), - Obx(() => _buildBody(_favDetailController.loadingState.value)), - ], + Obx(() => _buildBody(_favDetailController.loadingState.value)), + ], + ), ), ), ), diff --git a/lib/pages/later/view.dart b/lib/pages/later/view.dart index 49325cb5..40b7220c 100644 --- a/lib/pages/later/view.dart +++ b/lib/pages/later/view.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/icon_button.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/history/view.dart' show AppBarWidget; import 'package:PiliPlus/utils/extension.dart'; @@ -146,19 +147,24 @@ class _LaterPageState extends State { ) : const SizedBox(), ), - body: CustomScrollView( - physics: const AlwaysScrollableScrollPhysics(), - controller: _laterController.scrollController, - slivers: [ - SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom + 85, + body: refreshIndicator( + onRefresh: () async { + await _laterController.onRefresh(); + }, + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: _laterController.scrollController, + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom + 85, + ), + sliver: Obx( + () => _buildBody(_laterController.loadingState.value), + ), ), - sliver: Obx( - () => _buildBody(_laterController.loadingState.value), - ), - ), - ], + ], + ), ), ), ), diff --git a/lib/pages/msg_feed_top/at_me/view.dart b/lib/pages/msg_feed_top/at_me/view.dart index d57b2ea3..585d9fd7 100644 --- a/lib/pages/msg_feed_top/at_me/view.dart +++ b/lib/pages/msg_feed_top/at_me/view.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; @@ -52,92 +53,85 @@ class _AtMePageState extends State { onRefresh: () async { await _atMeController.onRefresh(); }, - child: SingleChildScrollView( - controller: _scrollController, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Obx( - () { - if (_atMeController.msgFeedAtMeList.isEmpty) { - return const Center( - child: CircularProgressIndicator(), - ); - } - return ListView.separated( - itemCount: _atMeController.msgFeedAtMeList.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, int i) { - return ListTile( - onTap: () { - String? nativeUri = - _atMeController.msgFeedAtMeList[i].item?.nativeUri; - if (nativeUri != null) { - PiliScheme.routePushFromUrl(nativeUri); - } - // SmartDialog.showToast("跳转至:$nativeUri(暂未实现)"); - }, - leading: NetworkImgLayer( - width: 45, - height: 45, - type: 'avatar', - src: _atMeController.msgFeedAtMeList[i].user?.avatar, - ), - title: Text( - "${_atMeController.msgFeedAtMeList[i].user?.nickname} " - "在${_atMeController.msgFeedAtMeList[i].item?.business}中@了我", + child: Obx( + () { + // TODO: refactor + if (_atMeController.msgFeedAtMeList.isEmpty) { + if (_atMeController.cursor == -1 && + _atMeController.cursorTime == -1) { + return const Center( + child: CircularProgressIndicator(), + ); + } else { + return scrollErrorWidget( + callback: _atMeController.queryMsgFeedAtMe); + } + } + return ListView.separated( + controller: _scrollController, + itemCount: _atMeController.msgFeedAtMeList.length, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, int i) { + return ListTile( + onTap: () { + String? nativeUri = + _atMeController.msgFeedAtMeList[i].item?.nativeUri; + if (nativeUri != null) { + PiliScheme.routePushFromUrl(nativeUri); + } + // SmartDialog.showToast("跳转至:$nativeUri(暂未实现)"); + }, + leading: NetworkImgLayer( + width: 45, + height: 45, + type: 'avatar', + src: _atMeController.msgFeedAtMeList[i].user?.avatar, + ), + title: Text( + "${_atMeController.msgFeedAtMeList[i].user?.nickname} " + "在${_atMeController.msgFeedAtMeList[i].item?.business}中@了我", + style: Theme.of(context).textTheme.titleMedium!.copyWith( + color: Theme.of(context).colorScheme.primary, + )), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + Text( + _atMeController + .msgFeedAtMeList[i].item?.sourceContent ?? + "", + maxLines: 3, + overflow: TextOverflow.ellipsis, style: Theme.of(context) .textTheme - .titleMedium! + .bodyMedium! .copyWith( - color: Theme.of(context).colorScheme.primary, - )), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 4), - Text( - _atMeController - .msgFeedAtMeList[i].item?.sourceContent ?? - "", - maxLines: 3, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .outline)) - ], - ), - trailing: _atMeController - .msgFeedAtMeList[i].item?.image != - null && - _atMeController.msgFeedAtMeList[i].item?.image != - "" - ? NetworkImgLayer( - width: 45, - height: 45, - type: 'cover', - src: _atMeController - .msgFeedAtMeList[i].item?.image, - ) - : null, - ); - }, - separatorBuilder: (BuildContext context, int index) { - return Divider( - indent: 72, - endIndent: 20, - height: 6, - color: Colors.grey.withOpacity(0.1), - ); - }, + color: Theme.of(context).colorScheme.outline)) + ], + ), + trailing: _atMeController.msgFeedAtMeList[i].item?.image != + null && + _atMeController.msgFeedAtMeList[i].item?.image != "" + ? NetworkImgLayer( + width: 45, + height: 45, + type: 'cover', + src: _atMeController.msgFeedAtMeList[i].item?.image, + ) + : null, + ); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider( + indent: 72, + endIndent: 20, + height: 6, + color: Colors.grey.withOpacity(0.1), ); }, ); - }), + }, ), ), ); diff --git a/lib/pages/msg_feed_top/like_me/view.dart b/lib/pages/msg_feed_top/like_me/view.dart index 5e0d5501..8b535abb 100644 --- a/lib/pages/msg_feed_top/like_me/view.dart +++ b/lib/pages/msg_feed_top/like_me/view.dart @@ -53,6 +53,7 @@ class _LikeMePageState extends State { onRefresh: () async { await _likeMeController.onRefresh(); }, + // TODO: refactor child: SingleChildScrollView( controller: _scrollController, child: LayoutBuilder( diff --git a/lib/pages/msg_feed_top/reply_me/view.dart b/lib/pages/msg_feed_top/reply_me/view.dart index 9733efb8..89790027 100644 --- a/lib/pages/msg_feed_top/reply_me/view.dart +++ b/lib/pages/msg_feed_top/reply_me/view.dart @@ -51,106 +51,100 @@ class _ReplyMePageState extends State { onRefresh: () async { await _replyMeController.onRefresh(); }, - child: SingleChildScrollView( - controller: _scrollController, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Obx( - () { - if (_replyMeController.msgFeedReplyMeList.isEmpty) { - return const Center( - child: CircularProgressIndicator(), - ); - } - return ListView.separated( - itemCount: _replyMeController.msgFeedReplyMeList.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, int i) { - return ListTile( - onTap: () { - String? nativeUri = _replyMeController - .msgFeedReplyMeList[i].item?.nativeUri; - if (nativeUri != null) { - PiliScheme.routePushFromUrl(nativeUri); - } - // SmartDialog.showToast("跳转至:$nativeUri(暂未实现)"); - }, - leading: NetworkImgLayer( - width: 45, - height: 45, - type: 'avatar', - src: _replyMeController - .msgFeedReplyMeList[i].user?.avatar, - ), - title: Text( - "${_replyMeController.msgFeedReplyMeList[i].user?.nickname} " - "回复了我的${_replyMeController.msgFeedReplyMeList[i].item?.business}", - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.primary), - ), - subtitle: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 4), - Text( - _replyMeController.msgFeedReplyMeList[i].item - ?.sourceContent ?? - "", - style: Theme.of(context).textTheme.bodyMedium), - const SizedBox(height: 4), - if (_replyMeController.msgFeedReplyMeList[i].item - ?.targetReplyContent != - null && - _replyMeController.msgFeedReplyMeList[i].item - ?.targetReplyContent != - "") - Text( - "| ${_replyMeController.msgFeedReplyMeList[i].item?.targetReplyContent}", - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .outline, - height: 1.5)), - if (_replyMeController.msgFeedReplyMeList[i].item - ?.rootReplyContent != - null && - _replyMeController.msgFeedReplyMeList[i].item - ?.rootReplyContent != - "") - Text( - " | ${_replyMeController.msgFeedReplyMeList[i].item?.rootReplyContent}", - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .labelMedium! - .copyWith( - color: Theme.of(context) - .colorScheme - .outline, - height: 1.5)), - ]), - ); - }, - separatorBuilder: (BuildContext context, int index) { - return Divider( - indent: 72, - endIndent: 20, - height: 6, - color: Colors.grey.withOpacity(0.1), - ); + // TODO: refactor + child: Obx( + () { + if (_replyMeController.msgFeedReplyMeList.isEmpty) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return ListView.separated( + controller: _scrollController, + itemCount: _replyMeController.msgFeedReplyMeList.length, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, int i) { + return ListTile( + onTap: () { + String? nativeUri = _replyMeController + .msgFeedReplyMeList[i].item?.nativeUri; + if (nativeUri != null) { + PiliScheme.routePushFromUrl(nativeUri); + } + // SmartDialog.showToast("跳转至:$nativeUri(暂未实现)"); }, + leading: NetworkImgLayer( + width: 45, + height: 45, + type: 'avatar', + src: _replyMeController.msgFeedReplyMeList[i].user?.avatar, + ), + title: Text( + "${_replyMeController.msgFeedReplyMeList[i].user?.nickname} " + "回复了我的${_replyMeController.msgFeedReplyMeList[i].item?.business}", + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Theme.of(context).colorScheme.primary), + ), + subtitle: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + Text( + _replyMeController.msgFeedReplyMeList[i].item + ?.sourceContent ?? + "", + style: Theme.of(context).textTheme.bodyMedium), + const SizedBox(height: 4), + if (_replyMeController.msgFeedReplyMeList[i].item + ?.targetReplyContent != + null && + _replyMeController.msgFeedReplyMeList[i].item + ?.targetReplyContent != + "") + Text( + "| ${_replyMeController.msgFeedReplyMeList[i].item?.targetReplyContent}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .labelMedium! + .copyWith( + color: + Theme.of(context).colorScheme.outline, + height: 1.5)), + if (_replyMeController.msgFeedReplyMeList[i].item + ?.rootReplyContent != + null && + _replyMeController.msgFeedReplyMeList[i].item + ?.rootReplyContent != + "") + Text( + " | ${_replyMeController.msgFeedReplyMeList[i].item?.rootReplyContent}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .labelMedium! + .copyWith( + color: + Theme.of(context).colorScheme.outline, + height: 1.5)), + ]), + ); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider( + indent: 72, + endIndent: 20, + height: 6, + color: Colors.grey.withOpacity(0.1), ); }, ); - }), + }, ), ), ); diff --git a/lib/pages/msg_feed_top/sys_msg/view.dart b/lib/pages/msg_feed_top/sys_msg/view.dart index 8036409e..6c506a6d 100644 --- a/lib/pages/msg_feed_top/sys_msg/view.dart +++ b/lib/pages/msg_feed_top/sys_msg/view.dart @@ -57,112 +57,105 @@ class _SysMsgPageState extends State { onRefresh: () async { await _sysMsgController.onRefresh(); }, - child: SingleChildScrollView( - controller: _scrollController, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return Obx( - () { - if (_sysMsgController.msgFeedSysMsgList.isEmpty) { - return const Center( - child: CircularProgressIndicator(), - ); - } - return ListView.separated( - itemCount: _sysMsgController.msgFeedSysMsgList.length, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, int i) { - String? content = - _sysMsgController.msgFeedSysMsgList[i].content; - if (content != null) { - try { - dynamic jsonContent = json.decode(content); - if (jsonContent != null && jsonContent['web'] != null) { - content = jsonContent['web']; - } - } catch (_) {} + // TODO: refactor + child: Obx( + () { + if (_sysMsgController.msgFeedSysMsgList.isEmpty) { + return const Center( + child: CircularProgressIndicator(), + ); + } + return ListView.separated( + controller: _scrollController, + itemCount: _sysMsgController.msgFeedSysMsgList.length, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, int i) { + String? content = + _sysMsgController.msgFeedSysMsgList[i].content; + if (content != null) { + try { + dynamic jsonContent = json.decode(content); + if (jsonContent != null && jsonContent['web'] != null) { + content = jsonContent['web']; } - return ListTile( - onTap: () {}, - onLongPress: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('确定删除该通知?'), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .outline, - ), - ), + } catch (_) {} + } + return ListTile( + onTap: () {}, + onLongPress: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('确定删除该通知?'), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle( + color: + Theme.of(context).colorScheme.outline, ), - TextButton( - onPressed: () { - Get.back(); - _sysMsgController.onRemove(i); - }, - child: const Text('确定'), - ), - ], - )); - }, - title: Text( - "${_sysMsgController.msgFeedSysMsgList[i].title}", - style: Theme.of(context).textTheme.titleMedium, - ), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 4), - Text.rich( - _buildContent(content ?? ''), - style: TextStyle( - fontSize: 14, - color: Theme.of(context) - .colorScheme - .onSurface - .withOpacity(0.85), - ), - ), - const SizedBox(height: 5), - SizedBox( - width: double.infinity, - child: Text( - "${_sysMsgController.msgFeedSysMsgList[i].timeAt}", - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: - Theme.of(context).colorScheme.outline, ), - textAlign: TextAlign.end, - ), - ), - ], + ), + TextButton( + onPressed: () { + Get.back(); + _sysMsgController.onRemove(i); + }, + child: const Text('确定'), + ), + ], + )); + }, + title: Text( + "${_sysMsgController.msgFeedSysMsgList[i].title}", + style: Theme.of(context).textTheme.titleMedium, + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + Text.rich( + _buildContent(content ?? ''), + style: TextStyle( + fontSize: 14, + color: Theme.of(context) + .colorScheme + .onSurface + .withOpacity(0.85), + ), ), - ); - }, - separatorBuilder: (BuildContext context, int index) { - return Divider( - indent: 72, - endIndent: 20, - height: 6, - color: Colors.grey.withOpacity(0.1), - ); - }, + const SizedBox(height: 5), + SizedBox( + width: double.infinity, + child: Text( + "${_sysMsgController.msgFeedSysMsgList[i].timeAt}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: Theme.of(context).colorScheme.outline, + ), + textAlign: TextAlign.end, + ), + ), + ], + ), + ); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider( + indent: 72, + endIndent: 20, + height: 6, + color: Colors.grey.withOpacity(0.1), ); }, ); - }), + }, ), ), ); diff --git a/lib/pages/subscription/view.dart b/lib/pages/subscription/view.dart index 3ee1ea63..7cf3f234 100644 --- a/lib/pages/subscription/view.dart +++ b/lib/pages/subscription/view.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/skeleton/video_card_h.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/subscription/widgets/item.dart'; import 'package:PiliPlus/utils/grid.dart'; @@ -22,15 +23,20 @@ class _SubPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('我的订阅')), - body: CustomScrollView( - slivers: [ - Obx(() => _buildBody(_subController.loadingState.value)), - SliverToBoxAdapter( - child: SizedBox( - height: MediaQuery.of(context).padding.bottom + 80, + body: refreshIndicator( + onRefresh: () async { + await _subController.onRefresh(); + }, + child: CustomScrollView( + slivers: [ + Obx(() => _buildBody(_subController.loadingState.value)), + SliverToBoxAdapter( + child: SizedBox( + height: MediaQuery.of(context).padding.bottom + 80, + ), ), - ), - ], + ], + ), ), ); } diff --git a/lib/pages/video/detail/note/note_list_page.dart b/lib/pages/video/detail/note/note_list_page.dart index 3eb018b1..24368446 100644 --- a/lib/pages/video/detail/note/note_list_page.dart +++ b/lib/pages/video/detail/note/note_list_page.dart @@ -2,6 +2,7 @@ import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/common/widgets/icon_button.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/video/detail/note/note_list_page_ctr.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; @@ -79,7 +80,7 @@ class _NoteListPageState extends State { ], ), Success() => (loadingState.response as List?)?.isNotEmpty == true - ? RefreshIndicator( + ? refreshIndicator( onRefresh: () async { await _controller.onRefresh(); },