|
|
|
@ -10,15 +10,48 @@ import '../../generated/assets.dart'; |
|
|
|
import '../../../widget/message/chat_input_bar.dart'; |
|
|
|
import '../../../widget/message/message_item.dart'; |
|
|
|
|
|
|
|
class ChatPage extends StatelessWidget { |
|
|
|
class ChatPage extends StatefulWidget { |
|
|
|
final String userId; |
|
|
|
|
|
|
|
const ChatPage({required this.userId, super.key}); |
|
|
|
|
|
|
|
@override |
|
|
|
State<ChatPage> createState() => _ChatPageState(); |
|
|
|
} |
|
|
|
|
|
|
|
class _ChatPageState extends State<ChatPage> { |
|
|
|
final ScrollController _scrollController = ScrollController(); |
|
|
|
bool _isLoadingMore = false; |
|
|
|
late ChatController _controller; |
|
|
|
|
|
|
|
@override |
|
|
|
void initState() { |
|
|
|
super.initState(); |
|
|
|
// 初始化 controller |
|
|
|
_controller = Get.put(ChatController(userId: widget.userId)); |
|
|
|
|
|
|
|
// 监听滚动,当滚动到顶部时加载更多消息 |
|
|
|
_scrollController.addListener(() { |
|
|
|
if (_scrollController.hasClients && |
|
|
|
_scrollController.position.pixels >= |
|
|
|
_scrollController.position.maxScrollExtent - 100 && |
|
|
|
!_isLoadingMore && |
|
|
|
_controller.messages.isNotEmpty) { |
|
|
|
_loadMoreMessages(); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@override |
|
|
|
void dispose() { |
|
|
|
_scrollController.dispose(); |
|
|
|
super.dispose(); |
|
|
|
} |
|
|
|
|
|
|
|
@override |
|
|
|
Widget build(BuildContext context) { |
|
|
|
return GetBuilder<ChatController>( |
|
|
|
init: ChatController(userId: userId), |
|
|
|
init: _controller, |
|
|
|
builder: (controller) { |
|
|
|
return WillPopScope( |
|
|
|
onWillPop: () async { |
|
|
|
@ -57,6 +90,7 @@ class ChatPage extends StatelessWidget { |
|
|
|
}, |
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
child: ListView.builder( |
|
|
|
controller: _scrollController, |
|
|
|
reverse: true, |
|
|
|
padding: EdgeInsets.all(16.w), |
|
|
|
itemCount: controller.messages.length, |
|
|
|
@ -79,34 +113,53 @@ class ChatPage extends StatelessWidget { |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
// 使用抽离的聊天输入栏组件 |
|
|
|
ChatInputBar( |
|
|
|
onSendMessage: (message) async { |
|
|
|
await controller.sendMessage(message); |
|
|
|
}, |
|
|
|
onImageSelected: (imagePaths) async { |
|
|
|
// 为每个图片路径调用控制器的方法发送图片消息 |
|
|
|
for (var imagePath in imagePaths) { |
|
|
|
await controller.sendImageMessage(imagePath); |
|
|
|
} |
|
|
|
}, |
|
|
|
onVoiceRecorded: (filePath, seconds) async { |
|
|
|
// 处理语音录音完成,回传文件路径和秒数 |
|
|
|
await controller.sendVoiceMessage(filePath, seconds); |
|
|
|
}, |
|
|
|
onVideoRecorded: (filePath, duration) async { |
|
|
|
print('🎬 [ChatPage] 收到视频录制/选择回调'); |
|
|
|
print('文件路径: $filePath'); |
|
|
|
print('时长: $duration 秒'); |
|
|
|
// 处理视频录制/选择完成,回传文件路径和时长 |
|
|
|
await controller.sendVideoMessage(filePath, duration); |
|
|
|
}, |
|
|
|
), |
|
|
|
], |
|
|
|
// 使用抽离的聊天输入栏组件 |
|
|
|
ChatInputBar( |
|
|
|
onSendMessage: (message) async { |
|
|
|
await controller.sendMessage(message); |
|
|
|
}, |
|
|
|
onImageSelected: (imagePaths) async { |
|
|
|
// 为每个图片路径调用控制器的方法发送图片消息 |
|
|
|
for (var imagePath in imagePaths) { |
|
|
|
await controller.sendImageMessage(imagePath); |
|
|
|
} |
|
|
|
}, |
|
|
|
onVoiceRecorded: (filePath, seconds) async { |
|
|
|
// 处理语音录音完成,回传文件路径和秒数 |
|
|
|
await controller.sendVoiceMessage(filePath, seconds); |
|
|
|
}, |
|
|
|
onVideoRecorded: (filePath, duration) async { |
|
|
|
print('🎬 [ChatPage] 收到视频录制/选择回调'); |
|
|
|
print('文件路径: $filePath'); |
|
|
|
print('时长: $duration 秒'); |
|
|
|
// 处理视频录制/选择完成,回传文件路径和时长 |
|
|
|
await controller.sendVideoMessage(filePath, duration); |
|
|
|
}, |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
); |
|
|
|
}, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// 加载更多消息 |
|
|
|
Future<void> _loadMoreMessages() async { |
|
|
|
if (_isLoadingMore) return; |
|
|
|
|
|
|
|
setState(() { |
|
|
|
_isLoadingMore = true; |
|
|
|
}); |
|
|
|
|
|
|
|
try { |
|
|
|
await _controller.fetchMessages(loadMore: true); |
|
|
|
} finally { |
|
|
|
if (mounted) { |
|
|
|
setState(() { |
|
|
|
_isLoadingMore = false; |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |