diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index bd0725028..698238666 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -295,7 +295,6 @@ class _DynamicDetailPageState extends State showModalBottomSheet( context: context, isScrollControlled: true, - isDismissible: false, builder: (BuildContext context) { return VideoReplyNewDialog( oid: _dynamicDetailController.oid ?? diff --git a/lib/pages/emote/view.dart b/lib/pages/emote/view.dart index 7268675fc..c19cfac41 100644 --- a/lib/pages/emote/view.dart +++ b/lib/pages/emote/view.dart @@ -49,47 +49,72 @@ class _EmotePanelState extends State int type = e.type!; return Padding( padding: const EdgeInsets.fromLTRB(12, 6, 12, 0), - child: GridView.builder( - gridDelegate: - SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: - type == 4 ? 100 : (size == 1 ? 40 : 60), - crossAxisSpacing: 8, - mainAxisSpacing: 8, - mainAxisExtent: size == 1 ? 40 : 60, - ), - itemCount: e.emote!.length, - itemBuilder: (context, index) { - return Material( - color: Colors.transparent, - clipBehavior: Clip.hardEdge, - // shape: RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(4), - // ), - child: InkWell( - onTap: () { - widget.onChoose(e, e.emote![index]); - }, - child: Padding( - padding: const EdgeInsets.all(3), - child: type == 4 - ? Text( - e.emote![index].text!, - overflow: TextOverflow.clip, - maxLines: 1, - ) - : NetworkImgLayer( - src: e.emote![index].url!, - width: size * 38, - height: size * 38, - semanticsLabel: e.emote![index].text!, - type: 'emote', + child: type != 4 + ? GridView.builder( + gridDelegate: + SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: (size == 1 ? 40 : 60), + crossAxisSpacing: 8, + mainAxisSpacing: 8, + mainAxisExtent: size == 1 ? 40 : 60, + ), + itemCount: e.emote!.length, + itemBuilder: (context, index) { + return Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(8), + onTap: () { + widget.onChoose(e, e.emote![index]); + }, + child: Tooltip( + message: e.emote![index].text! + .substring( + 1, + e.emote![index].text!.length - + 1), + child: Padding( + padding: const EdgeInsets.all(6), + child: NetworkImgLayer( + src: e.emote![index].url!, + width: size * 38, + height: size * 38, + semanticsLabel: + e.emote![index].text!, + type: 'emote', + ), ), + ), + ), + ); + }, + ) + : SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 12), + child: Wrap( + spacing: 8, + runSpacing: 8, + children: e.emote! + .map( + (item) => Material( + color: Colors.transparent, + child: InkWell( + borderRadius: + BorderRadius.circular(8), + onTap: () { + widget.onChoose(e, item); + }, + child: Padding( + padding: + const EdgeInsets.all(6), + child: Text(item.text!), + ), + ), + ), + ) + .toList(), ), ), - ); - }, - ), ); }, ).toList(), @@ -104,11 +129,14 @@ class _EmotePanelState extends State isScrollable: true, tabs: _emotePanelController.emotePackage .map( - (e) => NetworkImgLayer( - width: 36, - height: 36, - type: 'emote', - src: e.url, + (e) => Padding( + padding: const EdgeInsets.all(8), + child: NetworkImgLayer( + width: 24, + height: 24, + type: 'emote', + src: e.url, + ), ), ) .toList(), diff --git a/lib/pages/html/view.dart b/lib/pages/html/view.dart index d623c7d50..e73aea3f0 100644 --- a/lib/pages/html/view.dart +++ b/lib/pages/html/view.dart @@ -348,7 +348,6 @@ class _HtmlRenderPageState extends State showModalBottomSheet( context: context, isScrollControlled: true, - isDismissible: false, builder: (BuildContext context) { return VideoReplyNewDialog( oid: _htmlRenderCtr.oid.value, diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index c2176ac17..642c53a4d 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -239,7 +239,6 @@ class _VideoReplyPanelState extends State feedBack(); showModalBottomSheet( context: context, - isDismissible: false, isScrollControlled: true, builder: (BuildContext context) { return VideoReplyNewDialog( diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index 3f0eeaa7a..b9e9e9f00 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -303,7 +303,6 @@ class ReplyItem extends StatelessWidget { onPressed: () { feedBack(); showModalBottomSheet( - isDismissible: false, context: context, isScrollControlled: true, builder: (builder) { diff --git a/lib/pages/video/detail/reply_new/view.dart b/lib/pages/video/detail/reply_new/view.dart index 2de6a855b..8cedc50f7 100644 --- a/lib/pages/video/detail/reply_new/view.dart +++ b/lib/pages/video/detail/reply_new/view.dart @@ -40,6 +40,8 @@ class _VideoReplyNewDialogState extends State double keyboardHeight = 0.0; // 键盘高度 final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间 String toolbarType = 'input'; + bool _enablePublish = false; + final _publishStream = StreamController(); @override void initState() { @@ -94,6 +96,10 @@ class _VideoReplyNewDialogState extends State } void onChooseEmote(Packages package, Emote emote) { + if (!_enablePublish) { + _enablePublish = true; + _publishStream.add(true); + } final int cursorPosition = _replyContentController.selection.baseOffset; final String currentText = _replyContentController.text; final String newText = currentText.substring(0, cursorPosition) + @@ -138,7 +144,7 @@ class _VideoReplyNewDialogState extends State @override Widget build(BuildContext context) { - double keyboardHeight = EdgeInsets.fromViewPadding( + double _keyboardHeight = EdgeInsets.fromViewPadding( View.of(context).viewInsets, View.of(context).devicePixelRatio) .bottom; return Container( @@ -153,32 +159,35 @@ class _VideoReplyNewDialogState extends State child: Column( mainAxisSize: MainAxisSize.min, children: [ - ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 200, - minHeight: 120, - ), - child: Container( - padding: const EdgeInsets.only( - top: 12, right: 15, left: 15, bottom: 10), - child: SingleChildScrollView( - child: Form( - key: _formKey, - autovalidateMode: AutovalidateMode.onUserInteraction, - child: TextField( - controller: _replyContentController, - minLines: 1, - maxLines: null, - autofocus: false, - focusNode: replyContentFocusNode, - decoration: const InputDecoration( - hintText: "输入回复内容", - border: InputBorder.none, - hintStyle: TextStyle( - fontSize: 14, - )), - style: Theme.of(context).textTheme.bodyLarge, - ), + Container( + padding: + const EdgeInsets.only(top: 12, right: 15, left: 15, bottom: 10), + child: SingleChildScrollView( + child: Form( + key: _formKey, + autovalidateMode: AutovalidateMode.onUserInteraction, + child: TextField( + controller: _replyContentController, + minLines: 4, + maxLines: 8, + autofocus: false, + onChanged: (value) { + if (value.isNotEmpty && !_enablePublish) { + _enablePublish = true; + _publishStream.add(true); + } else if (value.isEmpty && _enablePublish) { + _enablePublish = false; + _publishStream.add(false); + } + }, + focusNode: replyContentFocusNode, + decoration: const InputDecoration( + hintText: "输入回复内容", + border: InputBorder.none, + hintStyle: TextStyle( + fontSize: 14, + )), + style: Theme.of(context).textTheme.bodyLarge, ), ), ), @@ -223,22 +232,36 @@ class _VideoReplyNewDialogState extends State selected: toolbarType == 'emote', ), const Spacer(), - TextButton( - onPressed: () => Get.back(), - child: Text('取消', - style: TextStyle( - color: Theme.of(context).colorScheme.secondary))), - const SizedBox(width: 10), - TextButton( - onPressed: () => submitReplyAdd(), child: const Text('发送')) + StreamBuilder( + initialData: false, + stream: _publishStream.stream, + builder: (_, snapshot) => FilledButton.tonal( + onPressed: snapshot.data == true ? submitReplyAdd : null, + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 10), + visualDensity: const VisualDensity( + horizontal: -2, + vertical: -2, + ), + ), + child: const Text('发送'), + ), + ), ], ), ), - SizedBox( - width: double.infinity, - height: toolbarType == 'input' ? keyboardHeight : emoteHeight, - child: EmotePanel( - onChoose: onChooseEmote, + AnimatedSize( + curve: Curves.easeInOut, + duration: const Duration(milliseconds: 300), + child: SizedBox( + width: double.infinity, + height: toolbarType == 'input' + ? (_keyboardHeight > keyboardHeight + ? _keyboardHeight + : keyboardHeight) + : emoteHeight, + child: EmotePanel(onChoose: onChooseEmote), ), ), if (toolbarType == 'input' && keyboardHeight == 0.0) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 0c0963cbd..2f99a9983 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:io'; import 'dart:math'; -import 'dart:ui'; import 'package:PiliPalaX/utils/extension.dart'; import 'package:auto_orientation/auto_orientation.dart';