opt: reply dialog

This commit is contained in:
bggRGjQaUbCoE
2024-08-27 10:15:46 +08:00
parent 9e158cc2d4
commit 0e332ce080
7 changed files with 134 additions and 88 deletions

View File

@@ -295,7 +295,6 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
isDismissible: false,
builder: (BuildContext context) { builder: (BuildContext context) {
return VideoReplyNewDialog( return VideoReplyNewDialog(
oid: _dynamicDetailController.oid ?? oid: _dynamicDetailController.oid ??

View File

@@ -49,11 +49,11 @@ class _EmotePanelState extends State<EmotePanel>
int type = e.type!; int type = e.type!;
return Padding( return Padding(
padding: const EdgeInsets.fromLTRB(12, 6, 12, 0), padding: const EdgeInsets.fromLTRB(12, 6, 12, 0),
child: GridView.builder( child: type != 4
? GridView.builder(
gridDelegate: gridDelegate:
SliverGridDelegateWithMaxCrossAxisExtent( SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent: (size == 1 ? 40 : 60),
type == 4 ? 100 : (size == 1 ? 40 : 60),
crossAxisSpacing: 8, crossAxisSpacing: 8,
mainAxisSpacing: 8, mainAxisSpacing: 8,
mainAxisExtent: size == 1 ? 40 : 60, mainAxisExtent: size == 1 ? 40 : 60,
@@ -62,33 +62,58 @@ class _EmotePanelState extends State<EmotePanel>
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
clipBehavior: Clip.hardEdge,
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(4),
// ),
child: InkWell( child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () { onTap: () {
widget.onChoose(e, e.emote![index]); widget.onChoose(e, e.emote![index]);
}, },
child: Tooltip(
message: e.emote![index].text!
.substring(
1,
e.emote![index].text!.length -
1),
child: Padding( child: Padding(
padding: const EdgeInsets.all(3), padding: const EdgeInsets.all(6),
child: type == 4 child: NetworkImgLayer(
? Text(
e.emote![index].text!,
overflow: TextOverflow.clip,
maxLines: 1,
)
: NetworkImgLayer(
src: e.emote![index].url!, src: e.emote![index].url!,
width: size * 38, width: size * 38,
height: size * 38, height: size * 38,
semanticsLabel: e.emote![index].text!, semanticsLabel:
e.emote![index].text!,
type: 'emote', 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(),
),
), ),
); );
}, },
@@ -104,12 +129,15 @@ class _EmotePanelState extends State<EmotePanel>
isScrollable: true, isScrollable: true,
tabs: _emotePanelController.emotePackage tabs: _emotePanelController.emotePackage
.map( .map(
(e) => NetworkImgLayer( (e) => Padding(
width: 36, padding: const EdgeInsets.all(8),
height: 36, child: NetworkImgLayer(
width: 24,
height: 24,
type: 'emote', type: 'emote',
src: e.url, src: e.url,
), ),
),
) )
.toList(), .toList(),
), ),

View File

@@ -348,7 +348,6 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
isDismissible: false,
builder: (BuildContext context) { builder: (BuildContext context) {
return VideoReplyNewDialog( return VideoReplyNewDialog(
oid: _htmlRenderCtr.oid.value, oid: _htmlRenderCtr.oid.value,

View File

@@ -239,7 +239,6 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
feedBack(); feedBack();
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
isDismissible: false,
isScrollControlled: true, isScrollControlled: true,
builder: (BuildContext context) { builder: (BuildContext context) {
return VideoReplyNewDialog( return VideoReplyNewDialog(

View File

@@ -303,7 +303,6 @@ class ReplyItem extends StatelessWidget {
onPressed: () { onPressed: () {
feedBack(); feedBack();
showModalBottomSheet( showModalBottomSheet(
isDismissible: false,
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (builder) { builder: (builder) {

View File

@@ -40,6 +40,8 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
double keyboardHeight = 0.0; // 键盘高度 double keyboardHeight = 0.0; // 键盘高度
final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间 final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间
String toolbarType = 'input'; String toolbarType = 'input';
bool _enablePublish = false;
final _publishStream = StreamController<bool>();
@override @override
void initState() { void initState() {
@@ -94,6 +96,10 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
} }
void onChooseEmote(Packages package, Emote emote) { void onChooseEmote(Packages package, Emote emote) {
if (!_enablePublish) {
_enablePublish = true;
_publishStream.add(true);
}
final int cursorPosition = _replyContentController.selection.baseOffset; final int cursorPosition = _replyContentController.selection.baseOffset;
final String currentText = _replyContentController.text; final String currentText = _replyContentController.text;
final String newText = currentText.substring(0, cursorPosition) + final String newText = currentText.substring(0, cursorPosition) +
@@ -138,7 +144,7 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double keyboardHeight = EdgeInsets.fromViewPadding( double _keyboardHeight = EdgeInsets.fromViewPadding(
View.of(context).viewInsets, View.of(context).devicePixelRatio) View.of(context).viewInsets, View.of(context).devicePixelRatio)
.bottom; .bottom;
return Container( return Container(
@@ -153,23 +159,27 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ConstrainedBox( Container(
constraints: const BoxConstraints( padding:
maxHeight: 200, const EdgeInsets.only(top: 12, right: 15, left: 15, bottom: 10),
minHeight: 120,
),
child: Container(
padding: const EdgeInsets.only(
top: 12, right: 15, left: 15, bottom: 10),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Form( child: Form(
key: _formKey, key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction, autovalidateMode: AutovalidateMode.onUserInteraction,
child: TextField( child: TextField(
controller: _replyContentController, controller: _replyContentController,
minLines: 1, minLines: 4,
maxLines: null, maxLines: 8,
autofocus: false, 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, focusNode: replyContentFocusNode,
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: "输入回复内容", hintText: "输入回复内容",
@@ -182,7 +192,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
), ),
), ),
), ),
),
Divider( Divider(
height: 1, height: 1,
color: Theme.of(context).dividerColor.withOpacity(0.1), color: Theme.of(context).dividerColor.withOpacity(0.1),
@@ -223,22 +232,36 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
selected: toolbarType == 'emote', selected: toolbarType == 'emote',
), ),
const Spacer(), const Spacer(),
TextButton( StreamBuilder(
onPressed: () => Get.back(), initialData: false,
child: Text('取消', stream: _publishStream.stream,
style: TextStyle( builder: (_, snapshot) => FilledButton.tonal(
color: Theme.of(context).colorScheme.secondary))), onPressed: snapshot.data == true ? submitReplyAdd : null,
const SizedBox(width: 10), style: FilledButton.styleFrom(
TextButton( padding: const EdgeInsets.symmetric(
onPressed: () => submitReplyAdd(), child: const Text('发送')) horizontal: 20, vertical: 10),
visualDensity: const VisualDensity(
horizontal: -2,
vertical: -2,
),
),
child: const Text('发送'),
),
),
], ],
), ),
), ),
SizedBox( AnimatedSize(
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 300),
child: SizedBox(
width: double.infinity, width: double.infinity,
height: toolbarType == 'input' ? keyboardHeight : emoteHeight, height: toolbarType == 'input'
child: EmotePanel( ? (_keyboardHeight > keyboardHeight
onChoose: onChooseEmote, ? _keyboardHeight
: keyboardHeight)
: emoteHeight,
child: EmotePanel(onChoose: onChooseEmote),
), ),
), ),
if (toolbarType == 'input' && keyboardHeight == 0.0) if (toolbarType == 'input' && keyboardHeight == 0.0)

View File

@@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:ui';
import 'package:PiliPalaX/utils/extension.dart'; import 'package:PiliPalaX/utils/extension.dart';
import 'package:auto_orientation/auto_orientation.dart'; import 'package:auto_orientation/auto_orientation.dart';