Merge pull request #433 from orz12/mod-video-detail-reply

mod: 视频评论输入框高度自适应
This commit is contained in:
guozhigq
2024-01-21 14:54:44 +08:00
committed by GitHub

View File

@ -2,12 +2,10 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/common/reply_type.dart';
import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart';
class VideoReplyNewDialog extends StatefulWidget { class VideoReplyNewDialog extends StatefulWidget {
final int? oid; final int? oid;
@ -34,25 +32,16 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
final TextEditingController _replyContentController = TextEditingController(); final TextEditingController _replyContentController = TextEditingController();
final FocusNode replyContentFocusNode = FocusNode(); final FocusNode replyContentFocusNode = FocusNode();
final GlobalKey _formKey = GlobalKey<FormState>(); final GlobalKey _formKey = GlobalKey<FormState>();
double _keyboardHeight = 0.0; // 键盘高度
final _debouncer = Debouncer(milliseconds: 100); // 设置延迟时间
bool ableClean = false;
Timer? timer;
Box localCache = GStrorage.localCache;
late double sheetHeight;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// 监听输入框聚焦 // 监听输入框聚焦
// replyContentFocusNode.addListener(_onFocus); // replyContentFocusNode.addListener(_onFocus);
_replyContentController.addListener(_printLatestValue);
// 界面观察者 必须 // 界面观察者 必须
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
// 自动聚焦 // 自动聚焦
_autoFocus(); _autoFocus();
sheetHeight = localCache.get('sheetHeight');
} }
_autoFocus() async { _autoFocus() async {
@ -62,12 +51,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
} }
} }
_printLatestValue() {
setState(() {
ableClean = _replyContentController.text != '';
});
}
Future submitReplyAdd() async { Future submitReplyAdd() async {
feedBack(); feedBack();
String message = _replyContentController.text; String message = _replyContentController.text;
@ -90,24 +73,6 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
} }
} }
@override
void didChangeMetrics() {
super.didChangeMetrics();
WidgetsBinding.instance.addPostFrameCallback((_) {
// 键盘高度
final viewInsets = EdgeInsets.fromViewPadding(
View.of(context).viewInsets, View.of(context).devicePixelRatio);
_debouncer.run(() {
if (mounted) {
setState(() {
_keyboardHeight =
_keyboardHeight == 0.0 ? viewInsets.bottom : _keyboardHeight;
});
}
});
});
}
@override @override
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
@ -117,8 +82,10 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double keyboardHeight = EdgeInsets.fromViewPadding(
View.of(context).viewInsets, View.of(context).devicePixelRatio)
.bottom;
return Container( return Container(
height: 500,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
@ -130,26 +97,32 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Expanded( ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 200,
minHeight: 120,
),
child: Container( child: Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 6, right: 15, left: 15, bottom: 10), top: 12, right: 15, left: 15, bottom: 10),
child: Form( child: SingleChildScrollView(
key: _formKey, child: Form(
autovalidateMode: AutovalidateMode.onUserInteraction, key: _formKey,
child: TextField( autovalidateMode: AutovalidateMode.onUserInteraction,
controller: _replyContentController, child: TextField(
minLines: 1, controller: _replyContentController,
maxLines: null, minLines: 1,
autofocus: false, maxLines: null,
focusNode: replyContentFocusNode, autofocus: false,
decoration: const InputDecoration( focusNode: replyContentFocusNode,
hintText: "输入回复内容", decoration: const InputDecoration(
border: InputBorder.none, hintText: "输入回复内容",
hintStyle: TextStyle( border: InputBorder.none,
fontSize: 14, hintStyle: TextStyle(
)), fontSize: 14,
style: Theme.of(context).textTheme.bodyLarge, )),
style: Theme.of(context).textTheme.bodyLarge,
),
), ),
), ),
), ),
@ -168,22 +141,23 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
width: 36, width: 36,
height: 36, height: 36,
child: IconButton( child: IconButton(
onPressed: () { onPressed: () {
FocusScope.of(context) FocusScope.of(context)
.requestFocus(replyContentFocusNode); .requestFocus(replyContentFocusNode);
}, },
icon: Icon(Icons.keyboard, icon: Icon(Icons.keyboard,
size: 22, size: 22,
color: Theme.of(context).colorScheme.onBackground), color: Theme.of(context).colorScheme.onBackground),
highlightColor: highlightColor:
Theme.of(context).colorScheme.onInverseSurface, Theme.of(context).colorScheme.onInverseSurface,
style: ButtonStyle( style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero), padding: MaterialStateProperty.all(EdgeInsets.zero),
backgroundColor: backgroundColor:
MaterialStateProperty.resolveWith((states) { MaterialStateProperty.resolveWith((states) {
return Theme.of(context).highlightColor; return Theme.of(context).highlightColor;
}), }),
)), ),
),
), ),
const Spacer(), const Spacer(),
TextButton( TextButton(
@ -196,7 +170,7 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
height: _keyboardHeight, height: keyboardHeight,
), ),
), ),
], ],
@ -204,22 +178,3 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
); );
} }
} }
typedef DebounceCallback = void Function();
class Debouncer {
DebounceCallback? callback;
final int? milliseconds;
Timer? _timer;
Debouncer({this.milliseconds});
run(DebounceCallback callback) {
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds!), () {
callback();
});
}
}