From 15e1cb5d4763a3b63b4c44e861b1dd79df7e6c6e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 24 Aug 2024 00:07:08 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E7=A7=81=E4=BF=A1=E5=8F=AF?= =?UTF-8?q?=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../whisper_detail/widget/chat_item.dart | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index 77e38073..94347aff 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -84,7 +84,7 @@ class ChatItem extends StatelessWidget { emojiMap[e['text']] = e['url']; } text.splitMapJoin( - RegExp(r"\[.+?\]"), + RegExp(r"\[[^\[\]]+\]"), onMatch: (Match match) { final String emojiKey = match[0]!; if (emojiMap.containsKey(emojiKey)) { @@ -95,6 +95,17 @@ class ChatItem extends StatelessWidget { src: emojiMap[emojiKey]!, ), )); + } else { + children.add( + TextSpan( + text: emojiKey, + style: TextStyle( + color: textColor(context), + letterSpacing: 0.6, + height: 1.5, + ), + ), + ); } return ''; }, @@ -109,13 +120,13 @@ class ChatItem extends StatelessWidget { return ''; }, ); - return RichText( - text: TextSpan( + return SelectableText.rich( + TextSpan( children: children, ), ); } else { - return Text( + return SelectableText( text, style: TextStyle( letterSpacing: 0.6, @@ -133,7 +144,7 @@ class ChatItem extends StatelessWidget { case MsgType.pic_card: return SystemNotice2(item: item); case MsgType.notify_text: - return Text( + return SelectableText( jsonDecode(content['content']) .map((m) => m['text'] as String) .join("\n"), @@ -530,7 +541,7 @@ class SystemNotice extends StatelessWidget { Divider( color: Theme.of(context).colorScheme.primary.withOpacity(0.05), ), - Text( + SelectableText( content['text'], ) ], From b96f35bae2f2f3e1458a0fdb66e1976fddc02f91 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 24 Aug 2024 00:28:07 +0800 Subject: [PATCH 2/3] =?UTF-8?q?mod:=20=E7=A7=BB=E9=99=A4up=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E5=88=86=E5=89=B2=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/member/view.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index c721d638..7d2e4bed 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -168,7 +168,6 @@ class _MemberPageState extends State const Icon(Icons.arrow_forward_outlined, size: 19), ), ), - const Divider(height: 1, thickness: 0.1), /// 视频 Obx(() => ListTile( @@ -178,7 +177,6 @@ class _MemberPageState extends State trailing: const Icon(Icons.arrow_forward_outlined, size: 19), )), - const Divider(height: 1, thickness: 0.1), /// 他的收藏夹 Obx(() => ListTile( @@ -188,13 +186,11 @@ class _MemberPageState extends State trailing: const Icon(Icons.arrow_forward_outlined, size: 19), )), - const Divider(height: 1, thickness: 0.1), /// 专栏 Obx(() => ListTile( title: Text( '${_memberController.isOwner.value ? '我' : 'Ta'}的专栏'))), - const Divider(height: 1, thickness: 0.1), /// 合集 Obx(() => ListTile( From d85e9446e3d634ad5c1cb3eecec45301a10a73e8 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 26 Aug 2024 00:12:35 +0800 Subject: [PATCH 3/3] opt: fav follow bottomSheet --- lib/pages/follow/widgets/follow_item.dart | 19 +++++-- .../video/detail/introduction/controller.dart | 19 +++++-- lib/pages/video/detail/introduction/view.dart | 49 ++++++++++--------- .../introduction/widgets/fav_panel.dart | 43 +++++++++------- .../introduction/widgets/group_panel.dart | 16 ++++-- pubspec.lock | 16 ++++++ pubspec.yaml | 1 + 7 files changed, 111 insertions(+), 52 deletions(-) diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart index d21a89bc..3d393277 100644 --- a/lib/pages/follow/widgets/follow_item.dart +++ b/lib/pages/follow/widgets/follow_item.dart @@ -1,3 +1,4 @@ +import 'package:bottom_sheet/bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; @@ -47,9 +48,21 @@ class FollowItem extends StatelessWidget { height: 34, child: TextButton( onPressed: () async { - await Get.bottomSheet( - GroupPanel(mid: item.mid!), - isScrollControlled: true, + await showFlexibleBottomSheet( + bottomSheetColor: Colors.transparent, + minHeight: 1, + initHeight: 1, + maxHeight: 1, + context: Get.context!, + builder: (BuildContext context, + ScrollController scrollController, double offset) { + return GroupPanel( + mid: item.mid!, + scrollController: scrollController, + ); + }, + anchors: [1], + isSafeArea: true, ); }, style: TextButton.styleFrom( diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 50aac4cd..d564aba4 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:bottom_sheet/bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -523,9 +524,21 @@ class VideoIntroController extends GetxController { // 设置关注分组 void setFollowGroup() { - Get.bottomSheet( - GroupPanel(mid: videoDetail.value.owner!.mid!), - isScrollControlled: true, + showFlexibleBottomSheet( + bottomSheetColor: Colors.transparent, + minHeight: 0.6, + initHeight: 0.6, + maxHeight: 1, + context: Get.context!, + builder: (BuildContext context, ScrollController scrollController, + double offset) { + return GroupPanel( + mid: videoDetail.value.owner!.mid!, + scrollController: scrollController, + ); + }, + anchors: [0.6, 1], + isSafeArea: true, ); } diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 760976ae..a89b4d28 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -1,3 +1,6 @@ +import 'dart:ffi'; + +import 'package:bottom_sheet/bottom_sheet.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter/services.dart'; @@ -215,37 +218,35 @@ class _VideoInfoState extends State with TickerProviderStateMixin { if (!videoIntroController.hasFav.value) { videoIntroController.actionFavVideo(type: 'default'); } else { - showModalBottomSheet( - context: context, - useRootNavigator: true, - isScrollControlled: true, - builder: (BuildContext context) { - return FavPanel(ctr: videoIntroController); - }, - ); + _showFavPanel(); } } else { - showModalBottomSheet( - context: context, - useRootNavigator: true, - isScrollControlled: true, - builder: (BuildContext context) { - return FavPanel(ctr: videoIntroController); - }, - ); + _showFavPanel(); } } else if (type != 'longPress') { - showModalBottomSheet( - context: context, - useRootNavigator: true, - isScrollControlled: true, - builder: (BuildContext context) { - return FavPanel(ctr: videoIntroController); - }, - ); + _showFavPanel(); } } + void _showFavPanel() { + showFlexibleBottomSheet( + bottomSheetColor: Colors.transparent, + minHeight: 0.6, + initHeight: 0.6, + maxHeight: 1, + context: context, + builder: (BuildContext context, ScrollController scrollController, + double offset) { + return FavPanel( + ctr: videoIntroController, + scrollController: scrollController, + ); + }, + anchors: [0.6, 1], + isSafeArea: true, + ); + } + // 视频介绍 showIntroDetail() { feedBack(); diff --git a/lib/pages/video/detail/introduction/widgets/fav_panel.dart b/lib/pages/video/detail/introduction/widgets/fav_panel.dart index 5ef78967..a4e98df7 100644 --- a/lib/pages/video/detail/introduction/widgets/fav_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/fav_panel.dart @@ -6,8 +6,9 @@ import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; class FavPanel extends StatefulWidget { - const FavPanel({super.key, this.ctr}); + const FavPanel({super.key, this.ctr, this.scrollController}); final dynamic ctr; + final ScrollController? scrollController; @override State createState() => _FavPanelState(); @@ -15,31 +16,39 @@ class FavPanel extends StatefulWidget { class _FavPanelState extends State { final Box localCache = GStrorage.localCache; - late double sheetHeight; late Future _futureBuilderFuture; @override void initState() { super.initState(); - sheetHeight = localCache.get('sheetHeight'); _futureBuilderFuture = widget.ctr!.queryVideoInFolder(); } @override Widget build(BuildContext context) { return Container( - height: sheetHeight, - color: Theme.of(context).colorScheme.surface, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), child: Column( children: [ AppBar( centerTitle: false, elevation: 0, - leading: IconButton( - onPressed: () => Get.back(), - icon: const Icon(Icons.close_outlined)), - title: - Text('添加到收藏夹', style: Theme.of(context).textTheme.titleMedium), + automaticallyImplyLeading: false, + leadingWidth: 0, + title: Text( + '选择收藏夹', + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(fontWeight: FontWeight.bold), + ), ), Expanded( child: Material( @@ -51,22 +60,22 @@ class _FavPanelState extends State { if (data['status']) { return Obx( () => ListView.builder( + controller: widget.scrollController, itemCount: widget.ctr!.favFolderData.value.list!.length, itemBuilder: (context, index) { + final item = + widget.ctr!.favFolderData.value.list![index]; return ListTile( - onTap: () => widget.ctr!.onChoose( - widget.ctr!.favFolderData.value.list![index] - .favState != - 1, - index), + onTap: () => widget.ctr! + .onChoose(item.favState != 1, index), dense: true, leading: const Icon(Icons.folder_outlined), minLeadingWidth: 0, title: Text(widget.ctr!.favFolderData.value .list![index].title!), subtitle: Text( - '${widget.ctr!.favFolderData.value.list![index].mediaCount}个内容', + '${item.mediaCount}个内容 ', ), trailing: Transform.scale( scale: 0.9, @@ -132,7 +141,7 @@ class _FavPanelState extends State { backgroundColor: Theme.of(context).colorScheme.primary, // 设置按钮背景色 ), - child: const Text('完成'), + child: const Text('确认选择'), ), ], ), diff --git a/lib/pages/video/detail/introduction/widgets/group_panel.dart b/lib/pages/video/detail/introduction/widgets/group_panel.dart index dcdaf9c5..4bb0980c 100644 --- a/lib/pages/video/detail/introduction/widgets/group_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/group_panel.dart @@ -10,7 +10,8 @@ import 'package:pilipala/utils/storage.dart'; class GroupPanel extends StatefulWidget { final int? mid; - const GroupPanel({super.key, this.mid}); + final ScrollController scrollController; + const GroupPanel({super.key, this.mid, required this.scrollController}); @override State createState() => _GroupPanelState(); @@ -18,7 +19,6 @@ class GroupPanel extends StatefulWidget { class _GroupPanelState extends State { final Box localCache = GStrorage.localCache; - late double sheetHeight; late Future _futureBuilderFuture; late List tagsList; bool showDefault = true; @@ -26,7 +26,6 @@ class _GroupPanelState extends State { @override void initState() { super.initState(); - sheetHeight = localCache.get('sheetHeight'); _futureBuilderFuture = MemberHttp.followUpTags(); } @@ -56,8 +55,14 @@ class _GroupPanelState extends State { @override Widget build(BuildContext context) { return Container( - height: sheetHeight, - color: Theme.of(context).colorScheme.surface, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), child: Column( children: [ AppBar( @@ -79,6 +84,7 @@ class _GroupPanelState extends State { if (data['status']) { tagsList = data['data']; return ListView.builder( + controller: widget.scrollController, itemCount: data['data'].length, itemBuilder: (context, index) { return ListTile( diff --git a/pubspec.lock b/pubspec.lock index a46127f9..a42df7bb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,6 +113,22 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.1" + bottom_inset_observer: + dependency: transitive + description: + name: bottom_inset_observer + sha256: cbfb01e0e07cc4922052701786d5e607765a6f54e1844f41061abf8744519a7d + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.0" + bottom_sheet: + dependency: "direct main" + description: + name: bottom_sheet + sha256: efd28f52357d23e1c01eaeb45466b407f1e29318305bd6d10baf814fda18bd7e + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.4" build: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b5d45714..fb4cc2c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -146,6 +146,7 @@ dependencies: lottie: ^3.1.2 # 二维码 qr_flutter: ^4.1.0 + bottom_sheet: ^4.0.4 dev_dependencies: flutter_test: