Browse Source

优化iM

ios
Jolie 3 months ago
parent
commit
cace9a8505
18 changed files with 724 additions and 183 deletions
  1. 9
      android/app/build.gradle.kts
  2. 4
      ios/Podfile.lock
  3. 31
      ios/Runner.xcodeproj/project.pbxproj
  4. 126
      ios/Runner/Info.plist
  5. 4
      lib/pages/home/content_card.dart
  6. 6
      lib/pages/message/chat_settings_page.dart
  7. 105
      lib/pages/message/conversation_tab.dart
  8. 24
      lib/pages/message/friend_tab.dart
  9. 2
      lib/pages/mine/user_info_page.dart
  10. 85
      lib/widget/message/call_item.dart
  11. 83
      lib/widget/message/gift_item.dart
  12. 82
      lib/widget/message/image_item.dart
  13. 83
      lib/widget/message/room_item.dart
  14. 83
      lib/widget/message/text_item.dart
  15. 82
      lib/widget/message/video_item.dart
  16. 86
      lib/widget/message/voice_item.dart
  17. 8
      location_plugin/example/pubspec.lock
  18. 4
      pubspec.yaml

9
android/app/build.gradle.kts

@ -30,6 +30,11 @@ android {
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
ndk {
// 添加所有常见的 ABI,按优先级排序
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
}
}
signingConfigs {
@ -56,7 +61,7 @@ android {
signingConfig = signingConfigs.getByName("release")
ndk {
abiFilters.clear()
abiFilters += "arm64-v8a"
abiFilters += listOf("armeabi-v7a", "arm64-v8a")
// 或者:abiFilters.add("arm64-v8a")
}
@ -74,7 +79,7 @@ android {
signingConfig = signingConfigs.getByName("release")
ndk {
abiFilters.clear()
abiFilters += "arm64-v8a"
abiFilters += listOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a")
// 或者:abiFilters.add("arm64-v8a")
}

4
ios/Podfile.lock

@ -101,7 +101,7 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- photo_manager (3.8.2):
- photo_manager (3.8.3):
- Flutter
- FlutterMacOS
- record_ios (1.1.0):
@ -236,7 +236,7 @@ SPEC CHECKSUMS:
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 0b743cbb62d8e47eab856f09262bb8c1ddcfe6ba
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
photo_manager: 8f40300912c856ef39d0d533a205afab5fbee62f
photo_manager: 647b6f5c5057632e2d00e2921c6ce3437ded57a9
record_ios: 840d21cce013c5a3b2168b74a54ebdb4136359e2
sensors_plus: 7229095999f30740798f0eeef5cd120357a8f4f2
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6

31
ios/Runner.xcodeproj/project.pbxproj

@ -8,14 +8,14 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
2D2952405A246D6FED52F01C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AFB57A27E7776B3F359A1C5C /* Pods_RunnerTests.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
629D13DAEFC0F1B763022B0C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F143A14201D60D1AB5F91F17 /* Pods_RunnerTests.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
74C4FE64A41BA4C47423BB91 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4B909E9A193D37A26B4444E /* Pods_Runner.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
CA4B8AEFC4889FC29913AC62 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4160400E07E3D928E2B9607F /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -48,7 +48,6 @@
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4160400E07E3D928E2B9607F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
56C88C7D01770BE2DBFDD697 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
682C5B3EB10C94F9A20C1D3D /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
6A05741EC62B5EEBE22A6CF2 /* Runner.entitlements */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
@ -65,7 +64,8 @@
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9B57E2640B7D789CFC5E81D9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
A68585D9660E736DD281FC18 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
F143A14201D60D1AB5F91F17 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AFB57A27E7776B3F359A1C5C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E4B909E9A193D37A26B4444E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -73,7 +73,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
629D13DAEFC0F1B763022B0C /* Pods_RunnerTests.framework in Frameworks */,
2D2952405A246D6FED52F01C /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -81,7 +81,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
CA4B8AEFC4889FC29913AC62 /* Pods_Runner.framework in Frameworks */,
74C4FE64A41BA4C47423BB91 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -91,8 +91,8 @@
18EC60AE150D603E57C4D66F /* Frameworks */ = {
isa = PBXGroup;
children = (
4160400E07E3D928E2B9607F /* Pods_Runner.framework */,
F143A14201D60D1AB5F91F17 /* Pods_RunnerTests.framework */,
E4B909E9A193D37A26B4444E /* Pods_Runner.framework */,
AFB57A27E7776B3F359A1C5C /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -504,8 +504,13 @@
PRODUCT_BUNDLE_IDENTIFIER = com.juxinghe.touchme;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@ -692,9 +697,14 @@
PRODUCT_BUNDLE_IDENTIFIER = com.juxinghe.touchme;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@ -720,8 +730,13 @@
PRODUCT_BUNDLE_IDENTIFIER = com.juxinghe.touchme;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

126
ios/Runner/Info.plist

@ -1,72 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>趣恋恋</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>dating_touchme_app</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array/>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
<string>weixinULAPI</string>
<string>weixinURLParamsAPI</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>趣恋恋</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>dating_touchme_app</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array/>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
<string>weixinULAPI</string>
<string>weixinURLParamsAPI</string>
</array>
<key>LSRequiresIPhoneOS</key>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择和发送图片、视频</string>
<key>NSCameraUsageDescription</key>
<string>需要访问相机以拍摄照片和视频</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风以录制语音和视频</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIStatusBarHidden</key>
<false/>
</dict>
<key>NSCameraUsageDescription</key>
<string>需要访问相机以拍摄照片和视频</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风以录制语音和视频</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择和发送图片、视频</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
</dict>
</plist>

4
lib/pages/home/content_card.dart

@ -48,7 +48,7 @@ class _CardHeader extends StatelessWidget {
),
),
errorWidget: (context, url, error) => Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
width: 60,
height: 60,
fit: BoxFit.cover,
@ -397,7 +397,7 @@ class _NetworkImageWidget extends StatelessWidget {
),
),
errorWidget: (context, url, error) => Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
width: 60,
height: 60,
fit: BoxFit.cover,

6
lib/pages/message/chat_settings_page.dart

@ -133,7 +133,7 @@ class ChatSettingsPage extends StatelessWidget {
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
width: 50.w,
height: 50.w,
fit: BoxFit.cover,
@ -141,7 +141,7 @@ class ChatSettingsPage extends StatelessWidget {
},
)
: Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
width: 50.w,
height: 50.w,
fit: BoxFit.cover,
@ -187,7 +187,7 @@ class ChatSettingsPage extends StatelessWidget {
children: [
ClipOval(
child: Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
width: 50.w,
height: 50.w,
fit: BoxFit.cover,

105
lib/pages/message/conversation_tab.dart

@ -4,7 +4,10 @@ import 'package:dating_touchme_app/generated/assets.dart';
import 'package:get/get.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../controller/message/conversation_controller.dart';
import '../../widget/message/emoji_text_widget.dart';
import '../../config/emoji_config.dart';
class ConversationTab extends StatefulWidget {
const ConversationTab({super.key});
@ -151,7 +154,7 @@ class _ConversationTabState extends State<ConversationTab>
? ClipRRect(
borderRadius: BorderRadius.circular(28),
child: Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
width: 56,
height: 56,
fit: BoxFit.cover,
@ -195,17 +198,9 @@ class _ConversationTabState extends State<ConversationTab>
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
child: _buildLastMessageContent(
controller.getLastMessageContent(message),
style: TextStyle(
fontSize: 14,
color: (message != null &&
message.direction == MessageDirection.SEND &&
message.status == MessageStatus.FAIL)
? Color.fromRGBO(248, 85, 66, 1) //
: Colors.grey,
),
overflow: TextOverflow.ellipsis,
message,
),
),
if (unreadCount > 0)
@ -268,6 +263,94 @@ class _ConversationTabState extends State<ConversationTab>
);
}
//
Widget _buildLastMessageContent(String content, EMMessage? message) {
//
final isFailed = message != null &&
message.direction == MessageDirection.SEND &&
message.status == MessageStatus.FAIL;
//
final containsEmoji = EmojiTextHelper.containsEmoji(content);
if (containsEmoji && !isFailed) {
// 使 widget
return _buildSingleLineEmojiText(
content,
TextStyle(
fontSize: 14.sp,
color: Colors.grey,
),
);
} else {
// 使 Text
return Text(
content,
style: TextStyle(
fontSize: 14.sp,
color: isFailed
? Color.fromRGBO(248, 85, 66, 1) //
: Colors.grey,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
);
}
}
//
Widget _buildSingleLineEmojiText(String text, TextStyle textStyle) {
final RegExp emojiRegex = RegExp(r'\[emoji:(\d+)\]');
final List<InlineSpan> spans = [];
int lastMatchEnd = 0;
final matches = emojiRegex.allMatches(text);
for (final match in matches) {
//
if (match.start > lastMatchEnd) {
final textPart = text.substring(lastMatchEnd, match.start);
spans.add(TextSpan(text: textPart, style: textStyle));
}
// 使 WidgetSpan
final emojiId = match.group(1);
if (emojiId != null) {
final emoji = EmojiConfig.getEmojiById(emojiId);
if (emoji != null) {
spans.add(WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w),
child: Image.asset(
emoji.path,
width: 16.w,
height: 16.w,
fit: BoxFit.contain,
),
),
));
} else {
//
spans.add(TextSpan(text: match.group(0)!, style: textStyle));
}
}
lastMatchEnd = match.end;
}
//
if (lastMatchEnd < text.length) {
final textPart = text.substring(lastMatchEnd);
spans.add(TextSpan(text: textPart, style: textStyle));
}
return RichText(
text: TextSpan(children: spans),
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
}
@override
bool get wantKeepAlive => true;
}

24
lib/pages/message/friend_tab.dart

@ -22,7 +22,7 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
{
"id": 1,
"name": "叫我大王",
"avatar": Assets.imagesAvatarsExample,
"avatar": Assets.imagesUserAvatar,
"age": 30,
"location": "广州",
"gender": "female",
@ -31,7 +31,7 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
{
"id": 2,
"name": "林园园",
"avatar": Assets.imagesAvatarsExample,
"avatar": Assets.imagesUserAvatar,
"age": 28,
"location": "深圳",
"gender": "female",
@ -40,7 +40,7 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
{
"id": 3,
"name": "张雪",
"avatar": Assets.imagesAvatarsExample,
"avatar": Assets.imagesUserAvatar,
"age": 25,
"location": "北京",
"gender": "female",
@ -53,37 +53,37 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
// {
// "id": 1,
// "name": "林园园",
// "avatar": Assets.imagesAvatarsExample,
// "avatar": Assets.imagesUserAvatar,
// "isOnline": true,
// },
// {
// "id": 2,
// "name": "李晖",
// "avatar": Assets.imagesAvatarsExample,
// "avatar": Assets.imagesUserAvatar,
// "isOnline": false,
// },
// {
// "id": 3,
// "name": "李哲",
// "avatar": Assets.imagesAvatarsExample,
// "avatar": Assets.imagesUserAvatar,
// "isOnline": false,
// },
// {
// "id": 4,
// "name": "李夏",
// "avatar": Assets.imagesAvatarsExample,
// "avatar": Assets.imagesUserAvatar,
// "isOnline": true,
// },
// {
// "id": 5,
// "name": "张雪",
// "avatar": Assets.imagesAvatarsExample,
// "avatar": Assets.imagesUserAvatar,
// "isOnline": false,
// },
// {
// "id": 6,
// "name": "王强",
// "avatar": Assets.imagesAvatarsExample,
// "avatar": Assets.imagesUserAvatar,
// "isOnline": true,
// },
// ];
@ -93,7 +93,7 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
{
"id": 1,
"name": "李晖",
"avatar": Assets.imagesAvatarsExample,
"avatar": Assets.imagesUserAvatar,
"age": 32,
"location": "上海",
"gender": "male",
@ -101,7 +101,7 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
{
"id": 2,
"name": "王强",
"avatar": Assets.imagesAvatarsExample,
"avatar": Assets.imagesUserAvatar,
"age": 29,
"location": "杭州",
"gender": "male",
@ -109,7 +109,7 @@ class _FriendTabState extends State<FriendTab> with TickerProviderStateMixin {
{
"id": 3,
"name": "李哲",
"avatar": Assets.imagesAvatarsExample,
"avatar": Assets.imagesUserAvatar,
"age": 27,
"location": "成都",
"gender": "male",

2
lib/pages/mine/user_info_page.dart

@ -320,7 +320,7 @@ class _UserInfoState extends State<UserInfoPage> {
fit: BoxFit.cover,
)
: Image.asset(
Assets.imagesAvatarsExample,
Assets.imagesUserAvatar,
fit: BoxFit.cover,
)),
),

85
lib/widget/message/call_item.dart

@ -2,8 +2,11 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:get/get.dart';
import '../../generated/assets.dart';
import '../../controller/global.dart';
import '../../controller/message/chat_controller.dart';
///
enum CallType {
@ -43,7 +46,7 @@ class CallItem extends StatelessWidget {
final content = textBody.content;
// [CALL:]
if (content != null && content.startsWith('[CALL:]')) {
if (content.startsWith('[CALL:]')) {
final jsonStr = content.substring(7); // '[CALL:]'
return jsonDecode(jsonStr) as Map<String, dynamic>;
}
@ -256,16 +259,76 @@ class CallItem extends StatelessWidget {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (isSentByMe) {
// 使
// attributes
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

83
lib/widget/message/gift_item.dart

@ -3,8 +3,11 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:get/get.dart';
import '../../generated/assets.dart';
import '../../controller/global.dart';
import '../../controller/message/chat_controller.dart';
class GiftItem extends StatelessWidget {
final EMMessage message;
@ -235,16 +238,76 @@ class GiftItem extends StatelessWidget {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (isSentByMe) {
// 使
// attributes
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

82
lib/widget/message/image_item.dart

@ -6,6 +6,8 @@ import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:dating_touchme_app/pages/message/image_viewer_page.dart';
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/controller/message/chat_controller.dart';
class ImageItem extends StatefulWidget {
final EMImageMessageBody imageBody;
@ -593,16 +595,76 @@ class _ImageItemState extends State<ImageItem> {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (widget.isSentByMe) {
// 使
// attributes
try {
final attributes = widget.message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
final attributes = widget.message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

83
lib/widget/message/room_item.dart

@ -5,8 +5,9 @@ import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:get/get.dart';
import '../../generated/assets.dart';
import '../../pages/discover/live_room_page.dart';
import '../../controller/discover/room_controller.dart';
import '../../controller/global.dart';
import '../../controller/message/chat_controller.dart';
class RoomItem extends StatelessWidget {
final EMMessage message;
@ -298,16 +299,76 @@ class RoomItem extends StatelessWidget {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (isSentByMe) {
// 使
// attributes
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

83
lib/widget/message/text_item.dart

@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:get/get.dart';
import '../../../generated/assets.dart';
import '../../../controller/global.dart';
import '../../../controller/message/chat_controller.dart';
import 'emoji_text_widget.dart';
class TextItem extends StatelessWidget {
@ -122,16 +125,76 @@ class TextItem extends StatelessWidget {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (isSentByMe) {
// 使
// attributes
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
final attributes = message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

82
lib/widget/message/video_item.dart

@ -8,6 +8,8 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:video_player/video_player.dart';
import 'package:dating_touchme_app/pages/message/video_player_page.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/controller/message/chat_controller.dart';
class VideoItem extends StatefulWidget {
final EMVideoMessageBody videoBody;
@ -396,16 +398,76 @@ class _VideoItemState extends State<VideoItem> {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (widget.isSentByMe) {
// 使
// attributes
try {
final attributes = widget.message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
final attributes = widget.message.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

86
lib/widget/message/voice_item.dart

@ -10,6 +10,8 @@ import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import '../../../generated/assets.dart';
import '../../../controller/message/voice_player_manager.dart';
import '../../../controller/global.dart';
import '../../../controller/message/chat_controller.dart';
class VoiceItem extends StatefulWidget {
final EMVoiceMessageBody voiceBody;
@ -342,16 +344,80 @@ class _VoiceItemState extends State<VoiceItem> with TickerProviderStateMixin {
//
Widget _buildAvatar() {
return Container(
width: 40.w,
height: 40.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.w),
image: DecorationImage(
image: AssetImage(Assets.imagesAvatarsExample),
fit: BoxFit.cover,
),
),
String? avatarUrl;
if (widget.isSentByMe) {
// 使
// attributes
try {
if (widget.message != null) {
final attributes = widget.message!.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
}
} catch (e) {
//
}
// 使
if (avatarUrl == null || avatarUrl.isEmpty) {
avatarUrl = GlobalData().userData?.profilePhoto;
}
} else {
// 使
try {
if (widget.message != null) {
final attributes = widget.message!.attributes;
if (attributes != null) {
avatarUrl = attributes['sender_avatarUrl'] as String? ??
attributes['avatarUrl'] as String?;
}
}
} catch (e) {
//
}
// ChatController
if ((avatarUrl == null || avatarUrl.isEmpty)) {
try {
// Get ChatController
final chatController = Get.find<ChatController>();
avatarUrl = chatController.userAvatarUrl;
} catch (e) {
// ChatController
}
}
}
// URL
if (avatarUrl != null && avatarUrl.isNotEmpty) {
avatarUrl = avatarUrl.trim().replaceAll('`', '');
}
return ClipOval(
child: avatarUrl != null && avatarUrl.isNotEmpty
? Image.network(
avatarUrl,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
);
},
)
: Image.asset(
Assets.imagesUserAvatar,
width: 40.w,
height: 40.w,
fit: BoxFit.cover,
),
);
}

8
location_plugin/example/pubspec.lock

@ -173,10 +173,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.16.0"
version: "1.17.0"
path:
dependency: transitive
description:
@ -266,10 +266,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.6"
version: "0.7.7"
typed_data:
dependency: transitive
description:

4
pubspec.yaml

@ -47,7 +47,6 @@ dependencies:
dio: ^5.9.0
retrofit: 4.9.0
flutter_native_splash: ^2.4.7
im_flutter_sdk: ^4.15.2
easy_localization: ^3.0.8
flutter_oss_aliyun: ^6.4.2
permission_handler: ^12.0.1
@ -77,7 +76,8 @@ dependencies:
url_launcher: ^6.3.2
wakelock_plus: ^1.4.0
pinput: ^6.0.1
im_flutter_sdk: 4.15.2
dev_dependencies:
flutter_test:
sdk: flutter

Loading…
Cancel
Save