2026-07-01 18:25:58 +08:00

361 lines
12 KiB
Dart

import 'package:extended_text/extended_text.dart';
import 'package:extended_text_field/extended_text_field.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:aslan/app_localizations.dart';
import 'package:aslan/chatvibe_ui/components/at_debounce_widget.dart';
import 'package:provider/provider.dart';
import 'package:aslan/chatvibe_core/constants/at_emoji_datas.dart';
import 'package:aslan/chatvibe_core/constants/at_screen.dart';
import 'package:aslan/chatvibe_core/utilities/at_keybord_util.dart';
import 'package:aslan/main.dart';
import 'package:aslan/chatvibe_managers/dynamic_content_manager.dart';
import 'package:aslan/chatvibe_ui/widgets/dynamic/comment/comment_gift_page.dart';
///聊天输入框
class CommentInput extends StatefulWidget {
String? toUserName;
String toUserId;
String dynamicContentId;
Function(String text)? callBack;
Function()? deleteCallBack;
Function(int count)? sendGiftCallBack;
CommentInput(
this.toUserId,
this.dynamicContentId, {
this.toUserName,
this.callBack,
this.deleteCallBack,
this.sendGiftCallBack,
});
@override
_CommentInputState createState() => _CommentInputState();
}
class _CommentInputState extends State<CommentInput> with RouteAware {
bool showSend = false;
final FocusNode _focusNode = FocusNode();
TextEditingController controller = TextEditingController();
@override
void initState() {
super.initState();
restState();
_focusNode.addListener((){
if(_focusNode.hasFocus){
Provider.of<ChatVibeDynamicContentManager>(context, listen: false).updateShowEmojiState(
false,
() {
setState(() {});
},
);
}
});
HardwareKeyboard.instance.addHandler(_handleKeyEvent);
}
bool _handleKeyEvent(KeyEvent event) {
// 检查是否是删除键
final isDeleteKey =
event.logicalKey == LogicalKeyboardKey.backspace ||
event.logicalKey == LogicalKeyboardKey.delete;
if (isDeleteKey) {
if (event is KeyDownEvent) {
// 删除键按下
if (controller.text.isEmpty) {
widget.deleteCallBack?.call();
}
}
}
// 返回 false 让其他部件也能处理这个事件
return false;
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 注册路由观察
final route = ModalRoute.of(context);
if (route is PageRoute) {
routeObserver.subscribe(this, route);
}
}
@override
void didPopNext() {
_focusNode.unfocus();
FocusScope.of(context).unfocus(); // 彻底取消当前上下文的所有焦点
}
@override
void dispose() {
_focusNode.dispose();
routeObserver.unsubscribe(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return float(context);
}
Widget float(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [_input(), _emoji(), _gift()],
);
}
_gift() {
return Selector<ChatVibeDynamicContentManager, bool>(
selector: (c, p) => p.showGift,
shouldRebuild: (prev, next) => prev != next,
builder: (_, showGift, __) {
return Visibility(
visible: showGift,
child: CommentGiftPage(
widget.toUserId,
widget.dynamicContentId,
sendGiftCallBack: widget.sendGiftCallBack,
),
);
},
);
}
_emoji() {
return Selector<ChatVibeDynamicContentManager, bool>(
selector: (c, p) => p.showEmoji,
shouldRebuild: (prev, next) => prev != next,
builder: (_, showEmoji, __) {
return Visibility(
visible: showEmoji,
child: Container(
color: Colors.white,
height: 150.w,
child: GridView.builder(
padding: EdgeInsets.symmetric(horizontal: 15.w),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 8,
crossAxisSpacing: 8.w,
mainAxisSpacing: 8.w,
),
itemBuilder: (c, index) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
var text = ATEmojiDatas.smileys[index];
final TextEditingValue value = controller.value;
controller.value = value.copyWith(
text: value.text + text,
selection: TextSelection.fromPosition(
TextPosition(offset: text.length),
),
);
showSend = true;
setState(() {});
},
child: Padding(
padding: EdgeInsets.all(4.0.w),
child: ExtendedText(
ATEmojiDatas.smileys[index],
// specialTextSpanBuilder: MySpecialTextSpanBuilder(),
style: TextStyle(fontSize: sp(15)),
),
),
);
},
itemCount: ATEmojiDatas.smileys.length,
),
),
);
},
);
}
void restState() {
Provider.of<ChatVibeDynamicContentManager>(context, listen: false).updateShowEmojiState(
false,
() {
setState(() {});
},
);
Provider.of<ChatVibeDynamicContentManager>(context, listen: false).updateShowGiftState(
false,
() {
setState(() {});
},
);
}
_input() {
return Selector<ChatVibeDynamicContentManager, bool>(
selector: (c, p) => p.showGift,
shouldRebuild: (prev, next) => prev != next,
builder: (_, showGift, __) {
return Visibility(
visible: !showGift,
child: Container(
decoration: BoxDecoration(color: Colors.white),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.w),
height: 56.w,
child: Row(
children: [
ATDebounceWidget(
child: Image.asset(
"atu_images/dynamic/at_icon_dynamic_emoji.png",
height: 35.w,
),
onTap: () {
ATKeybordUtil.conceal(context);
Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).updateShowEmojiState(
!Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).showEmoji,
() {
setState(() {});
},
);
Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).updateShowGiftState(false, () {
setState(() {});
});
},
),
SizedBox(width: 8.w),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Color(0xff7726FF).withOpacity(0.1),
borderRadius: BorderRadius.circular(height(5)),
),
child: Row(
children: [
Expanded(
child: ExtendedTextField(
focusNode: _focusNode,
controller: controller,
autofocus: false,
onChanged: (s) {
setState(() {
showSend = controller.text.isNotEmpty;
});
},
onSubmitted: (s) {
if (s.isNotEmpty) {
showSend = false;
setState(() {});
controller.clear();
}
},
decoration: InputDecoration(
hintText:
widget.toUserName == null ||
(widget.toUserName?.isEmpty ?? false)
? ATAppLocalizations.of(
context,
)!.saySomething
: "${ATAppLocalizations.of(context)!.reply}@${widget.toUserName}",
fillColor: Colors.transparent,
hintStyle: TextStyle(
color: Colors.grey,
fontSize: sp(13),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 15,
),
counterText: '',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(height(5)),
borderSide: BorderSide.none,
),
filled: true,
),
style: TextStyle(
fontSize: ScreenUtil().setSp(13),
color: Colors.black.withOpacity(1),
),
),
),
ATDebounceWidget(
onTap: () {
showSend = false;
Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).updateShowEmojiState(false, () {
setState(() {});
});
if (widget.dynamicContentId.isNotEmpty &&
controller.text.isNotEmpty) {
widget.callBack?.call(controller.text);
controller.text = "";
}
},
child: Container(
padding: EdgeInsets.all(4.w),
width: 30.w,
height: 30.w,
child: Image.asset(
showSend
? "atu_images/dynamic/at_icon_comment_input_message_send_en.png"
: "atu_images/dynamic/at_icon_comment_input_message_send_no.png",
),
),
),
SizedBox(width: 3.w),
],
),
),
),
SizedBox(width: 8.w),
widget.sendGiftCallBack != null
? ATDebounceWidget(
child: Image.asset(
"atu_images/dynamic/at_icon_dynamic_comment_gift.png",
height: 35.w,
),
onTap: () {
Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).updateShowGiftState(
!Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).showGift,
() {
setState(() {});
},
);
Provider.of<ChatVibeDynamicContentManager>(
context,
listen: false,
).updateShowEmojiState(false, () {
setState(() {});
});
},
)
: Container(),
],
),
),
);
},
);
}
}