diff --git a/yinmeng-ios.xcodeproj/project.pbxproj b/yinmeng-ios.xcodeproj/project.pbxproj index 7e8b454..3688510 100644 --- a/yinmeng-ios.xcodeproj/project.pbxproj +++ b/yinmeng-ios.xcodeproj/project.pbxproj @@ -45,6 +45,10 @@ E884E8662B6900C500ADE6EE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E884E8642B6900C500ADE6EE /* Main.storyboard */; }; E884E8682B6900C600ADE6EE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E884E8672B6900C600ADE6EE /* Assets.xcassets */; }; E884E86B2B6900C600ADE6EE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E884E8692B6900C600ADE6EE /* LaunchScreen.storyboard */; }; + E89F19452B917DBA0098E797 /* ChatSendVoiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89F19442B917DBA0098E797 /* ChatSendVoiceView.swift */; }; + E89F19472B9197090098E797 /* ChatTimeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89F19462B9197090098E797 /* ChatTimeCell.swift */; }; + E89F19492B919EB80098E797 /* ChatVoiceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89F19482B919EB80098E797 /* ChatVoiceCell.swift */; }; + E89F194B2B919ECB0098E797 /* ChatImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89F194A2B919ECB0098E797 /* ChatImageCell.swift */; }; E8D15A9D2B899E1500369467 /* YMNetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15A9C2B899E1500369467 /* YMNetworkHelper.swift */; }; E8D15A9F2B89AED600369467 /* AuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15A9E2B89AED500369467 /* AuthManager.swift */; }; E8D15AA12B89AF4F00369467 /* UserTokenObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15AA02B89AF4F00369467 /* UserTokenObject.swift */; }; @@ -122,6 +126,10 @@ E884E8672B6900C600ADE6EE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; E884E86A2B6900C600ADE6EE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; E884E86C2B6900C600ADE6EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E89F19442B917DBA0098E797 /* ChatSendVoiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatSendVoiceView.swift; sourceTree = ""; }; + E89F19462B9197090098E797 /* ChatTimeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTimeCell.swift; sourceTree = ""; }; + E89F19482B919EB80098E797 /* ChatVoiceCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatVoiceCell.swift; sourceTree = ""; }; + E89F194A2B919ECB0098E797 /* ChatImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatImageCell.swift; sourceTree = ""; }; E8D15A9C2B899E1500369467 /* YMNetworkHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMNetworkHelper.swift; sourceTree = ""; }; E8D15A9E2B89AED500369467 /* AuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthManager.swift; sourceTree = ""; }; E8D15AA02B89AF4F00369467 /* UserTokenObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTokenObject.swift; sourceTree = ""; }; @@ -202,8 +210,11 @@ E8479E3E2B8DC624009AF878 /* View */ = { isa = PBXGroup; children = ( + E89F19462B9197090098E797 /* ChatTimeCell.swift */, E8E4AB262B902A750096D77C /* ChatList */, E8479E3C2B8DC61F009AF878 /* ChatBaseCell.swift */, + E89F19482B919EB80098E797 /* ChatVoiceCell.swift */, + E89F194A2B919ECB0098E797 /* ChatImageCell.swift */, E8479E472B8DD6E1009AF878 /* ChatTextCell.swift */, E8FF28B52B90ED6C005D2BE7 /* ChatNavView.swift */, ); @@ -511,6 +522,7 @@ E8E4AB202B901CD50096D77C /* ChatMoreMenuView.swift */, E8E4AB222B901E0C0096D77C /* ChatMoreMnueConfig.swift */, E8E4AB242B901E400096D77C /* ChatMoreMenuCell.swift */, + E89F19442B917DBA0098E797 /* ChatSendVoiceView.swift */, ); path = Keyboard; sourceTree = ""; @@ -670,6 +682,7 @@ E86A43E82B884C5E0084C04D /* String+.swift in Sources */, E8D15AA32B89B03D00369467 /* Deserialized.swift in Sources */, E8E4AAB72B8F95CA0096D77C /* AuthAppleManager.swift in Sources */, + E89F19452B917DBA0098E797 /* ChatSendVoiceView.swift in Sources */, E8D15AC22B8C703C00369467 /* UserFunctionView.swift in Sources */, E86A43DA2B877A840084C04D /* AppConfigObject.swift in Sources */, E8D15AA62B89B0C600369467 /* List+.swift in Sources */, @@ -692,10 +705,12 @@ E86A43C82B8743EA0084C04D /* AuthFillDataVC.swift in Sources */, E86A43CD2B874C8E0084C04D /* BaseView.swift in Sources */, E8D15AE82B8CD47100369467 /* WebViewController.swift in Sources */, + E89F194B2B919ECB0098E797 /* ChatImageCell.swift in Sources */, E8D15AA12B89AF4F00369467 /* UserTokenObject.swift in Sources */, 233E515B2B8C849600582F9C /* PlanetStarClickItemView.swift in Sources */, E8FF28B42B90ADBE005D2BE7 /* AppKeys.swift in Sources */, 2311D6A92B8F405F001C70AB /* HomeVoiceChooseTypeView.swift in Sources */, + E89F19492B919EB80098E797 /* ChatVoiceCell.swift in Sources */, E8D15AB62B8B002700369467 /* ChatVC.swift in Sources */, E8E4AB182B9019E50096D77C /* ChatKeyboardView.swift in Sources */, E8E4AB232B901E0C0096D77C /* ChatMoreMnueConfig.swift in Sources */, @@ -717,6 +732,7 @@ E8D15AB02B8AFFCE00369467 /* HomeVoiceVC.swift in Sources */, E8E4AB282B902A9C0096D77C /* ChatListCell.swift in Sources */, E86A43D52B8774B70084C04D /* AuthViewModel.swift in Sources */, + E89F19472B9197090098E797 /* ChatTimeCell.swift in Sources */, E8D15AB32B8B000400369467 /* PlanetStarVC.swift in Sources */, E8FF28B62B90ED6C005D2BE7 /* ChatNavView.swift in Sources */, E8D15A9D2B899E1500369467 /* YMNetworkHelper.swift in Sources */, @@ -881,6 +897,10 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "yinmeng-ios/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "音萌"; + INFOPLIST_KEY_NSCameraUsageDescription = "“音萌”需要您的同意,才可以访问进行拍照,才可以在聊天中分享图片给他人查看,或上传图片以更新头像"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "\"音萌\"需要您的同意,才可以进行语音聊天"; + INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "“音萌”需要您的同意,才可以访问相册并选择图片,然后在聊天中分享图片给他人查看,或上传图片以更新头像"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; @@ -916,6 +936,10 @@ ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "yinmeng-ios/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = "音萌"; + INFOPLIST_KEY_NSCameraUsageDescription = "“音萌”需要您的同意,才可以访问进行拍照,才可以在聊天中分享图片给他人查看,或上传图片以更新头像"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "\"音萌\"需要您的同意,才可以进行语音聊天"; + INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "“音萌”需要您的同意,才可以访问相册并选择图片,然后在聊天中分享图片给他人查看,或上传图片以更新头像"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; diff --git a/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/UserInterfaceState.xcuserstate b/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/UserInterfaceState.xcuserstate index 6c2b1fa..d2e66a9 100644 Binary files a/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/UserInterfaceState.xcuserstate and b/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index bfec6c7..c382daa 100644 --- a/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/yinmeng-ios.xcworkspace/xcuserdata/fengshuo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -16,5 +16,21 @@ stopOnStyle = "0"> + + + + diff --git a/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/Contents.json new file mode 100644 index 0000000..bf128bf --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_more_album@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_more_album@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/chat_more_album@2x.png b/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/chat_more_album@2x.png new file mode 100644 index 0000000..9c6f340 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/chat_more_album@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/chat_more_album@3x.png b/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/chat_more_album@3x.png new file mode 100644 index 0000000..9f81f21 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/chat_more_album.imageset/chat_more_album@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/Contents.json new file mode 100644 index 0000000..ce1bdd7 --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_voice@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_voice@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/chat_voice@2x.png b/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/chat_voice@2x.png new file mode 100644 index 0000000..9f9cce1 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/chat_voice@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/chat_voice@3x.png b/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/chat_voice@3x.png new file mode 100644 index 0000000..2000cee Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/chat_voice.imageset/chat_voice@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/Contents.json new file mode 100644 index 0000000..d0eecfd --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_audio_playing_first@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_audio_playing_first@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/chat_audio_playing_first@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/chat_audio_playing_first@2x.png new file mode 100644 index 0000000..ec4fff3 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/chat_audio_playing_first@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/chat_audio_playing_first@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/chat_audio_playing_first@3x.png new file mode 100644 index 0000000..8e9a468 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_first.imageset/chat_audio_playing_first@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/Contents.json new file mode 100644 index 0000000..1b73338 --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_audio_playing_second@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_audio_playing_second@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/chat_audio_playing_second@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/chat_audio_playing_second@2x.png new file mode 100644 index 0000000..8768677 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/chat_audio_playing_second@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/chat_audio_playing_second@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/chat_audio_playing_second@3x.png new file mode 100644 index 0000000..f2a4fd1 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_second.imageset/chat_audio_playing_second@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/Contents.json new file mode 100644 index 0000000..8827044 --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_audio_playing_third@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_audio_playing_third@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/chat_audio_playing_third@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/chat_audio_playing_third@2x.png new file mode 100644 index 0000000..5d9d85f Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/chat_audio_playing_third@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/chat_audio_playing_third@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/chat_audio_playing_third@3x.png new file mode 100644 index 0000000..f1a0db5 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_audio_playing_third.imageset/chat_audio_playing_third@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/Contents.json new file mode 100644 index 0000000..d89283d --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_voice_record_cancel@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_voice_record_cancel@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/chat_voice_record_cancel@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/chat_voice_record_cancel@2x.png new file mode 100644 index 0000000..e31e8ac Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/chat_voice_record_cancel@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/chat_voice_record_cancel@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/chat_voice_record_cancel@3x.png new file mode 100644 index 0000000..2cc341c Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_cancel.imageset/chat_voice_record_cancel@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/Contents.json new file mode 100644 index 0000000..783320c --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_voice_record_first@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_voice_record_first@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/chat_voice_record_first@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/chat_voice_record_first@2x.png new file mode 100644 index 0000000..8f3f619 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/chat_voice_record_first@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/chat_voice_record_first@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/chat_voice_record_first@3x.png new file mode 100644 index 0000000..3c0a7b9 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_first.imageset/chat_voice_record_first@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/Contents.json new file mode 100644 index 0000000..6c6ba73 --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_voice_record_second@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_voice_record_second@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/chat_voice_record_second@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/chat_voice_record_second@2x.png new file mode 100644 index 0000000..8204f75 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/chat_voice_record_second@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/chat_voice_record_second@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/chat_voice_record_second@3x.png new file mode 100644 index 0000000..d023e06 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_second.imageset/chat_voice_record_second@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/Contents.json new file mode 100644 index 0000000..8d73422 --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "chat_voice_record_third@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "chat_voice_record_third@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/chat_voice_record_third@2x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/chat_voice_record_third@2x.png new file mode 100644 index 0000000..12186c4 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/chat_voice_record_third@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/chat_voice_record_third@3x.png b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/chat_voice_record_third@3x.png new file mode 100644 index 0000000..2f6a5c2 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/chat/voice/chat_voice_record_third.imageset/chat_voice_record_third@3x.png differ diff --git a/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/Contents.json b/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/Contents.json new file mode 100644 index 0000000..9d566ef --- /dev/null +++ b/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "public_avatar@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "public_avatar@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/public_avatar@2x.png b/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/public_avatar@2x.png new file mode 100644 index 0000000..193e477 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/public_avatar@2x.png differ diff --git a/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/public_avatar@3x.png b/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/public_avatar@3x.png new file mode 100644 index 0000000..34508c6 Binary files /dev/null and b/yinmeng-ios/Assets.xcassets/public/public_avatar.imageset/public_avatar@3x.png differ diff --git a/yinmeng-ios/Modules/Chat/ChatVC.swift b/yinmeng-ios/Modules/Chat/ChatVC.swift index 8a71f3f..5ca1ca4 100644 --- a/yinmeng-ios/Modules/Chat/ChatVC.swift +++ b/yinmeng-ios/Modules/Chat/ChatVC.swift @@ -19,8 +19,7 @@ class ChatVC: BaseViewController, HiddenNavigationBarProtocol { public init(session: NIMSession) { vm = ChatViewModel(session: session) super.init(nibName: nil, bundle: nil) -// vm.delegate = self -// NIMSDK.shared().mediaManager.add(self) + vm.delegate = self } required init?(coder: NSCoder) { @@ -33,9 +32,19 @@ class ChatVC: BaseViewController, HiddenNavigationBarProtocol { .darkContent } + override open func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + if NIMSDK.shared().mediaManager.isPlaying() { + NIMSDK.shared().mediaManager.stopPlay() + } + } + override func viewDidLoad() { super.viewDidLoad() - + view.backgroundColor = ThemeColor(hexStr: "#F8F8FB") + requestInfo() + loadChatList() + registerChatCell() let height = ScreenHeight - (ToolBarLastH + NavHeight) chatTableView.frame = CGRect(x: 0, y: NavHeight, width: ScreenWidth, height: height) navView.frame = CGRect(x: 0, y: 0, width: ScreenWidth, height: NavHeight) @@ -47,17 +56,16 @@ class ChatVC: BaseViewController, HiddenNavigationBarProtocol { ///注册cell private func registerChatCell() { chatTableView.register(cellType: ChatTextCell.self) + chatTableView.register(cellType: ChatTimeCell.self) } - - private lazy var chatTableView: UITableView = { let tableView = UITableView(frame: .zero, style: .plain) tableView.delegate = self tableView.dataSource = self tableView.tableFooterView = UIView() tableView.separatorStyle = .none - tableView.backgroundColor = ThemeColor(hexStr: "#F8F8FB") + tableView.backgroundColor = .clear if #available(iOS 11.0, *) { tableView.contentInsetAdjustmentBehavior = .never } @@ -84,6 +92,12 @@ class ChatVC: BaseViewController, HiddenNavigationBarProtocol { // MARK: - ChatKeyboardViewDelegate extension ChatVC: ChatKeyboardViewDelegate { + func keyboard(_ keyboard: ChatKeyboardView, voiceDidFinish path: String) { + vm.sendAudioMessage(filePath: path) { error in + + } + } + func keyboard(_ keyboard: ChatKeyboardView, DidFinish content: String) { ///发送消息 vm.sendTextMessage(text: content) { error in @@ -106,6 +120,138 @@ extension ChatVC: ChatKeyboardViewDelegate { } } +extension ChatVC { + + func requestInfo() { + let params = ["uid": vm.session.sessionId] + RequestGet(path: "user/get", parma: params) { data in + if let info = Deserialized.toModel(with: data) { + self.navView.name = info.nick + } + } fail: { code, msg in + + } + + let par:[String : Any] = ["uid": AuthManager.userUid, "isLikeUid": vm.session.sessionId] + RequestGet(path: "fans/isLike", parma: par) { data in + if let isLike = data as? Bool { + self.navView.isLike = isLike + } + } fail: { code, msg in + + } + } + + func loadChatList() { + + weak var weakSelf = self + vm.queryRoamMsgHasMoreTime_v2 { error, historyEnd, newEnd, models, index in + if let ms = models, ms.count > 0 { + weakSelf?.chatTableView.reloadData() + if weakSelf?.vm.isHistoryAnchorChat == true { + let indexPath = IndexPath(row: index, section: 0) + weakSelf?.chatTableView.scrollToRow(at: indexPath, at: .none, animated: false) + } else { + if let tempArrayJJom = weakSelf?.vm.messageObjects, tempArrayJJom.count > 0 { + DispatchQueue.main.async { + weakSelf?.chatTableView.scrollToRow( + at: IndexPath(row: tempArrayJJom.count - 1, section: 0), + at: .bottom, + animated: false + ) + } + } + } + } else if let err = error { + HUDTool.show(with: err.localizedDescription) + } + } + + } + + private func insertRows() { + let oldRows = chatTableView.numberOfRows(inSection: 0) + if oldRows == 0 { + chatTableView.reloadData() + return + } + if oldRows == vm.messageObjects.count { + chatTableView.reloadData() + return + } + var indexs = [IndexPath]() + for (i, _) in vm.messageObjects.enumerated() { + if i >= oldRows { + indexs.append(IndexPath(row: i, section: 0)) + } + } + + if !indexs.isEmpty { + chatTableView.insertRows(at: indexs, with: .none) + chatTableView.scrollToRow( + at: IndexPath(row: vm.messageObjects.count - 1, section: 0), + at: .bottom, + animated: false + ) + } + } + + public func tableViewDeleteIndexs(_ indexs: [IndexPath]) { + chatTableView.beginUpdates() + chatTableView.deleteRows(at: indexs, with: .none) + chatTableView.endUpdates() + } + + public func tableViewReloadIndexs(_ indexs: [IndexPath]) { + chatTableView.beginUpdates() + chatTableView.reloadRows(at: indexs, with: .none) + chatTableView.endUpdates() + } + +} + +extension ChatVC: ChatViewModelDelegate{ + public func onRecvMessages(_ messages: [NIMMessage]) { + insertRows() + vm.markRead(messages: messages) { error in + + } + } + + public func willSend(_ message: NIMMessage) { + + } + + public func didAppend(_ message: NIMMessage) { + + } + + public func send(_ message: NIMMessage, progress: Float) {} + + public func send(_ message: NIMMessage, didCompleteWithError error: Error?) { + + } + + private func indexPathsWithMessags(_ messages: [NIMMessage]) -> [IndexPath] { + var indexPaths = [IndexPath]() + for messageModel in messages { + for (i, model) in vm.messageObjects.enumerated() { + if model.msg?.messageId == messageModel.messageId { + indexPaths.append(IndexPath(row: i, section: 0)) + } + } + } + return indexPaths + } + + public func onDeleteMessage(_ message: NIMMessage, atIndexs: [IndexPath]) { + if atIndexs.isEmpty { + return + } + tableViewDeleteIndexs(atIndexs) + } +} + extension ChatVC: UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate { public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return vm.messageObjects.count @@ -117,6 +263,9 @@ extension ChatVC: UITableViewDelegate, UITableViewDataSource, UIScrollViewDelega if model?.type == .text { let cell = tableView.dequeueReusableCell(for: indexPath, cellType: ChatTextCell.self) cell.model = model + } else if model?.type == .time { + let cell = tableView.dequeueReusableCell(for: indexPath, cellType: ChatTimeCell.self) + cell.model = model } return UITableViewCell() } diff --git a/yinmeng-ios/Modules/Chat/Keyboard/ChatGrowingTextView.swift b/yinmeng-ios/Modules/Chat/Keyboard/ChatGrowingTextView.swift index 46e6b2e..d11e2c7 100644 --- a/yinmeng-ios/Modules/Chat/Keyboard/ChatGrowingTextView.swift +++ b/yinmeng-ios/Modules/Chat/Keyboard/ChatGrowingTextView.swift @@ -77,7 +77,7 @@ class ChatGrowingTextView: UITextView { self.returnKeyType = .send self.layer.cornerRadius = 4 - self.layer.borderWidth = 1 + self.layer.borderWidth = 0 self.layer.borderColor = ThemeColor(hexStr: "#2C363E").cgColor self.layer.masksToBounds = true // 添加占位控件 diff --git a/yinmeng-ios/Modules/Chat/Keyboard/ChatKeyboardView.swift b/yinmeng-ios/Modules/Chat/Keyboard/ChatKeyboardView.swift index 7fe3ccd..a611ed3 100644 --- a/yinmeng-ios/Modules/Chat/Keyboard/ChatKeyboardView.swift +++ b/yinmeng-ios/Modules/Chat/Keyboard/ChatKeyboardView.swift @@ -6,8 +6,10 @@ // import UIKit - +import NIMSDK protocol ChatKeyboardViewDelegate: NSObjectProtocol { + /// 录音完成 + func keyboard(_ keyboard: ChatKeyboardView, voiceDidFinish path: String) /// 输入完消息 func keyboard(_ keyboard: ChatKeyboardView, DidFinish content: String) /// 键盘收起/弹出 @@ -30,14 +32,14 @@ class ChatKeyboardView: UIView { private let kLeft: CGFloat = 12.0 private let kSpace: CGFloat = 12.0 - private let kViewWH: CGFloat = 25.0 + private let kViewWH: CGFloat = 26.0 private let kLineHeight: CGFloat = 0.75 // MARK: - var lazy weak var delegate: ChatKeyboardViewDelegate? - fileprivate var toolBarHeight: CGFloat = 52.0 + fileprivate var toolBarHeight: CGFloat = (52.0 + SafeAraeBottomHeight) fileprivate var lastTextHeight: CGFloat = 34.0 fileprivate var keyboardHeight: CGFloat = 0.0 @@ -48,14 +50,29 @@ class ChatKeyboardView: UIView { /// 是否弹出了系统键盘 fileprivate var isShowKeyboard = false - /// 更多按钮 + private lazy var sendVoiceBtn: UIButton = { + let button = UIButton(type: .custom) + let w: CGFloat = ScreenWidth - self.kViewWH * 2 - self.kSpace * 3 - self.kSpace + button.frame = CGRect(x: self.kSpace + self.kLeft + self.kViewWH, y: self.kSpace, width: w, height: 36) + button.setTitle("按住说话", for: .normal) + button.setTitle("松开结束", for: .normal) + button.backgroundColor = ThemeColor(hexStr: "F1F1FA") + button.setTitleColor(ThemeColor(hexStr: "#282828"), for: .normal) + button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium) + button.layer.masksToBounds = true + button.layer.cornerRadius = 4 + button.isHidden = true + return button + }() + + /// 语音文字 切换按钮 fileprivate lazy var changeButton : UIButton = { let button = UIButton(type: .custom) let x: CGFloat = self.kLeft - button.frame = CGRect(x: x, y: self.kSpace, width: self.kViewWH, height: self.kViewWH) - button.setImage(UIImage(named: "chat_more"), for: .normal) - button.setImage(UIImage(named: "chat_more"), for: .highlighted) - button.addTarget(self, action: #selector(moreDidAction(_:)), for: .touchUpInside) + button.frame = CGRect(x: x, y: self.kSpace + 5, width: self.kViewWH, height: self.kViewWH) + button.setImage(UIImage(named: "chat_input_text"), for: .normal) + button.setImage(UIImage(named: "chat_voice"), for: .highlighted) + button.addTarget(self, action: #selector(changeDidAction(_:)), for: .touchUpInside) return button }() @@ -63,7 +80,7 @@ class ChatKeyboardView: UIView { fileprivate lazy var moreButton : UIButton = { let button = UIButton(type: .custom) let x: CGFloat = ScreenWidth - self.kViewWH - self.kSpace - button.frame = CGRect(x: x, y: self.kSpace, width: self.kViewWH, height: self.kViewWH) + button.frame = CGRect(x: x, y: self.kSpace + 5, width: self.kViewWH, height: self.kViewWH) button.setImage(UIImage(named: "chat_more"), for: .normal) button.setImage(UIImage(named: "chat_more"), for: .highlighted) button.addTarget(self, action: #selector(moreDidAction(_:)), for: .touchUpInside) @@ -109,11 +126,17 @@ class ChatKeyboardView: UIView { return view }() + private lazy var voiceView: ChatSendVoiceView = { + let view = ChatSendVoiceView() + view.backgroundColor = .clear + return view + }() + // MARK: - life cycle override init(frame: CGRect) { super.init(frame: frame) - + NIMSDK.shared().mediaManager.add(self) setupKeyboardView() registerNotification() } @@ -128,15 +151,23 @@ class ChatKeyboardView: UIView { func setupKeyboardView() { self.backgroundColor = .clear self.isUserInteractionEnabled = true - + addSendVoiceAction() addSubview(toolBarView) toolBarView.addSubview(moreButton) toolBarView.addSubview(changeButton) toolBarView.addSubview(chatTextView) + toolBarView.addSubview(sendVoiceBtn) addSubview(contentView) contentView.addSubview(moreMenuView) } + private func addSendVoiceAction() { + sendVoiceBtn.addTarget(self, action: #selector(audioTouchDownAction), for: .touchDown) + sendVoiceBtn.addTarget(self, action: #selector(audioTouchUpOutsideAction), for: .touchUpOutside) + sendVoiceBtn.addTarget(self, action: #selector(audioTouchUpInsideAction), for: .touchUpInside) + sendVoiceBtn.addTarget(self, action: #selector(audioTouchDragEnterAction), for: .touchDragEnter) + sendVoiceBtn.addTarget(self, action: #selector(audioTouchDragExitAction), for: .touchDragExit) + } // MARK: - 监听键盘通知 private func registerNotification() { @@ -171,18 +202,30 @@ class ChatKeyboardView: UIView { } deinit { - + NIMSDK.shared().mediaManager.remove(self) self.removeObserver(self, forKeyPath: "frame") } } +extension ChatKeyboardView: NIMMediaManagerDelegate { + func recordAudioInterruptionBegin() { + voiceView.cancelAudioRecord() + } + + func recordAudioProgress(_ currentTime: TimeInterval) { + voiceView.updateAudioRecordProgress(recordTime: currentTime) + } + func recordAudio(_ filePath: String?, didCompletedWithError error: Error?) { + if let path = filePath { + delegate?.keyboard(self, voiceDidFinish: path) + } + } +} // MARK: - ChatMoreMenuViewDelegate - extension ChatKeyboardView: ChatMoreMenuViewDelegate { func menu(_ view: ChatMoreMenuView, DidSelected type: ChatMoreMenuType) { - delegate?.keyboard(self, DidMoreMenu: type) } } @@ -209,7 +252,6 @@ extension ChatKeyboardView: UITextViewDelegate { /// 发送消息内容 private func sendChatMessage() { delegate?.keyboard(self, DidFinish: self.chatTextView.text ?? "") - changeKeyboardHeight(height: lastTextHeight) chatTextView.text = "" chatTextView.attributedText = NSAttributedString(string: "") @@ -240,12 +282,12 @@ extension ChatKeyboardView { let option = userInfo["UIKeyboardAnimationCurveUserInfoKey"] as! Int - var changedY = y - self.toolBarHeight - NavHeight - contentHeight + var changedY = y - self.toolBarHeight - contentHeight if (isShowMore) { //显示系统键盘 isShowMore = false self.moreMenuView.isHidden = true self.moreMenuView.hidePageController = true - changedY = y - self.toolBarHeight - NavHeight + changedY = y - self.toolBarHeight } UIView.animate(withDuration: duration, delay: 0, options: UIView.AnimationOptions(rawValue: UIView.AnimationOptions.RawValue(option)), animations: { @@ -270,7 +312,7 @@ extension ChatKeyboardView { isShowKeyboard = false let option = userInfo["UIKeyboardAnimationCurveUserInfoKey"] as! Int - let changedY = ScreenHeight - NavHeight - self.toolBarHeight - SafeAraeBottomHeight - self.contentHeight + let changedY = ScreenHeight - self.toolBarHeight - self.contentHeight UIView.animate(withDuration: duration, delay: 0, options: UIView.AnimationOptions(rawValue: UIView.AnimationOptions.RawValue(option)), animations: { self.frame = CGRect(x: 0, y: changedY, width: ScreenWidth, height: self.toolBarHeight + self.contentHeight) }, completion: nil) @@ -293,10 +335,69 @@ extension ChatKeyboardView { // MARK: - Action extension ChatKeyboardView { + + @objc func audioTouchDownAction() { + sendVoiceBtn.isSelected = true + // 开始录音 + if voiceView.superview == nil { + UIApplication.shared.keyWindow?.addSubview(voiceView) + voiceView.translatesAutoresizingMaskIntoConstraints = false + voiceView.snp.makeConstraints { make in + make.center.equalToSuperview() + } + voiceView.configAudioRecord(imageName: "chat_voice_record_first", title: "手指上滑,取消发送", isAnimation: true) + voiceView.beginAudioRecord() + } + } + + @objc func audioTouchUpOutsideAction() { + sendVoiceBtn.isSelected = false + voiceView.cancelAudioRecord() + voiceView.removeFromSuperview() + } + + @objc func audioTouchUpInsideAction() { + sendVoiceBtn.isSelected = false + voiceView.finishAudioRecord() + voiceView.removeFromSuperview() + } + + @objc func audioTouchDragEnterAction() { + voiceView.configAudioRecord(imageName: "chat_voice_record_first", title: "手指上滑,取消发送", isAnimation: true) + } + + @objc func audioTouchDragExitAction() { + voiceView.configAudioRecord(imageName: "chat_voice_record_cancel", title: "松开手指,取消发送", isAnimation: false) + } + @objc func changeDidAction(_ button: UIButton) { + button.isSelected = !button.isSelected + isShowMore = false + contentView.isHidden = true + moreMenuView.isHidden = true + contentHeight = 0.0 + restToolbarContentHeight(true) + if button.isSelected { + chatTextView.resignFirstResponder() + sendVoiceBtn.isHidden = false + chatTextView.isHidden = true + } else { + chatTextView.becomeFirstResponder() + sendVoiceBtn.isHidden = true + chatTextView.isHidden = false + } + delegate?.keyboard(self, DidBecome: false) + } + /// 更多按钮点击处理 @objc func moreDidAction(_ button: UIButton) { // 如有弹出菜单 if isShowMore { + isShowMore = false + contentView.isHidden = true + moreMenuView.isHidden = true + contentHeight = 0.0 + restToolbarContentHeight(true) + delegate?.keyboard(self, DidBecome: false) return } @@ -314,13 +415,13 @@ extension ChatKeyboardView { /// 更改容器高度 func restToolbarContentHeight(_ isRest: Bool = false) { - var changedY = ScreenHeight - self.toolBarHeight - NavHeight - contentHeight + var changedY = ScreenHeight - self.toolBarHeight - contentHeight if (isRest) { if (isShowMore) { isShowMore = false } - changedY = ScreenHeight - self.toolBarHeight - NavHeight - contentHeight - SafeAraeBottomHeight + changedY = ScreenHeight - self.toolBarHeight - contentHeight } UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseOut, animations: { @@ -355,10 +456,10 @@ extension ChatKeyboardView { isShowMore = false } - let changedY = ScreenHeight - keyboardHeight - toolBarHeight - NavHeight + let changedY = ScreenHeight - keyboardHeight - toolBarHeight self.frame = CGRect(x: 0, y: changedY, width: ScreenWidth, height: toolBarView.height + contentView.height) }else { - let changedY = ScreenHeight - NavHeight - (toolBarView.height + contentView.height) + let changedY = ScreenHeight - (toolBarView.height + contentView.height) self.frame = CGRect(x: 0, y: changedY, width: ScreenWidth, height: toolBarView.height + contentView.height) } diff --git a/yinmeng-ios/Modules/Chat/Keyboard/ChatMoreMenuView.swift b/yinmeng-ios/Modules/Chat/Keyboard/ChatMoreMenuView.swift index 7738c3c..8ed15a2 100644 --- a/yinmeng-ios/Modules/Chat/Keyboard/ChatMoreMenuView.swift +++ b/yinmeng-ios/Modules/Chat/Keyboard/ChatMoreMenuView.swift @@ -67,8 +67,7 @@ class ChatMoreMenuView: UIView { lazy var dataSource: [ChatMoreMnueConfig] = { let configs = [ - ChatMoreMnueConfig(title: "图片", image: "ic_more_album", type: .album), - ChatMoreMnueConfig(title: "拍照", image: "ic_more_camera", type: .camera) + ChatMoreMnueConfig(title: "图片", image: "chat_more_album", type: .album), ] return configs }() @@ -138,7 +137,7 @@ class ChatMoreMenuView: UIView { UIView.animate(withDuration: 0.15, delay: 0, options: .curveEaseOut, animations: { self.pageControl.alpha = 1.0 - self.pageControl.isHidden = false + self.pageControl.isHidden = self.dataSource.count > 8 ? false : true }, completion: nil) DispatchQueue.main.async { diff --git a/yinmeng-ios/Modules/Chat/Keyboard/ChatSendVoiceView.swift b/yinmeng-ios/Modules/Chat/Keyboard/ChatSendVoiceView.swift new file mode 100644 index 0000000..ba2c18e --- /dev/null +++ b/yinmeng-ios/Modules/Chat/Keyboard/ChatSendVoiceView.swift @@ -0,0 +1,124 @@ +// +// ChatSendVoiceView.swift +// yinmeng-ios +// +// Created by MaiMang on 2024/3/1. +// + +import UIKit +import NIMSDK +class ChatSendVoiceView: UIView { + + private var backView: UIView = { + let view = UIView() + view.backgroundColor = .black + view.layer.masksToBounds = true + view.layer.cornerRadius = 10 + return view + }() + + private var logoImageView: UIImageView = { + let imageView = UIImageView() + imageView.isUserInteractionEnabled = true + let firstImage = UIImage(named: "chat_voice_record_first")! + let secondImage = UIImage(named: "chat_voice_record_second")! + let thirdImage = UIImage(named: "chat_voice_record_third")! + imageView.animationImages = [firstImage, secondImage, thirdImage] + imageView.animationDuration = 1 + imageView.animationRepeatCount = .max + return imageView + }() + + private var titleLabel: UILabel = { + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 15) + label.textColor = .white + label.textAlignment = .center + return label + }() + + private var timeLabel: UILabel = { + let label = UILabel() + label.font = UIFont.systemFont(ofSize: 17, weight: .medium) + label.textColor = .white + label.textAlignment = .center + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + loadSubViews() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + func configAudioRecord(imageName: String, title: String, isAnimation: Bool) { + logoImageView.image = UIImage(named: imageName) + if isAnimation { + logoImageView.startAnimating() + } else { + logoImageView.stopAnimating() + } + titleLabel.text = title + } + + func beginAudioRecord() { + timeLabel.text = "00:00" + NIMSDK.shared().mediaManager.record(forDuration: 60) + } + + func cancelAudioRecord() { + timeLabel.text = "00:00" + NIMSDK.shared().mediaManager.cancelRecord() + } + + func finishAudioRecord() { + timeLabel.text = "00:00" + NIMSDK.shared().mediaManager.stopRecord() + } + + func updateAudioRecordProgress(recordTime: TimeInterval) { + let minutes = Int(recordTime) / 60 + let seconds = Int(recordTime) % 60 + timeLabel.text = String(format: "%02d:%02d", minutes, seconds) + } + + // Private Method + + private func loadSubViews() { + addSubview(backView) + backView.addSubview(logoImageView) + backView.addSubview(titleLabel) + backView.addSubview(timeLabel) + + translatesAutoresizingMaskIntoConstraints = false + + self.snp.makeConstraints { make in + make.size.equalTo(CGSize(width: 250, height: 250)) + } + + timeLabel.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().offset(25) + } + + backView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + logoImageView.snp.makeConstraints { make in + make.size.equalTo(CGSize(width: 90, height: 72)) + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(50) + } + + titleLabel.snp.makeConstraints { make in + make.left.right.equalTo(backView).inset(0) + make.top.equalTo(logoImageView.snp.bottom).offset(25) + } + + } +} diff --git a/yinmeng-ios/Modules/Chat/Model/ChatBaseObject.swift b/yinmeng-ios/Modules/Chat/Model/ChatBaseObject.swift index 03797f8..c87644b 100644 --- a/yinmeng-ios/Modules/Chat/Model/ChatBaseObject.swift +++ b/yinmeng-ios/Modules/Chat/Model/ChatBaseObject.swift @@ -12,6 +12,7 @@ public enum SessionType: Int { case text = 1 case image case time + case voice } @@ -66,7 +67,7 @@ class ChatTextObject: ChatBaseObject { let style = NSMutableParagraphStyle() style.lineSpacing = 6 - let attributeStr = NSMutableAttributedString(string: msg?.text ?? "", attributes: [NSAttributedString.Key.font: ChatUIConfig.ui.messageFont, NSAttributedString.Key.paragraphStyle: style]) + let attributeStr = NSMutableAttributedString(string: msg?.text ?? "", attributes: [NSAttributedString.Key.font: ChatUIConfig.ui.messageFont, NSAttributedString.Key.foregroundColor:ThemeColor(hexStr: "#2B2D33"), NSAttributedString.Key.paragraphStyle: style]) attribute = attributeStr let textSize = ChatAttributeTool.boundingRect(attribute: attributeStr, font: ChatUIConfig.ui.messageFont, maxSize: CGSize(width: ChatUIConfig.layout.contentMaxWidth, height: CGFloat.greatestFiniteMagnitude)) @@ -83,23 +84,86 @@ class ChatTextObject: ChatBaseObject { class ChatTimeObject: ChatBaseObject { var text:String = "" - public var attribute: NSMutableAttributedString? required init(msg: NIMMessage?) { super.init(msg: msg) type = .time - let style = NSMutableParagraphStyle() - style.lineSpacing = 6 - let attributeStr = NSMutableAttributedString(string: msg?.text ?? "", attributes: [NSAttributedString.Key.font: ChatUIConfig.ui.messageFont, NSAttributedString.Key.paragraphStyle: style]) - attribute = attributeStr - let textSize = ChatAttributeTool.boundingRect(attribute: attributeStr, font: ChatUIConfig.ui.messageFont, maxSize: CGSize(width: ChatUIConfig.layout.contentMaxWidth, height: CGFloat.greatestFiniteMagnitude)) - - var h = ChatUIConfig.layout.bubbleMinHeight - h = textSize.height + 1 + ChatUIConfig.layout.textInsets.top + ChatUIConfig.layout.textInsets.bottom - if h < 36 { - h = 36 - } - contentSize = CGSize(width: textSize.width + ChatUIConfig.layout.textInsets.left + ChatUIConfig.layout.textInsets.right + 1, height: h) - - height = Float(contentSize.height + ChatUIConfig.layout.cellContentInsets.bottom + ChatUIConfig.layout.cellContentInsets.top) + text = timestrToTimeSecond("\(msg?.timestamp ?? 0)") + contentSize = CGSize(width: ScreenWidth, height: 30) + height = Float(50) } } + +class ChatImageObject: ChatBaseObject { + var url:String = "" + required init(msg: NIMMessage?) { + super.init(msg: msg) + type = .image + if let content = msg?.messageObject as? NIMImageObject { + url = content.url ?? content.thumbUrl ?? "" + } + contentSize = CGSize(width: 200 , height: 200) + height = Float(200 + ChatUIConfig.layout.cellContentInsets.bottom + ChatUIConfig.layout.cellContentInsets.top) + } +} + +class ChatVoiceObject: ChatBaseObject { + var filPath:String = "" + var duartion:Int = 0 + required init(msg: NIMMessage?) { + super.init(msg: msg) + type = .voice + let voiceHeight = 30.0 + if let content = msg?.messageObject as? NIMAudioObject { + let scale = 2*atan((Double(content.duration)/1000.0-1)/10.0)/M_PI; + let low = (ChatUIConfig.layout.contentMaxWidth - 180) + let max = (ChatUIConfig.layout.contentMaxWidth - 100) + let width = (max - low) * scale + low + if let path = content.path { + filPath = path + } + duartion = content.duration + contentSize = CGSize(width: width, height: voiceHeight) + height = Float(voiceHeight + ChatUIConfig.layout.cellContentInsets.bottom + ChatUIConfig.layout.cellContentInsets.top) + } else { + let low = (ChatUIConfig.layout.contentMaxWidth - 180) + contentSize = CGSize(width: low , height: voiceHeight) + height = Float(voiceHeight + ChatUIConfig.layout.cellContentInsets.bottom + ChatUIConfig.layout.cellContentInsets.top) + } + } +} + + +func timestrToTimeSecond(_ timeStr: String) -> String { + let interval = TimeInterval(timeStr) ?? 0 + let date = Date(timeIntervalSince1970: interval) + return stringFromDate(date) +} + +func stringFromDate(_ date: Date) -> String { + let currentFormatter = DateFormatter() + if isDateInToday(date) { + currentFormatter.dateFormat = "HH:mm" + } else { + if date.timeIntervalSince1970 > 0 { + currentFormatter.dateFormat = "MM月dd日 HH:mm" + } else { + currentFormatter.dateFormat = "yyyy年MM月dd日 HH:mm" + } + } + let dateString = currentFormatter.string(from: date) + return dateString +} + +func isDateInToday(_ date: Date) -> Bool { + let secondsPerDay: TimeInterval = 24 * 60 * 60 + let today = Date() + let tomorrow = today.addingTimeInterval(secondsPerDay) + let yesterday = today.addingTimeInterval(-secondsPerDay) + + let todayString = String(describing: today).prefix(10) + let yesterdayString = String(describing: yesterday).prefix(10) + let tomorrowString = String(describing: tomorrow).prefix(10) + let dateString = String(describing: date).prefix(10) + + return dateString == todayString +} diff --git a/yinmeng-ios/Modules/Chat/Model/ChatUIConfig.swift b/yinmeng-ios/Modules/Chat/Model/ChatUIConfig.swift index 0717ba3..4f0ecd9 100644 --- a/yinmeng-ios/Modules/Chat/Model/ChatUIConfig.swift +++ b/yinmeng-ios/Modules/Chat/Model/ChatUIConfig.swift @@ -46,9 +46,9 @@ public class ChatUIConfig { /// 头像大小 public var avatarSize: CGFloat = 34.0 /// 聊天cell整体内容距离 - public var cellContentInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) + public var cellContentInsets = UIEdgeInsets(top: 10, left: 16, bottom: 8, right: 16) /// 文本消息距离 - public var textInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15) + public var textInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) /// 内容最大宽度 public var contentMaxWidth: CGFloat = (UIScreen.main.bounds.size.width - 170) /// 图片最大宽高 diff --git a/yinmeng-ios/Modules/Chat/VM/ChatViewModel.swift b/yinmeng-ios/Modules/Chat/VM/ChatViewModel.swift index d2f818c..6ada12b 100644 --- a/yinmeng-ios/Modules/Chat/VM/ChatViewModel.swift +++ b/yinmeng-ios/Modules/Chat/VM/ChatViewModel.swift @@ -406,8 +406,6 @@ public class ChatViewModel: NSObject, let timeMsg = NIMMessage() timeMsg.timestamp = message.timestamp let model = ChatTimeObject(msg: timeMsg) - model.type = .time - model.text = "2024-2-28" return model } @@ -418,11 +416,12 @@ public class ChatViewModel: NSObject, switch message.messageType { case .text: model = ChatTextObject(msg: message) + case .audio: + model = ChatVoiceObject(msg: message) + case .image: + model = ChatImageObject(msg: message) default: return nil - // 未识别的消息类型,默认为文本消息类型,text为未知消息 - // message.text = "未知消息" - // model = MAIMessageContentModel(message: message) } if let uid = message.from { diff --git a/yinmeng-ios/Modules/Chat/View/ChatBaseCell.swift b/yinmeng-ios/Modules/Chat/View/ChatBaseCell.swift index e1d72c6..21b39d4 100644 --- a/yinmeng-ios/Modules/Chat/View/ChatBaseCell.swift +++ b/yinmeng-ios/Modules/Chat/View/ChatBaseCell.swift @@ -7,6 +7,7 @@ import UIKit import Reusable +import NIMSDK protocol ChatBaseCellProtocol: NSObjectProtocol { func cell(_ cell: ChatBaseCell, didTapAvatarAt model: ChatBaseObject) } @@ -15,7 +16,16 @@ class ChatBaseCell: UITableViewCell, Reusable{ weak var delegate: ChatBaseCellProtocol? var model:ChatSessionProtocol? { didSet { - guard let _ = model else {return} + guard let model = model else {return} + if let sessionId = model.msg?.session?.sessionId { + let user = NIMSDK.shared().userManager.userInfo(sessionId) + if let url = user?.userInfo?.avatarUrl { + self.avatarImgView.kf.setImage(with: URL(string: url), + placeholder: UIImage(named: "public_avatar")) + } else { + + } + } layoutMessageCell() } } @@ -45,7 +55,7 @@ class ChatBaseCell: UITableViewCell, Reusable{ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) selectionStyle = .none - backgroundColor = .clear + backgroundColor = ThemeColor(hexStr: "#F8F8FB") contentView.addSubview(avatarImgView) contentView.addSubview(bubbleView) contentView.addSubview(activityIndicatorView) @@ -61,11 +71,15 @@ class ChatBaseCell: UITableViewCell, Reusable{ imageView.isUserInteractionEnabled = true imageView.layer.masksToBounds = true imageView.contentMode = .scaleAspectFill + imageView.layer.cornerRadius = ChatUIConfig.layout.avatarSize / 2.0 return imageView }() lazy var bubbleView: UIImageView = { let imageView = UIImageView() + imageView.backgroundColor = .white + imageView.layer.masksToBounds = true + imageView.layer.cornerRadius = 8 return imageView }() diff --git a/yinmeng-ios/Modules/Chat/View/ChatImageCell.swift b/yinmeng-ios/Modules/Chat/View/ChatImageCell.swift new file mode 100644 index 0000000..f1aeab9 --- /dev/null +++ b/yinmeng-ios/Modules/Chat/View/ChatImageCell.swift @@ -0,0 +1,88 @@ +// +// ChatImageCell.swift +// yinmeng-ios +// +// Created by MaiMang on 2024/3/1. +// + +import UIKit + +class ChatImageCell: ChatBaseCell { + override var model: ChatSessionProtocol? { + didSet { + if let model = model as? ChatImageObject { + backImageView.kf.setImage(with: URL(string: model.url), + placeholder: UIImage(named: "public_avatar")) + } + } + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + bubbleView.addSubview(backImageView) + backImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private lazy var backImageView: UIImageView = { + let imageView = UIImageView() + imageView.isUserInteractionEnabled = true + imageView.layer.masksToBounds = true + imageView.contentMode = .scaleAspectFill + return imageView + }() + +} + +extension ChatImageCell { + + func setupCellLayout() { + guard let model = model else {return} + if model.msg?.isOutgoingMsg == true { //我发送的 + avatarImgView.snp.remakeConstraints { (make) in + make.size.equalTo(ChatUIConfig.layout.avatarSize) + make.right.equalToSuperview().offset(-10) + make.top.equalToSuperview().offset(ChatUIConfig.layout.cellContentInsets.top) + } + + bubbleView.snp.remakeConstraints { make in + make.size.equalTo(model.contentSize) + make.top.equalTo(avatarImgView) + make.right.equalTo(avatarImgView.snp.left).offset(-10) + } + activityIndicatorView.snp.remakeConstraints { (make) in + make.centerY.equalTo(bubbleView) + make.right.equalTo(bubbleView.snp.left) + make.width.height.equalTo(30) + } + + backImageView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + // start + activityStartAnimating() + + }else { + avatarImgView.snp.remakeConstraints { (make) in + make.size.equalTo(ChatUIConfig.layout.avatarSize) + make.left.equalToSuperview().offset(10) + make.top.equalToSuperview().offset(ChatUIConfig.layout.cellContentInsets.top) + } + + bubbleView.snp.remakeConstraints { make in + make.size.equalTo(model.contentSize) + make.top.equalTo(avatarImgView) + make.left.equalTo(avatarImgView.snp.right).offset(10) + } + + backImageView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } + } +} diff --git a/yinmeng-ios/Modules/Chat/View/ChatList/ChatListCell.swift b/yinmeng-ios/Modules/Chat/View/ChatList/ChatListCell.swift index 12bc09f..990372d 100644 --- a/yinmeng-ios/Modules/Chat/View/ChatList/ChatListCell.swift +++ b/yinmeng-ios/Modules/Chat/View/ChatList/ChatListCell.swift @@ -97,7 +97,7 @@ class ChatListCell: UITableViewCell, Reusable { let user = users?[safe:0] if let url = user?.userInfo?.avatarUrl { self.avatarImgView.kf.setImage(with: URL(string: url), - placeholder: nil) + placeholder: UIImage(named: "public_avatar")) } self.nameLb.text = user?.userInfo?.nickName diff --git a/yinmeng-ios/Modules/Chat/View/ChatNavView.swift b/yinmeng-ios/Modules/Chat/View/ChatNavView.swift index 96189df..9fc05ec 100644 --- a/yinmeng-ios/Modules/Chat/View/ChatNavView.swift +++ b/yinmeng-ios/Modules/Chat/View/ChatNavView.swift @@ -9,6 +9,18 @@ import UIKit class ChatNavView: BaseView { + var isLike:Bool? { + didSet { + self.likeBtn.isHidden = isLike ?? false + } + } + + var name:String? { + didSet { + self.titleLb.text = name + } + } + override func loadSubViews() { addSubview(backBtn) addSubview(titleLb) @@ -57,10 +69,11 @@ class ChatNavView: BaseView { let button = UIButton(type: .custom) button.setTitle("关注", for: .normal) button.setTitleColor(ThemeColor(hexStr: "#FFDA24"), for: .normal) - button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .medium) + button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .medium) button.layer.masksToBounds = true - button.layer.cornerRadius = 26 - button.isEnabled = false + button.layer.cornerRadius = 11 + button.layer.borderWidth = 0.5 + button.layer.borderColor = ThemeColor(hexStr: "#FFDA24").cgColor button.addTarget(self, action: #selector(likeClick), for: .touchUpInside) return button }() diff --git a/yinmeng-ios/Modules/Chat/View/ChatTextCell.swift b/yinmeng-ios/Modules/Chat/View/ChatTextCell.swift index 0264575..2afbd80 100644 --- a/yinmeng-ios/Modules/Chat/View/ChatTextCell.swift +++ b/yinmeng-ios/Modules/Chat/View/ChatTextCell.swift @@ -19,18 +19,19 @@ class ChatTextCell: ChatBaseCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) + initSubview() } func initSubview() { bubbleView.addSubview(textLb) - avatarImgView.snp.remakeConstraints { (make) in + avatarImgView.snp.makeConstraints { (make) in make.size.equalTo(ChatUIConfig.layout.avatarSize) make.left.equalToSuperview().offset(10) make.top.equalTo(contentView).offset(10) } - bubbleView.snp.remakeConstraints { (make) in + bubbleView.snp.makeConstraints { (make) in make.top.equalTo(contentView.snp.top).offset(2) make.bottom.equalTo(textLb.snp.bottom).offset(2) make.left.equalTo(avatarImgView.snp.right) @@ -38,13 +39,13 @@ class ChatTextCell: ChatBaseCell { make.height.equalTo(textLb).offset(26) } - textLb.snp.remakeConstraints { (make) in + textLb.snp.makeConstraints { (make) in make.top.equalTo(bubbleView).offset(ChatUIConfig.layout.textInsets.top); make.left.equalTo(bubbleView).offset(ChatUIConfig.layout.textInsets.left); make.right.equalTo(bubbleView).offset(-ChatUIConfig.layout.textInsets.right); } - activityIndicatorView.snp.remakeConstraints { (make) in + activityIndicatorView.snp.makeConstraints { (make) in make.centerY.equalTo(bubbleView) make.centerX.equalToSuperview() make.width.height.equalTo(30) @@ -78,7 +79,7 @@ extension ChatTextCell { make.top.equalToSuperview().offset(ChatUIConfig.layout.cellContentInsets.top) } - bubbleView.snp.makeConstraints { make in + bubbleView.snp.remakeConstraints { make in make.size.equalTo(model.contentSize) make.top.equalTo(avatarImgView) make.right.equalTo(avatarImgView.snp.left).offset(-10) @@ -89,8 +90,8 @@ extension ChatTextCell { make.width.height.equalTo(30) } - textLb.snp.makeConstraints { make in - make.edges.equalTo(ChatUIConfig.layout.textInsets) + textLb.snp.remakeConstraints { make in + make.edges.equalToSuperview().inset(ChatUIConfig.layout.textInsets) } // start @@ -103,14 +104,14 @@ extension ChatTextCell { make.top.equalToSuperview().offset(ChatUIConfig.layout.cellContentInsets.top) } - bubbleView.snp.makeConstraints { make in + bubbleView.snp.remakeConstraints { make in make.size.equalTo(model.contentSize) make.top.equalTo(avatarImgView) make.left.equalTo(avatarImgView.snp.right).offset(10) } - textLb.snp.makeConstraints { make in - make.edges.equalTo(ChatUIConfig.layout.textInsets) + textLb.snp.remakeConstraints { make in + make.edges.equalToSuperview().inset(ChatUIConfig.layout.textInsets) } } } diff --git a/yinmeng-ios/Modules/Chat/View/ChatTimeCell.swift b/yinmeng-ios/Modules/Chat/View/ChatTimeCell.swift new file mode 100644 index 0000000..e6892ea --- /dev/null +++ b/yinmeng-ios/Modules/Chat/View/ChatTimeCell.swift @@ -0,0 +1,43 @@ +// +// ChatTimeCell.swift +// yinmeng-ios +// +// Created by MaiMang on 2024/3/1. +// + +import UIKit +import Reusable +class ChatTimeCell: UITableViewCell, Reusable { + + var model:ChatSessionProtocol? { + didSet { + if let model = model as? ChatTimeObject { + self.timeLb.text = model.text + } + } + } + + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + selectionStyle = .none + backgroundColor = ThemeColor(hexStr: "#F8F8FB") + contentView.addSubview(timeLb) + timeLb.snp.makeConstraints { make in + make.edges.equalTo(contentView) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private lazy var timeLb: UILabel = { + let label = UILabel() + label.textColor = ThemeColor(hexStr: "#A2A7B8") + label.font = UIFont.systemFont(ofSize: 12) + label.textAlignment = .center + return label + }() + +} diff --git a/yinmeng-ios/Modules/Chat/View/ChatVoiceCell.swift b/yinmeng-ios/Modules/Chat/View/ChatVoiceCell.swift new file mode 100644 index 0000000..2af99b9 --- /dev/null +++ b/yinmeng-ios/Modules/Chat/View/ChatVoiceCell.swift @@ -0,0 +1,156 @@ +// +// ChatVoiceCell.swift +// yinmeng-ios +// +// Created by MaiMang on 2024/3/1. +// + +import UIKit +import NIMSDK +class ChatVoiceCell: ChatBaseCell, NIMMediaManagerDelegate { + + override var model: ChatSessionProtocol? { + didSet { + if let model = model as? ChatVoiceObject { + timeLabel.text = "\(model.duartion / 1000)" + } + } + } + + private lazy var timeLabel: UILabel = { + let label = UILabel() + label.textColor = ThemeColor(hexStr: "#2B2D33") + label.font = UIFont.systemFont(ofSize: 14, weight: .medium) + return label + }() + + private lazy var voiceImageView: UIImageView = { + let imageView = UIImageView() + imageView.isUserInteractionEnabled = true + let firstImage = UIImage(named:"chat_audio_playing_first")! + let second = UIImage(named:"chat_audio_playing_first")! + let third = UIImage(named:"chat_audio_playing_first")! + imageView.animationImages = [firstImage, second, third]; + imageView.animationDuration = 1 + imageView.animationRepeatCount = 100 + imageView.image = third + return imageView + }() + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + NIMSDK.shared().mediaManager.setNeedProximityMonitor(false) + NIMSDK.shared().mediaManager.add(self) + loadSubViews() + } + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + NIMSDK.shared().mediaManager.remove(self) + } + + func loadSubViews() { + bubbleView.addSubview(timeLabel) + bubbleView.addSubview(voiceImageView) + timeLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(10) + make.centerY.equalToSuperview() + } + + voiceImageView.snp.makeConstraints { make in + make.size.equalTo(CGSize(width: 20, height: 20)) + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-10) + } + } + + + func playAudio(_ filePath: String, didBeganWithError error: Error?) { + if filePath.isEmpty || error != nil { return } + voiceImageView.startAnimating() + } + + func playAudio(_ filePath: String, didCompletedWithError error: Error?) { + voiceImageView.stopAnimating() + let thirdImage = UIImage(named: "chat_audio_playing_third") + voiceImageView.image = thirdImage + } + + @objc func didTapBackRecognizer() { + if NIMSDK.shared().mediaManager.isPlaying() { + NIMSDK.shared().mediaManager.stopPlay() + } + if let path = self.model as? ChatVoiceObject , path.filPath.count > 0{ + NIMSDK.shared().mediaManager.play(path.filPath) + } + } + + +} + + +extension ChatVoiceCell { + func setupCellLayout() { + guard let model = model else {return} + if model.msg?.isOutgoingMsg == true { //我发送的 + avatarImgView.snp.remakeConstraints { (make) in + make.size.equalTo(ChatUIConfig.layout.avatarSize) + make.right.equalToSuperview().offset(-10) + make.top.equalToSuperview().offset(ChatUIConfig.layout.cellContentInsets.top) + } + + bubbleView.snp.remakeConstraints { make in + make.size.equalTo(model.contentSize) + make.top.equalTo(avatarImgView) + make.right.equalTo(avatarImgView.snp.left).offset(-10) + } + activityIndicatorView.snp.remakeConstraints { (make) in + make.centerY.equalTo(bubbleView) + make.right.equalTo(bubbleView.snp.left) + make.width.height.equalTo(30) + } + + timeLabel.snp.remakeConstraints { make in + make.left.equalToSuperview().offset(10) + make.centerY.equalToSuperview() + } + + voiceImageView.snp.remakeConstraints { make in + make.size.equalTo(CGSize(width: 20, height: 20)) + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-10) + } + + // start + activityStartAnimating() + + }else { + avatarImgView.snp.remakeConstraints { (make) in + make.size.equalTo(ChatUIConfig.layout.avatarSize) + make.left.equalToSuperview().offset(10) + make.top.equalToSuperview().offset(ChatUIConfig.layout.cellContentInsets.top) + } + + bubbleView.snp.remakeConstraints { make in + make.size.equalTo(model.contentSize) + make.top.equalTo(avatarImgView) + make.left.equalTo(avatarImgView.snp.right).offset(10) + } + + timeLabel.snp.remakeConstraints { make in + make.left.equalToSuperview().offset(10) + make.centerY.equalToSuperview() + } + + voiceImageView.snp.remakeConstraints { make in + make.size.equalTo(CGSize(width: 20, height: 20)) + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-10) + } + } + } +}