diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 345b4a5..a2ad459 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -2,6 +2,8 @@
+
+
LaunchScreen
UIMainStoryboardFile
Main
+ NSPhotoLibraryUsageDescription
+ Replace with your permission description.
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
diff --git a/lib/controller/message/chat_controller.dart b/lib/controller/message/chat_controller.dart
index 98473b4..c5cee71 100644
--- a/lib/controller/message/chat_controller.dart
+++ b/lib/controller/message/chat_controller.dart
@@ -65,6 +65,25 @@ class ChatController extends GetxController {
}
}
+ /// 发送图片消息
+ Future sendImageMessage(String imagePath) async {
+ try {
+ final message = await IMManager.instance.sendImageMessage(imagePath, userId);
+ if (message != null) {
+ // 发送成功后将消息添加到列表开头
+ messages.insert(0, message);
+ update();
+ return true;
+ }
+ return false;
+ } catch (e) {
+ if (Get.isLogEnable) {
+ Get.log('发送图片消息失败: $e');
+ }
+ return false;
+ }
+ }
+
/// 获取消息列表
Future fetchMessages({bool loadMore = false}) async {
try {
diff --git a/lib/pages/message/chat_page.dart b/lib/pages/message/chat_page.dart
index a1749e3..a673afa 100644
--- a/lib/pages/message/chat_page.dart
+++ b/lib/pages/message/chat_page.dart
@@ -80,6 +80,12 @@ class ChatPage extends StatelessWidget {
onSendMessage: (message) async {
await controller.sendMessage(message);
},
+ onImageSelected: (imagePaths) async {
+ // 为每个图片路径调用控制器的方法发送图片消息
+ for (var imagePath in imagePaths) {
+ await controller.sendImageMessage(imagePath);
+ }
+ },
),
],
),
diff --git a/lib/widget/message/chat_input_bar.dart b/lib/widget/message/chat_input_bar.dart
index c3e69cc..79622a0 100644
--- a/lib/widget/message/chat_input_bar.dart
+++ b/lib/widget/message/chat_input_bar.dart
@@ -4,11 +4,13 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import '../../generated/assets.dart';
+import 'more_options_view.dart';
class ChatInputBar extends StatefulWidget {
final ValueChanged onSendMessage;
+ final ValueChanged>? onImageSelected;
- const ChatInputBar({required this.onSendMessage, super.key});
+ const ChatInputBar({required this.onSendMessage, this.onImageSelected, super.key});
@override
State createState() => _ChatInputBarState();
@@ -38,6 +40,26 @@ class _ChatInputBarState extends State {
});
}
+ void _handleImageTap(List imagePaths) {
+ if (Get.isLogEnable) {
+ Get.log("选择了图片: $imagePaths");
+ }
+ // 将图片路径列表传递给父组件
+ if (widget.onImageSelected != null) {
+ widget.onImageSelected!(imagePaths);
+ }
+ }
+
+ void _handleCameraTap(String imagePath) {
+ if (Get.isLogEnable) {
+ Get.log("拍摄了照片: $imagePath");
+ }
+ // 将单个图片路径包装成列表传递给父组件
+ if (widget.onImageSelected != null) {
+ widget.onImageSelected!([imagePath]);
+ }
+ }
+
@override
Widget build(BuildContext context) {
return Column(
@@ -110,80 +132,14 @@ class _ChatInputBarState extends State {
),
),
// 更多选项展开视图
- _buildMoreOptionsView(),
+ MoreOptionsView(
+ isVisible: _isMoreOptionsVisible,
+ onImageSelected: _handleImageTap,
+ onCameraSelected: _handleCameraTap,
+ )
],
);
}
- // 构建更多选项展开视图
- Widget _buildMoreOptionsView() {
- return AnimatedContainer(
- duration: Duration(milliseconds: 300),
- height: _isMoreOptionsVisible ? 180.h : 0,
- color: Colors.white,
- child: _isMoreOptionsVisible
- ? Container(
- padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 20.h),
- child: Column(
- children: [
- SizedBox(height: 10.h),
- // 第一行选项
- Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- // 图片选项
- Column(
- children: [
- Container(
- width: 60.w,
- height: 60.w,
- decoration: BoxDecoration(
- color: Color(0xffF0F5FF),
- borderRadius: BorderRadius.circular(8.w),
- ),
- padding: EdgeInsets.all(10.w),
- child: Image.asset(Assets.imagesPhoto, width: 40.w, height: 40.w),
- ),
- SizedBox(height: 8.h),
- Text(
- "图片",
- style: TextStyle(
- fontSize: 12.sp,
- color: Colors.black,
- ),
- ),
- ],
- ),
- SizedBox(width: 40.w),
- // 相机选项
- Column(
- children: [
- Container(
- width: 60.w,
- height: 60.w,
- decoration: BoxDecoration(
- color: Color(0xffF0F5FF),
- borderRadius: BorderRadius.circular(8.w),
- ),
- padding: EdgeInsets.all(10.w),
- child: Image.asset(Assets.imagesCamera, width: 40.w, height: 40.w),
- ),
- SizedBox(height: 8.h),
- Text(
- "相机",
- style: TextStyle(
- fontSize: 12.sp,
- color: Colors.black,
- ),
- ),
- ],
- ),
- ],
- ),
- ],
- ),
- )
- : null,
- );
- }
+
}
diff --git a/lib/widget/message/more_options_view.dart b/lib/widget/message/more_options_view.dart
new file mode 100644
index 0000000..9dd5750
--- /dev/null
+++ b/lib/widget/message/more_options_view.dart
@@ -0,0 +1,137 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:wechat_assets_picker/wechat_assets_picker.dart';
+import 'package:wechat_camera_picker/wechat_camera_picker.dart';
+
+import '../../generated/assets.dart';
+
+class MoreOptionsView extends StatelessWidget {
+ final bool isVisible;
+ final ValueChanged> onImageSelected;
+ final ValueChanged onCameraSelected;
+
+ const MoreOptionsView({
+ required this.isVisible,
+ required this.onImageSelected,
+ required this.onCameraSelected,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return AnimatedContainer(
+ duration: Duration(milliseconds: 300),
+ height: isVisible ? 180.h : 0,
+ color: Colors.white,
+ child: isVisible
+ ? Container(
+ padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 20.h),
+ child: Column(
+ children: [
+ SizedBox(height: 10.h),
+ // 第一行选项
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ // 图片选项
+ GestureDetector(
+ onTap: () async{
+ try {
+ List? result = await AssetPicker.pickAssets(context);
+ if (result != null && result.isNotEmpty) {
+ // 获取所有选中图片的文件路径
+ List imagePaths = [];
+ for (var asset in result) {
+ final file = await asset.file;
+ if (file != null) {
+ imagePaths.add(file.path);
+ }
+ }
+ if (imagePaths.isNotEmpty) {
+ onImageSelected(imagePaths);
+ }
+ }
+ } catch (e) {
+ if (Get.isLogEnable) {
+ Get.log("选择图片失败: $e");
+ }
+ }
+ },
+ child: Column(
+ children: [
+ Container(
+ width: 60.w,
+ height: 60.w,
+ decoration: BoxDecoration(
+ color: Color(0xffF0F5FF),
+ borderRadius: BorderRadius.circular(8.w),
+ ),
+ padding: EdgeInsets.all(10.w),
+ child: Image.asset(Assets.imagesPhoto, width: 40.w, height: 40.w),
+ ),
+ SizedBox(height: 8.h),
+ Text(
+ "图片",
+ style: TextStyle(
+ fontSize: 12.sp,
+ color: Colors.black,
+ ),
+ ),
+ ],
+ ),
+ ),
+ SizedBox(width: 40.w),
+ // 相机选项
+ GestureDetector(
+ onTap: () async{
+ try {
+ AssetEntity? entity = await CameraPicker.pickFromCamera(
+ context,
+ pickerConfig: const CameraPickerConfig(),
+ );
+ if (entity != null) {
+ // 获取拍摄照片的文件路径
+ final file = await entity.file;
+ if (file != null) {
+ onCameraSelected(file.path);
+ }
+ }
+ } catch (e) {
+ if (Get.isLogEnable) {
+ Get.log("拍照失败: $e");
+ }
+ }
+ },
+ child: Column(
+ children: [
+ Container(
+ width: 60.w,
+ height: 60.w,
+ decoration: BoxDecoration(
+ color: Color(0xffF0F5FF),
+ borderRadius: BorderRadius.circular(8.w),
+ ),
+ padding: EdgeInsets.all(10.w),
+ child: Image.asset(Assets.imagesCamera, width: 40.w, height: 40.w),
+ ),
+ SizedBox(height: 8.h),
+ Text(
+ "相机",
+ style: TextStyle(
+ fontSize: 12.sp,
+ color: Colors.black,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ )
+ : null,
+ );
+ }
+}
\ No newline at end of file
diff --git a/pubspec.lock b/pubspec.lock
index 29dbbaa..9102ef1 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -105,6 +105,46 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "8.12.0"
+ camera:
+ dependency: transitive
+ description:
+ name: camera
+ sha256: dfa8fc5a1adaeb95e7a54d86a5bd56f4bb0e035515354c8ac6d262e35cec2ec8
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.10.6"
+ camera_android:
+ dependency: transitive
+ description:
+ name: camera_android
+ sha256: "8397c4fcec4f4dbafdeff994adc6ed16dcaa4a25f02e70e3b8fbe59c9a88807f"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.10.10+11"
+ camera_avfoundation:
+ dependency: transitive
+ description:
+ name: camera_avfoundation
+ sha256: "34bcd5db30e52414f1f0783c5e3f566909fab14141a21b3b576c78bd35382bf6"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.9.22+4"
+ camera_platform_interface:
+ dependency: transitive
+ description:
+ name: camera_platform_interface
+ sha256: "98cfc9357e04bad617671b4c1f78a597f25f08003089dd94050709ae54effc63"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.12.0"
+ camera_web:
+ dependency: transitive
+ description:
+ name: camera_web
+ sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.3.5"
characters:
dependency: transitive
description:
@@ -257,6 +297,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.1"
+ extended_image:
+ dependency: transitive
+ description:
+ name: extended_image
+ sha256: f6cbb1d798f51262ed1a3d93b4f1f2aa0d76128df39af18ecb77fa740f88b2e0
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "10.0.1"
+ extended_image_library:
+ dependency: transitive
+ description:
+ name: extended_image_library
+ sha256: "1f9a24d3a00c2633891c6a7b5cab2807999eb2d5b597e5133b63f49d113811fe"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "5.0.1"
fake_async:
dependency: transitive
description:
@@ -461,6 +517,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.0"
+ http_client_helper:
+ dependency: transitive
+ description:
+ name: http_client_helper
+ sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.0.0"
http_multi_server:
dependency: transitive
description:
@@ -597,6 +661,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
+ js:
+ dependency: transitive
+ description:
+ name: js
+ sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.7.2"
json_annotation:
dependency: transitive
description:
@@ -693,6 +765,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.6"
+ nested:
+ dependency: transitive
+ description:
+ name: nested
+ sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.0.0"
package_config:
dependency: transitive
description:
@@ -829,6 +909,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
+ photo_manager:
+ dependency: transitive
+ description:
+ name: photo_manager
+ sha256: a0d9a7a9bc35eda02d33766412bde6d883a8b0acb86bbe37dac5f691a0894e8a
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "3.7.1"
+ photo_manager_image_provider:
+ dependency: transitive
+ description:
+ name: photo_manager_image_provider
+ sha256: b6015b67b32f345f57cf32c126f871bced2501236c405aafaefa885f7c821e4f
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.2.0"
platform:
dependency: transitive
description:
@@ -869,6 +965,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.1.0"
+ provider:
+ dependency: transitive
+ description:
+ name: provider
+ sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "6.1.5+1"
pub_semver:
dependency: transitive
description:
@@ -909,6 +1013,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "10.1.3"
+ sensors_plus:
+ dependency: transitive
+ description:
+ name: sensors_plus
+ sha256: "89e2bfc3d883743539ce5774a2b93df61effde40ff958ecad78cd66b1a8b8d52"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "6.1.2"
+ sensors_plus_platform_interface:
+ dependency: transitive
+ description:
+ name: sensors_plus_platform_interface
+ sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.0.1"
shared_preferences:
dependency: transitive
description:
@@ -1098,6 +1218,54 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
+ video_player:
+ dependency: transitive
+ description:
+ name: video_player
+ sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.10.0"
+ video_player_android:
+ dependency: transitive
+ description:
+ name: video_player_android
+ sha256: cf768d02924b91e333e2bc1ff928528f57d686445874f383bafab12d0bdfc340
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.8.17"
+ video_player_avfoundation:
+ dependency: transitive
+ description:
+ name: video_player_avfoundation
+ sha256: "19ed1162a7a5520e7d7791e0b7b73ba03161b6a69428b82e4689e435b325432d"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.8.5"
+ video_player_platform_interface:
+ dependency: transitive
+ description:
+ name: video_player_platform_interface
+ sha256: "57c5d73173f76d801129d0531c2774052c5a7c11ccb962f1830630decd9f24ec"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "6.6.0"
+ video_player_web:
+ dependency: transitive
+ description:
+ name: video_player_web
+ sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "2.4.0"
+ visibility_detector:
+ dependency: transitive
+ description:
+ name: visibility_detector
+ sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "0.4.0+2"
vm_service:
dependency: transitive
description:
@@ -1138,6 +1306,30 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.3"
+ wechat_assets_picker:
+ dependency: "direct main"
+ description:
+ name: wechat_assets_picker
+ sha256: c307e50394c1e6dfcd5c4701e84efb549fce71444fedcf2e671c50d809b3e2a1
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "9.8.0"
+ wechat_camera_picker:
+ dependency: "direct main"
+ description:
+ name: wechat_camera_picker
+ sha256: "776ce32feda72d84b63425533a27d3b822bfb93cc063d2aef3cc6d788769f36b"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "4.4.0"
+ wechat_picker_library:
+ dependency: transitive
+ description:
+ name: wechat_picker_library
+ sha256: "5cb61b9aa935b60da5b043f8446fbb9c5077419f20ccc4856bf444aec4f44bc1"
+ url: "https://pub.flutter-io.cn"
+ source: hosted
+ version: "1.0.7"
xdg_directories:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index ce17b03..5ed3197 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -53,6 +53,8 @@ dependencies:
permission_handler: ^12.0.1
flustars: ^2.0.1
easy_refresh: ^3.4.0
+ wechat_assets_picker: ^9.8.0
+ wechat_camera_picker: ^4.4.0
dev_dependencies:
flutter_test: