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(
context: context,
isScrollControlled: true,
isDismissible: false,
builder: (BuildContext context) {
return VideoReplyNewDialog(
oid: _dynamicDetailController.oid ??

View File

@@ -49,47 +49,72 @@ class _EmotePanelState extends State<EmotePanel>
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<EmotePanel>
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(),

View File

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

View File

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

View File

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

View File

@@ -40,6 +40,8 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
double keyboardHeight = 0.0; // 键盘高度
final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间
String toolbarType = 'input';
bool _enablePublish = false;
final _publishStream = StreamController<bool>();
@override
void initState() {
@@ -94,6 +96,10 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
}
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<VideoReplyNewDialog>
@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<VideoReplyNewDialog>
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<VideoReplyNewDialog>
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)

View File

@@ -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';