You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1142 lines
51 KiB
1142 lines
51 KiB
import 'dart:io';
|
|
|
|
import 'package:dating_touchme_app/components/chat_message.dart';
|
|
import 'package:dating_touchme_app/components/my_message.dart';
|
|
import 'package:dating_touchme_app/components/page_appbar.dart';
|
|
import 'package:dating_touchme_app/router/route_paths.dart';
|
|
import 'package:dating_touchme_app/utils/utils.dart';
|
|
import 'package:device_info_plus/device_info_plus.dart';
|
|
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
|
import 'package:flutter/foundation.dart' as foundation;
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import 'package:tdesign_flutter/tdesign_flutter.dart';
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';
|
|
|
|
class MessagePage extends StatefulWidget {
|
|
final int id;
|
|
const MessagePage({super.key, required this.id});
|
|
|
|
@override
|
|
State<MessagePage> createState() => _MessagePageState();
|
|
}
|
|
|
|
class _MessagePageState extends State<MessagePage> with TickerProviderStateMixin {
|
|
|
|
|
|
String message = '';
|
|
final TextEditingController _messageController = TextEditingController();
|
|
|
|
|
|
|
|
final _controller = TextEditingController();
|
|
final _scrollController = ScrollController();
|
|
|
|
|
|
final ScrollController _messageScrollController = ScrollController();
|
|
|
|
|
|
|
|
int activeGift = 0;
|
|
|
|
List<Map> giftList = [
|
|
{"icon": "assets/gift1.png", "title": "爱心礼物", "price": 30},
|
|
{"icon": "assets/gift2.png", "title": "小小小星星", "price": 30},
|
|
{"icon": "assets/gift3.png", "title": "助威", "price": 30},
|
|
{"icon": "assets/gift4.png", "title": "点赞", "price": 30},
|
|
{"icon": "assets/gift5.png", "title": "崇拜衣柜", "price": 30},
|
|
];
|
|
|
|
final giftNum = ValueNotifier<int>(1);
|
|
|
|
|
|
|
|
changeActive(int index){
|
|
activeGift = index;
|
|
setState(() {
|
|
|
|
});
|
|
}
|
|
|
|
|
|
late AnimationController _voiceController;
|
|
late Animation<double> _voiceAnimation;
|
|
|
|
late AnimationController _giftController;
|
|
late Animation<double> _giftAnimation;
|
|
|
|
late AnimationController _emojiController;
|
|
late Animation<double> _emojiAnimation;
|
|
|
|
late AnimationController _moreController;
|
|
late Animation<double> _moreAnimation;
|
|
|
|
List<Map> messageList = [
|
|
{"avatar": "assets/user_avatar.png", "message": "你好", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "你好", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "这周六有空吗?", "type": 2},
|
|
{"avatar": "assets/user_avatar.png", "message": "周六时间不方便,我们约周日下午可以吗?", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "那周六不见不散", "type": 2},
|
|
{"avatar": "assets/user_avatar.png", "message": "你好", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "这周六有空吗?", "type": 2},
|
|
{"avatar": "assets/user_avatar.png", "message": "周六时间不方便,我们约周日下午可以吗?", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "那周六不见不散", "type": 2},
|
|
{"avatar": "assets/user_avatar.png", "message": "你好", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "这周六有空吗?", "type": 2},
|
|
{"avatar": "assets/user_avatar.png", "message": "周六时间不方便,我们约周日下午可以吗?", "type": 1},
|
|
{"avatar": "assets/user_avatar.png", "message": "那周六不见不散", "type": 2},
|
|
];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
_voiceController = AnimationController(
|
|
vsync: this,
|
|
duration: Duration(milliseconds: 200),
|
|
);
|
|
|
|
_voiceAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_voiceController)
|
|
..addListener(() {
|
|
setState(() {});
|
|
});
|
|
|
|
_giftController = AnimationController(
|
|
vsync: this,
|
|
duration: Duration(milliseconds: 200),
|
|
);
|
|
|
|
_giftAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_giftController)
|
|
..addListener(() {
|
|
setState(() {});
|
|
});
|
|
|
|
_emojiController = AnimationController(
|
|
vsync: this,
|
|
duration: Duration(milliseconds: 200),
|
|
);
|
|
|
|
_emojiAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_emojiController)
|
|
..addListener(() {
|
|
setState(() {});
|
|
});
|
|
|
|
_moreController = AnimationController(
|
|
vsync: this,
|
|
duration: Duration(milliseconds: 200),
|
|
);
|
|
|
|
_moreAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_moreController)
|
|
..addListener(() {
|
|
setState(() {});
|
|
});
|
|
|
|
|
|
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_messageScrollController.animateTo(
|
|
_messageScrollController.position.maxScrollExtent, // 滚动到最大可滚动位置
|
|
duration: const Duration(milliseconds: 300),
|
|
curve: Curves.easeOut,
|
|
);
|
|
});
|
|
}
|
|
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
_controller.dispose();
|
|
_voiceController.dispose();
|
|
_giftController.dispose();
|
|
_emojiController.dispose();
|
|
_moreController.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
onTap: (){
|
|
_emojiController.reverse();
|
|
_voiceController.reverse();
|
|
_giftController.reverse();
|
|
_moreController.reverse();
|
|
FocusScope.of(context).unfocus();
|
|
},
|
|
child: Scaffold(
|
|
backgroundColor: const Color.fromRGBO(250, 250, 250, 1),
|
|
appBar: PageAppbar(title: "林园园", right: Container(
|
|
margin: EdgeInsets.only(right: 28.w),
|
|
child: InkWell(
|
|
onTap: (){
|
|
context.pushNamed(RouteNames.messageSetting);
|
|
},
|
|
child: Image.asset(
|
|
"assets/menu_icon.png",
|
|
width: 31.w,
|
|
height: 35.w,
|
|
),
|
|
),
|
|
),),
|
|
body: Column(
|
|
children: [
|
|
Expanded(
|
|
child: SingleChildScrollView(
|
|
controller: _messageScrollController,
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(
|
|
horizontal: 20.w,
|
|
vertical: 28.w
|
|
),
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
width: 710.w,
|
|
height: 351.w,
|
|
padding: EdgeInsets.all(20.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
border: Border.all(width: 1, color: const Color.fromRGBO(117, 98, 249, .32)),
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter, // 对应 180deg:从上到下
|
|
end: Alignment.bottomCenter,
|
|
colors: [
|
|
Color.fromRGBO(248, 242, 255, 1), // 顶部透明白
|
|
Color.fromRGBO(255, 255, 255, 1), // 底部纯白
|
|
],
|
|
stops: [0.0, 1.0],
|
|
),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Text(
|
|
"林媛媛",
|
|
style: TextStyle(
|
|
fontSize: 32.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1),
|
|
fontWeight: FontWeight.w500
|
|
),
|
|
),
|
|
SizedBox(width: 19.w,),
|
|
Container(
|
|
width: 87.w,
|
|
height: 26.w,
|
|
margin: EdgeInsets.only(right: 8.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(26.w)),
|
|
color: const Color.fromRGBO(246, 237, 255, 1)
|
|
),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Image.asset(
|
|
"assets/real_name.png",
|
|
width: 16.w,
|
|
),
|
|
SizedBox(width: 5.w,),
|
|
Text(
|
|
"实名",
|
|
style: TextStyle(
|
|
fontSize: 18.w,
|
|
color: const Color.fromRGBO(160, 92, 255, 1)
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
width: 66.w,
|
|
height: 26.w,
|
|
margin: EdgeInsets.only(right: 5.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(26.w)),
|
|
color: const Color.fromRGBO(234, 255, 219, 1)
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"在线",
|
|
style: TextStyle(
|
|
fontSize: 18.w,
|
|
color: const Color.fromRGBO(38, 199, 124, 1)
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
SizedBox(width: 14.w,),
|
|
Row(
|
|
children: [
|
|
SizedBox(width: 12.w,),
|
|
Image.asset(
|
|
"assets/female.png",
|
|
width: 20.w,
|
|
height: 20.w,
|
|
),
|
|
SizedBox(width: 2.w,),
|
|
Text(
|
|
"·19",
|
|
style: TextStyle(
|
|
fontSize: 23.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1),
|
|
),
|
|
),
|
|
SizedBox(width: 32.w,),
|
|
Text(
|
|
"北京",
|
|
style: TextStyle(
|
|
fontSize: 23.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1),
|
|
),
|
|
),
|
|
SizedBox(width: 32.w,),
|
|
Text(
|
|
"160cm",
|
|
style: TextStyle(
|
|
fontSize: 23.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1),
|
|
),
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
Container(
|
|
width: 40.w,
|
|
height: 40.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(40.w)),
|
|
border: Border.all(width: 1, color: const Color.fromRGBO(158, 149, 201, 1))
|
|
),
|
|
child: Center(
|
|
child: Icon(
|
|
Icons.keyboard_arrow_right,
|
|
size: 20.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
SizedBox(height: 20.w,),
|
|
Text(
|
|
"喜欢在广州的早茶里抢最后一个虾饺,也能在深夜的猎德大桥喜欢在广州的早茶里抢最后一个虾饺,也能在深夜的猎德大桥喜欢在广州的早茶里抢最后一个虾饺,也能在深夜的猎德大桥.........",
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
fontSize: 23.w,
|
|
color: const Color.fromRGBO(144, 144, 144, 1)
|
|
),
|
|
),
|
|
SizedBox(height: 14.w,),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
child: Image.network(
|
|
"https://fastly.picsum.photos/id/64/800/800.jpg?hmac=NBZ4_-vqzD6p25oCeaW0H5vH-ql9zzei-SqJNeUo1QU",
|
|
width: 158.w,
|
|
height: 158.w,
|
|
),
|
|
),
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
child: Image.network(
|
|
"https://fastly.picsum.photos/id/985/800/800.jpg?hmac=DfRt99HFbMJ96DlN-poOhruWYRsexESE94ilLC3g1rU",
|
|
width: 158.w,
|
|
height: 158.w,
|
|
),
|
|
),
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
child: Image.network(
|
|
"https://fastly.picsum.photos/id/703/800/800.jpg?hmac=-bRTkPxnsiQ5kCo2tfXj6tFrXMD7YnVx7bQ0STno3Tg",
|
|
width: 158.w,
|
|
height: 158.w,
|
|
),
|
|
),
|
|
ClipRRect(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
child: Image.network(
|
|
"https://fastly.picsum.photos/id/392/800/800.jpg?hmac=kG-nWTx3JQTI-0F7oq9G6VyD_3GNJg4eRUsYX4yRHgc",
|
|
width: 158.w,
|
|
height: 158.w,
|
|
),
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
),
|
|
SizedBox(height: 60.w,),
|
|
Text(
|
|
"昨天 下午 14:46",
|
|
style: TextStyle(
|
|
fontSize: 21.w,
|
|
color: const Color.fromRGBO(144, 144, 144, 1)
|
|
),
|
|
),
|
|
...messageList.map((e){
|
|
if(e["type"] == 1){
|
|
return ChatMessage(avatar: e["avatar"], message: e["message"]);
|
|
} else {
|
|
return MyMessage(avatar: e["avatar"], message: e["message"]);
|
|
}
|
|
}),
|
|
],
|
|
),
|
|
),
|
|
)
|
|
),
|
|
Container(
|
|
padding: EdgeInsets.only(
|
|
top: 17.w,
|
|
right: 28.w,
|
|
left: 31.w
|
|
),
|
|
color: Colors.white,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Container(
|
|
width: 552.w,
|
|
height: 77.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
color: const Color.fromRGBO(242, 242, 242, 1)
|
|
),
|
|
child: Center(
|
|
child: TextField(
|
|
controller: _messageController,
|
|
keyboardType: TextInputType.number,
|
|
style: TextStyle(
|
|
fontSize: ScreenUtil().setWidth(28),
|
|
height: 1
|
|
),
|
|
decoration: InputDecoration(
|
|
contentPadding: EdgeInsets.symmetric(
|
|
vertical: 0,
|
|
horizontal: 34.w
|
|
),
|
|
hintText: "请输入聊天内容~",
|
|
|
|
border: const OutlineInputBorder(
|
|
borderSide: BorderSide.none, // 这将移除边框 // 可选:设置圆角
|
|
),
|
|
// 如果你希望聚焦时和未聚焦时都没有边框,也可以设置 focusedBorder 和 enabledBorder
|
|
focusedBorder: const OutlineInputBorder(
|
|
borderSide: BorderSide.none,
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
),
|
|
enabledBorder: const OutlineInputBorder(
|
|
borderSide: BorderSide.none,
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
),
|
|
),
|
|
onChanged: (value){
|
|
message = value;
|
|
},
|
|
),
|
|
),
|
|
),
|
|
InkWell(
|
|
onTap: (){
|
|
messageList.add({
|
|
"avatar": "assets/user_avatar.png",
|
|
"message": message,
|
|
"type": 2
|
|
});
|
|
message = "";
|
|
|
|
_messageController.value = TextEditingValue(
|
|
text: message,
|
|
selection: TextSelection.fromPosition(TextPosition(offset: message.length)),
|
|
);
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
});
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
_messageScrollController.animateTo(
|
|
_messageScrollController.position.maxScrollExtent, // 滚动到最大可滚动位置
|
|
duration: const Duration(milliseconds: 300),
|
|
curve: Curves.easeOut,
|
|
);
|
|
});
|
|
|
|
},
|
|
child: Container(
|
|
width: 120.w,
|
|
height: 63.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(8.w)),
|
|
color: const Color.fromRGBO(117, 98, 249, 1)
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"发送",
|
|
style: TextStyle(
|
|
fontSize: 31.w,
|
|
color: Colors.white
|
|
),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
padding: EdgeInsets.symmetric(vertical: 28.w, horizontal: 56.w),
|
|
color: Colors.white,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
InkWell(
|
|
onTap: (){
|
|
_emojiController.reverse();
|
|
_giftController.reverse();
|
|
_moreController.reverse();
|
|
if (_voiceController.isCompleted) {
|
|
_voiceController.reverse();
|
|
} else {
|
|
_voiceController.forward();
|
|
}
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
child: Image.asset(
|
|
"assets/chat_voice.png",
|
|
width: 39.w,
|
|
height: 39.w,
|
|
),
|
|
),
|
|
InkWell(
|
|
child: Image.asset(
|
|
"assets/chat_video.png",
|
|
width: 39.w,
|
|
height: 39.w,
|
|
),
|
|
),
|
|
InkWell(
|
|
onTap: (){
|
|
_voiceController.reverse();
|
|
_emojiController.reverse();
|
|
_moreController.reverse();
|
|
if (_giftController.isCompleted) {
|
|
_giftController.reverse();
|
|
} else {
|
|
_giftController.forward();
|
|
}
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
child: Image.asset(
|
|
"assets/chat_gift.png",
|
|
width: 39.w,
|
|
height: 39.w,
|
|
),
|
|
),
|
|
InkWell(
|
|
onTap: (){
|
|
_voiceController.reverse();
|
|
_giftController.reverse();
|
|
_moreController.reverse();
|
|
if (_emojiController.isCompleted) {
|
|
_emojiController.reverse();
|
|
} else {
|
|
_emojiController.forward();
|
|
}
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
child: Image.asset(
|
|
"assets/chat_emoji.png",
|
|
width: 39.w,
|
|
height: 39.w,
|
|
),
|
|
),
|
|
InkWell(
|
|
onTap: (){
|
|
_voiceController.reverse();
|
|
_giftController.reverse();
|
|
_emojiController.reverse();
|
|
if (_moreController.isCompleted) {
|
|
_moreController.reverse();
|
|
} else {
|
|
_moreController.forward();
|
|
}
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
child: Image.asset(
|
|
"assets/chat_more.png",
|
|
width: 39.w,
|
|
height: 39.w,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
AnimatedBuilder(
|
|
animation: _voiceAnimation,
|
|
builder: (BuildContext context, child) {
|
|
return Opacity(
|
|
opacity: _voiceAnimation.value,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.translucent,
|
|
onTap: (){},
|
|
child: Container(
|
|
height: 343.w * _voiceAnimation.value,
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
InkWell(
|
|
onTap: (){
|
|
print(1111);
|
|
},
|
|
child: Container(
|
|
width: 196.w,
|
|
height: 196.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(196.w)),
|
|
border: Border.all(width: 1, color: const Color.fromRGBO(117, 98, 249, 1))
|
|
),
|
|
child: Center(
|
|
child: Container(
|
|
width: 184.w,
|
|
height: 184.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(184.w)),
|
|
gradient: LinearGradient(
|
|
begin: Alignment.centerLeft, // 从左开始
|
|
end: Alignment.centerRight, // 到右结束(90度)
|
|
colors: [
|
|
Color.fromRGBO(131, 89, 255, 1), // 紫色
|
|
Color.fromRGBO(61, 138, 224, 1), // 蓝色
|
|
],
|
|
),
|
|
),
|
|
child: Center(
|
|
child: Image.asset(
|
|
"assets/mic_line.png",
|
|
width: 72.w,
|
|
height: 85.w,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 22.w,),
|
|
Text(
|
|
"按住说话",
|
|
style: TextStyle(
|
|
fontSize:23.w,
|
|
color: const Color.fromRGBO(144, 144, 144, 1),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
AnimatedBuilder(
|
|
animation: _giftAnimation,
|
|
builder: (BuildContext context, child) {
|
|
return Opacity(
|
|
opacity: _giftAnimation.value,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.translucent,
|
|
onTap: (){},
|
|
child: Container(
|
|
height: 620.w * _giftAnimation.value,
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
height: 95.w,
|
|
padding: EdgeInsets.only(left: 59.w),
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
"互动",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: const Color.fromRGBO(144, 144, 144, 1)
|
|
),
|
|
),
|
|
SizedBox(width: 80.w,),
|
|
Text(
|
|
"礼物",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: const Color.fromRGBO(117, 98, 249, 1),
|
|
fontWeight: FontWeight.w700
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Swiper(
|
|
autoplay: false,
|
|
itemCount: 6,
|
|
loop: true,
|
|
pagination: const SwiperPagination(
|
|
alignment: Alignment.bottomCenter,
|
|
builder: TDSwiperDotsPagination(
|
|
color: Color.fromRGBO(144, 144, 144, 1),
|
|
activeColor: Color.fromRGBO(77, 77, 77, 1),
|
|
)),
|
|
itemBuilder: (BuildContext context, int index) {
|
|
return Align(
|
|
alignment: Alignment.topCenter,
|
|
child: Wrap(
|
|
children: [
|
|
...giftList.asMap().entries.map((entry){
|
|
return GiftItem(item: entry.value, active: activeGift, index: entry.key, changeActive: changeActive);
|
|
}),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Image.asset(
|
|
"assets/rose_gift.png",
|
|
width: 43.w,
|
|
height: 43.w,
|
|
),
|
|
SizedBox(width: 17.w,),
|
|
Text(
|
|
"9",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1)
|
|
),
|
|
),
|
|
SizedBox(width: 24.w,),
|
|
Image.asset(
|
|
"assets/first_pay.png",
|
|
width: 137.w,
|
|
height: 66.w,
|
|
),
|
|
],
|
|
) ,
|
|
|
|
ValueListenableBuilder<int>(
|
|
valueListenable: giftNum,
|
|
builder: (context, num, _) {
|
|
return Row(
|
|
children: [
|
|
// TDStepper(
|
|
// theme: TDStepperTheme.filled,
|
|
// value: giftNum,
|
|
// min: 1,
|
|
// onChange: (e){
|
|
// giftNum = e;
|
|
// },
|
|
// ),
|
|
InkWell(
|
|
onTap: (){
|
|
if(giftNum.value <= 1) return;
|
|
giftNum.value -= 1;
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
child: Container(
|
|
width: 29.w,
|
|
height: 29.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(29.w)),
|
|
color: Color.fromRGBO(117, 98, 249, giftNum.value <= 1 ? 0 : 1),
|
|
border: Border.all(width: 1, color: Color.fromRGBO(117, 98, 249, 1))
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"-",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: giftNum.value <= 1 ? Color.fromRGBO(117, 98, 249, 1) : Colors.white,
|
|
height: 1
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: 46.w,
|
|
child: Center(
|
|
child: Text(
|
|
"$num",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1)
|
|
),
|
|
),
|
|
),
|
|
),
|
|
InkWell(
|
|
onTap: (){
|
|
giftNum.value += 1;
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
child: Container(
|
|
width: 29.w,
|
|
height: 29.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(29.w)),
|
|
color: Color.fromRGBO(117, 98, 249, 1)
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"+",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: Colors.white,
|
|
height: 1
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(width: 18.w,),
|
|
Container(
|
|
width: 127.w,
|
|
height: 60.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(60.w)),
|
|
gradient: LinearGradient(
|
|
begin: Alignment.centerLeft, // 左侧开始
|
|
end: Alignment.centerRight, // 右侧结束(90度)
|
|
colors: [
|
|
Color.fromRGBO(61, 138, 224, 1), // 蓝色
|
|
Color.fromRGBO(131, 89, 255, 1), // 紫色
|
|
],
|
|
),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
"赠送",
|
|
style: TextStyle(
|
|
fontSize: 26.w,
|
|
color: Colors.white
|
|
),
|
|
),
|
|
),
|
|
)
|
|
],
|
|
);
|
|
}),
|
|
],
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
|
|
AnimatedBuilder(
|
|
animation: _emojiAnimation,
|
|
builder: (BuildContext context, child) {
|
|
return Opacity(
|
|
opacity: _emojiAnimation.value,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.translucent,
|
|
onTap: (){},
|
|
child: Container(
|
|
height: 490.w * _emojiAnimation.value,
|
|
child: EmojiPicker(
|
|
onEmojiSelected: (Category? category, Emoji emoji) {
|
|
print(category);
|
|
print(emoji.emoji);
|
|
message += emoji.emoji;
|
|
|
|
_messageController.value = TextEditingValue(
|
|
text: message,
|
|
selection: TextSelection.fromPosition(TextPosition(offset: message.length)),
|
|
);
|
|
setState(() {
|
|
|
|
});
|
|
},
|
|
onBackspacePressed: () {
|
|
// Do something when the user taps the backspace button (optional)
|
|
// Set it to null to hide the Backspace-Button
|
|
},
|
|
textEditingController: _controller,
|
|
scrollController: _scrollController,
|
|
config: Config(
|
|
locale: const Locale("zh"),
|
|
height: 490.w * _emojiAnimation.value,
|
|
checkPlatformCompatibility: true,
|
|
viewOrderConfig: const ViewOrderConfig(),
|
|
emojiViewConfig: EmojiViewConfig(
|
|
// Issue: https://github.com/flutter/flutter/issues/28894
|
|
emojiSizeMax: 28 *
|
|
(foundation.defaultTargetPlatform ==
|
|
TargetPlatform.iOS
|
|
? 1.2
|
|
: 1.0),
|
|
noRecents: Text(
|
|
'暂无最近使用',
|
|
style: TextStyle(fontSize: 20, color: Colors.black26),
|
|
textAlign: TextAlign.center,
|
|
)
|
|
),
|
|
skinToneConfig: const SkinToneConfig(),
|
|
categoryViewConfig: const CategoryViewConfig(),
|
|
bottomActionBarConfig: const BottomActionBarConfig(
|
|
enabled: false
|
|
),
|
|
searchViewConfig: const SearchViewConfig(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
|
|
AnimatedBuilder(
|
|
animation: _moreAnimation,
|
|
builder: (BuildContext context, child) {
|
|
return Opacity(
|
|
opacity: _moreAnimation.value,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.translucent,
|
|
onTap: (){},
|
|
child: Container(
|
|
width: 750.w,
|
|
padding: EdgeInsets.symmetric(horizontal: 53.w),
|
|
height: 343.w * _moreAnimation.value,
|
|
color: Colors.white,
|
|
child: Wrap(
|
|
spacing: 90.w,
|
|
|
|
children: [
|
|
InkWell(
|
|
onTap: () async {
|
|
|
|
int sdk = 0;
|
|
if (Platform.isAndroid) {
|
|
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
|
final androidInfo = await deviceInfo.androidInfo;
|
|
sdk = androidInfo.version.sdkInt;
|
|
}
|
|
var res;
|
|
if(sdk <= 32){
|
|
res = await handlePermission(
|
|
context,
|
|
"为了上传发送图片,我们需要获取您设备的相册读取权限",
|
|
[
|
|
Permission.photos,
|
|
]
|
|
);
|
|
} else {
|
|
res = true;
|
|
}
|
|
if(res){
|
|
final ImagePicker picker = ImagePicker();
|
|
final List<XFile> list = await picker.pickMultiImage(
|
|
|
|
// limit: 5,
|
|
);
|
|
// setState(() {
|
|
// imageList.addAll(list);
|
|
// });
|
|
} else {
|
|
toast("权限获取失败", context);
|
|
}
|
|
},
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
width: 100.w,
|
|
height: 100.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
color: const Color.fromRGBO(247, 247, 247, 1)
|
|
),
|
|
child: Center(
|
|
child: Image.asset(
|
|
"assets/img_icon.png",
|
|
width: 69.w,
|
|
height: 69.w,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 13.w,),
|
|
Text(
|
|
"图片",
|
|
style: TextStyle(
|
|
fontSize: 23.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1)
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
InkWell(
|
|
onTap: () async {
|
|
var res = await handlePermission(
|
|
context,
|
|
"为了拍照上传发送图片,我们需要获取您设备的相机和相册存取权限",
|
|
[
|
|
Permission.camera,
|
|
Permission.photos,
|
|
Permission.storage,
|
|
]
|
|
);
|
|
if(res){
|
|
final ImagePicker _picker = ImagePicker();
|
|
final XFile? image = await _picker.pickImage(source: ImageSource.camera);
|
|
|
|
if (image != null) {
|
|
// 这里你可以使用image.path来访问图片的本地路径
|
|
// 或者使用image.readAsBytes()来获取图片的字节数据
|
|
// 例如,你可以将图片显示在屏幕上,或者上传到服务器
|
|
// 这里只打印图片路径作为示例
|
|
print(image.path);
|
|
}
|
|
} else {
|
|
toast("权限获取失败", context);
|
|
}
|
|
},
|
|
child: Column(
|
|
children: [
|
|
Container(
|
|
width: 100.w,
|
|
height: 100.w,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
color: const Color.fromRGBO(247, 247, 247, 1)
|
|
),
|
|
child: Center(
|
|
child: Image.asset(
|
|
"assets/camera_icon.png",
|
|
width: 69.w,
|
|
height: 69.w,
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 13.w,),
|
|
Text(
|
|
"相机",
|
|
style: TextStyle(
|
|
fontSize: 23.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1)
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
class GiftItem extends StatefulWidget {
|
|
final Map item;
|
|
final int active;
|
|
final int index;
|
|
final void Function(int) changeActive;
|
|
const GiftItem({super.key, required this.item, required this.active, required this.index, required this.changeActive, });
|
|
|
|
@override
|
|
State<GiftItem> createState() => _GiftItemState();
|
|
}
|
|
|
|
class _GiftItemState extends State<GiftItem> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return InkWell(
|
|
onTap: (){
|
|
widget.changeActive(widget.index);
|
|
},
|
|
child: Container(
|
|
width: 167.w,
|
|
height: 189.w,
|
|
padding: EdgeInsets.only(top: 21.w),
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(18.w)),
|
|
color: Color.fromRGBO(117, 98, 249, widget.active == widget.index ? .2 : 0),
|
|
border: Border.all(width: 1, color: Color.fromRGBO(117, 98, 249, widget.active == widget.index ? 1 : 0))
|
|
),
|
|
child: Column(
|
|
children: [
|
|
Image.asset(
|
|
widget.item["icon"],
|
|
width: 82.w,
|
|
height: 82.w,
|
|
),
|
|
SizedBox(height: 15.w,),
|
|
Text(
|
|
widget.item["title"],
|
|
style: TextStyle(
|
|
fontSize: 22.w,
|
|
color: const Color.fromRGBO(51, 51, 51, 1)
|
|
),
|
|
),
|
|
SizedBox(height: 2.w,),
|
|
Text(
|
|
"${widget.item["price"]}支",
|
|
style: TextStyle(
|
|
fontSize: 15.w,
|
|
color: const Color.fromRGBO(144, 144, 144, 1)
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|