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,47 +49,72 @@ 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
gridDelegate: ? GridView.builder(
SliverGridDelegateWithMaxCrossAxisExtent( gridDelegate:
maxCrossAxisExtent: SliverGridDelegateWithMaxCrossAxisExtent(
type == 4 ? 100 : (size == 1 ? 40 : 60), maxCrossAxisExtent: (size == 1 ? 40 : 60),
crossAxisSpacing: 8, crossAxisSpacing: 8,
mainAxisSpacing: 8, mainAxisSpacing: 8,
mainAxisExtent: size == 1 ? 40 : 60, mainAxisExtent: size == 1 ? 40 : 60,
), ),
itemCount: e.emote!.length, itemCount: e.emote!.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
clipBehavior: Clip.hardEdge, child: InkWell(
// shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8),
// borderRadius: BorderRadius.circular(4), onTap: () {
// ), widget.onChoose(e, e.emote![index]);
child: InkWell( },
onTap: () { child: Tooltip(
widget.onChoose(e, e.emote![index]); message: e.emote![index].text!
}, .substring(
child: Padding( 1,
padding: const EdgeInsets.all(3), e.emote![index].text!.length -
child: type == 4 1),
? Text( child: Padding(
e.emote![index].text!, padding: const EdgeInsets.all(6),
overflow: TextOverflow.clip, child: NetworkImgLayer(
maxLines: 1, src: e.emote![index].url!,
) width: size * 38,
: NetworkImgLayer( height: size * 38,
src: e.emote![index].url!, semanticsLabel:
width: size * 38, e.emote![index].text!,
height: size * 38, type: 'emote',
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(), ).toList(),
@@ -104,11 +129,14 @@ 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(
type: 'emote', width: 24,
src: e.url, height: 24,
type: 'emote',
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,32 +159,35 @@ 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: SingleChildScrollView(
), child: Form(
child: Container( key: _formKey,
padding: const EdgeInsets.only( autovalidateMode: AutovalidateMode.onUserInteraction,
top: 12, right: 15, left: 15, bottom: 10), child: TextField(
child: SingleChildScrollView( controller: _replyContentController,
child: Form( minLines: 4,
key: _formKey, maxLines: 8,
autovalidateMode: AutovalidateMode.onUserInteraction, autofocus: false,
child: TextField( onChanged: (value) {
controller: _replyContentController, if (value.isNotEmpty && !_enablePublish) {
minLines: 1, _enablePublish = true;
maxLines: null, _publishStream.add(true);
autofocus: false, } else if (value.isEmpty && _enablePublish) {
focusNode: replyContentFocusNode, _enablePublish = false;
decoration: const InputDecoration( _publishStream.add(false);
hintText: "输入回复内容", }
border: InputBorder.none, },
hintStyle: TextStyle( focusNode: replyContentFocusNode,
fontSize: 14, decoration: const InputDecoration(
)), hintText: "输入回复内容",
style: Theme.of(context).textTheme.bodyLarge, border: InputBorder.none,
), hintStyle: TextStyle(
fontSize: 14,
)),
style: Theme.of(context).textTheme.bodyLarge,
), ),
), ),
), ),
@@ -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(
width: double.infinity, curve: Curves.easeInOut,
height: toolbarType == 'input' ? keyboardHeight : emoteHeight, duration: const Duration(milliseconds: 300),
child: EmotePanel( child: SizedBox(
onChoose: onChooseEmote, width: double.infinity,
height: toolbarType == 'input'
? (_keyboardHeight > keyboardHeight
? _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';