diff --git a/Ash_AWord.xcodeproj/project.pbxproj b/Ash_AWord.xcodeproj/project.pbxproj index a545adc..68e1541 100644 --- a/Ash_AWord.xcodeproj/project.pbxproj +++ b/Ash_AWord.xcodeproj/project.pbxproj @@ -101,8 +101,62 @@ A96F27F51B21C5AC00DA0A66 /* PraiseUserListTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A96F27F31B21C5AC00DA0A66 /* PraiseUserListTableViewCell.xib */; }; A96F27F91B21C5C800DA0A66 /* PraiseUserListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A96F27F71B21C5C800DA0A66 /* PraiseUserListViewController.m */; }; A96F27FA1B21C5C800DA0A66 /* PraiseUserListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A96F27F81B21C5C800DA0A66 /* PraiseUserListViewController.xib */; }; + A971ED931B32B50A0023740E /* XHMessageTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = A971ED921B32B50A0023740E /* XHMessageTextView.m */; }; + A971ED961B32B5200023740E /* DXFaceView.m in Sources */ = {isa = PBXBuildFile; fileRef = A971ED951B32B5200023740E /* DXFaceView.m */; }; + A971ED991B32B5260023740E /* DXRecordView.m in Sources */ = {isa = PBXBuildFile; fileRef = A971ED981B32B5260023740E /* DXRecordView.m */; }; + A971ED9C1B32B53D0023740E /* FacialView.m in Sources */ = {isa = PBXBuildFile; fileRef = A971ED9B1B32B53D0023740E /* FacialView.m */; }; + A971EDB11B32B5740023740E /* EMAudioPlayerUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDA31B32B5740023740E /* EMAudioPlayerUtil.m */; }; + A971EDB21B32B5740023740E /* EMAudioRecorderUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDA51B32B5740023740E /* EMAudioRecorderUtil.m */; }; + A971EDB31B32B5740023740E /* EMCDDeviceManager+Media.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDA71B32B5740023740E /* EMCDDeviceManager+Media.m */; }; + A971EDB41B32B5740023740E /* EMCDDeviceManager+Microphone.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDA91B32B5740023740E /* EMCDDeviceManager+Microphone.m */; }; + A971EDB51B32B5740023740E /* EMCDDeviceManager+ProximitySensor.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDAB1B32B5740023740E /* EMCDDeviceManager+ProximitySensor.m */; }; + A971EDB61B32B5740023740E /* EMCDDeviceManager+Remind.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDAD1B32B5740023740E /* EMCDDeviceManager+Remind.m */; }; + A971EDB71B32B5740023740E /* EMCDDeviceManagerBase.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDB01B32B5740023740E /* EMCDDeviceManagerBase.m */; }; + A971EDC81B32B6A40023740E /* amrFileCodec.mm in Sources */ = {isa = PBXBuildFile; fileRef = A971EDBB1B32B6A40023740E /* amrFileCodec.mm */; }; + A971EDC91B32B6A40023740E /* wav.mm in Sources */ = {isa = PBXBuildFile; fileRef = A971EDBD1B32B6A40023740E /* wav.mm */; }; + A971EDCA1B32B6A40023740E /* EMVoiceConverter.mm in Sources */ = {isa = PBXBuildFile; fileRef = A971EDBF1B32B6A40023740E /* EMVoiceConverter.mm */; }; + A971EDCB1B32B6A40023740E /* libopencore-amrnb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A971EDC31B32B6A40023740E /* libopencore-amrnb.a */; }; + A971EDCC1B32B6A40023740E /* libopencore-amrwb.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A971EDC71B32B6A40023740E /* libopencore-amrwb.a */; }; + A971EDD21B32B6CF0023740E /* Emoji.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDCF1B32B6CF0023740E /* Emoji.m */; }; + A971EDD31B32B6CF0023740E /* EmojiEmoticons.m in Sources */ = {isa = PBXBuildFile; fileRef = A971EDD11B32B6CF0023740E /* EmojiEmoticons.m */; }; + A971EDD51B32B7790023740E /* messageToolbarBg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDD41B32B7790023740E /* messageToolbarBg@2x.png */; }; + A971EDDC1B32B7960023740E /* chatBar_face@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDD61B32B7960023740E /* chatBar_face@2x.png */; }; + A971EDDD1B32B7960023740E /* chatBar_faceSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDD71B32B7960023740E /* chatBar_faceSelected@2x.png */; }; + A971EDDE1B32B7960023740E /* chatBar_keyboard@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDD81B32B7960023740E /* chatBar_keyboard@2x.png */; }; + A971EDDF1B32B7960023740E /* chatBar_keyboardSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDD91B32B7960023740E /* chatBar_keyboardSelected@2x.png */; }; + A971EDE01B32B7960023740E /* chatBar_more@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDDA1B32B7960023740E /* chatBar_more@2x.png */; }; + A971EDE11B32B7960023740E /* chatBar_moreSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDDB1B32B7960023740E /* chatBar_moreSelected@2x.png */; }; + A971EDE61B32B7A00023740E /* chatBar_record@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDE21B32B7A00023740E /* chatBar_record@2x.png */; }; + A971EDE71B32B7A00023740E /* chatBar_recordBg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDE31B32B7A00023740E /* chatBar_recordBg@2x.png */; }; + A971EDE81B32B7A00023740E /* chatBar_recordSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDE41B32B7A00023740E /* chatBar_recordSelected@2x.png */; }; + A971EDE91B32B7A00023740E /* chatBar_recordSelectedBg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDE51B32B7A00023740E /* chatBar_recordSelectedBg@2x.png */; }; + A971EDF01B32B7AF0023740E /* chatBar_more_camera@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDEA1B32B7AF0023740E /* chatBar_more_camera@2x.png */; }; + A971EDF11B32B7AF0023740E /* chatBar_more_cameraSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDEB1B32B7AF0023740E /* chatBar_more_cameraSelected@2x.png */; }; + A971EDF21B32B7AF0023740E /* chatBar_more_location@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDEC1B32B7AF0023740E /* chatBar_more_location@2x.png */; }; + A971EDF31B32B7AF0023740E /* chatBar_more_locationSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDED1B32B7AF0023740E /* chatBar_more_locationSelected@2x.png */; }; + A971EDF41B32B7AF0023740E /* chatBar_more_photo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDEE1B32B7AF0023740E /* chatBar_more_photo@2x.png */; }; + A971EDF51B32B7AF0023740E /* chatBar_more_photoSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDEF1B32B7AF0023740E /* chatBar_more_photoSelected@2x.png */; }; + A971EE021B32B7C40023740E /* chatBar_colorMore_audioCall@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDF61B32B7C40023740E /* chatBar_colorMore_audioCall@2x.png */; }; + A971EE031B32B7C40023740E /* chatBar_colorMore_audioCallSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDF71B32B7C40023740E /* chatBar_colorMore_audioCallSelected@2x.png */; }; + A971EE041B32B7C40023740E /* chatBar_colorMore_camera@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDF81B32B7C40023740E /* chatBar_colorMore_camera@2x.png */; }; + A971EE051B32B7C40023740E /* chatBar_colorMore_cameraSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDF91B32B7C40023740E /* chatBar_colorMore_cameraSelected@2x.png */; }; + A971EE061B32B7C40023740E /* chatBar_colorMore_location@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDFA1B32B7C40023740E /* chatBar_colorMore_location@2x.png */; }; + A971EE071B32B7C40023740E /* chatBar_colorMore_locationSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDFB1B32B7C40023740E /* chatBar_colorMore_locationSelected@2x.png */; }; + A971EE081B32B7C40023740E /* chatBar_colorMore_photo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDFC1B32B7C40023740E /* chatBar_colorMore_photo@2x.png */; }; + A971EE091B32B7C40023740E /* chatBar_colorMore_photoSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDFD1B32B7C40023740E /* chatBar_colorMore_photoSelected@2x.png */; }; + A971EE0A1B32B7C40023740E /* chatBar_colorMore_video@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDFE1B32B7C40023740E /* chatBar_colorMore_video@2x.png */; }; + A971EE0B1B32B7C40023740E /* chatBar_colorMore_videoCall@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EDFF1B32B7C40023740E /* chatBar_colorMore_videoCall@2x.png */; }; + A971EE0C1B32B7C40023740E /* chatBar_colorMore_videoCallSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EE001B32B7C40023740E /* chatBar_colorMore_videoCallSelected@2x.png */; }; + A971EE0D1B32B7C40023740E /* chatBar_colorMore_videoSelected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A971EE011B32B7C40023740E /* chatBar_colorMore_videoSelected@2x.png */; }; A9744EDD1B311DBA0082301D /* MessageCommentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9744EDB1B311DBA0082301D /* MessageCommentViewController.m */; }; A9744EDE1B311DBA0082301D /* MessageCommentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9744EDC1B311DBA0082301D /* MessageCommentViewController.xib */; }; + A9744F4D1B3155160082301D /* libEaseMobClientSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9744F491B3155160082301D /* libEaseMobClientSDK.a */; }; + A9744F4F1B3155160082301D /* EaseMob.bundle in Resources */ = {isa = PBXBuildFile; fileRef = A9744F4C1B3155160082301D /* EaseMob.bundle */; }; + A9744F511B3155690082301D /* libstdc++.6.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = A9744F501B3155690082301D /* libstdc++.6.dylib */; }; + A9744F531B31557A0082301D /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = A9744F521B31557A0082301D /* libxml2.dylib */; }; + A9744F551B3155950082301D /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = A9744F541B3155950082301D /* libresolv.dylib */; }; + A9744F571B3155A60082301D /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9744F561B3155A60082301D /* CFNetwork.framework */; }; + A9744F591B3155B00082301D /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9744F581B3155B00082301D /* MobileCoreServices.framework */; }; A9754A1C1ADC080E0018BAAD /* AudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A9754A0F1ADC080E0018BAAD /* AudioPlayer.m */; }; A9754A1D1ADC080E0018BAAD /* AutoRecoveringHttpDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A9754A111ADC080E0018BAAD /* AutoRecoveringHttpDataSource.m */; }; A9754A1E1ADC080E0018BAAD /* CoreFoundationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = A9754A131ADC080E0018BAAD /* CoreFoundationDataSource.m */; }; @@ -133,6 +187,23 @@ A97559D11ACBF0BC004ADA42 /* btn_share@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A97559CB1ACBF0BC004ADA42 /* btn_share@2x.png */; }; A97883881AD369DF00D46477 /* mainCellDingClick@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A97883871AD369DF00D46477 /* mainCellDingClick@2x.png */; }; A978838A1AD36A0500D46477 /* mainCellDing@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A97883891AD36A0500D46477 /* mainCellDing@2x.png */; }; + A978CB291B3A3D5A00028C4A /* chat_sender_audio_playing_000@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB231B3A3D5A00028C4A /* chat_sender_audio_playing_000@2x.png */; }; + A978CB2A1B3A3D5A00028C4A /* chat_sender_audio_playing_001@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB241B3A3D5A00028C4A /* chat_sender_audio_playing_001@2x.png */; }; + A978CB2B1B3A3D5A00028C4A /* chat_sender_audio_playing_002@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB251B3A3D5A00028C4A /* chat_sender_audio_playing_002@2x.png */; }; + A978CB2C1B3A3D5A00028C4A /* chat_sender_audio_playing_003@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB261B3A3D5A00028C4A /* chat_sender_audio_playing_003@2x.png */; }; + A978CB2D1B3A3D5A00028C4A /* chat_sender_audio_playing_full@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB271B3A3D5A00028C4A /* chat_sender_audio_playing_full@2x.png */; }; + A978CB2E1B3A3D5A00028C4A /* chat_sender_bg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB281B3A3D5A00028C4A /* chat_sender_bg@2x.png */; }; + A978CB351B3A3D6700028C4A /* chat_receiver_audio_playing_full@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB2F1B3A3D6700028C4A /* chat_receiver_audio_playing_full@2x.png */; }; + A978CB361B3A3D6700028C4A /* chat_receiver_audio_playing000@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB301B3A3D6700028C4A /* chat_receiver_audio_playing000@2x.png */; }; + A978CB371B3A3D6700028C4A /* chat_receiver_audio_playing001@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB311B3A3D6700028C4A /* chat_receiver_audio_playing001@2x.png */; }; + A978CB381B3A3D6700028C4A /* chat_receiver_audio_playing002@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB321B3A3D6700028C4A /* chat_receiver_audio_playing002@2x.png */; }; + A978CB391B3A3D6700028C4A /* chat_receiver_audio_playing003@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB331B3A3D6700028C4A /* chat_receiver_audio_playing003@2x.png */; }; + A978CB3A1B3A3D6700028C4A /* chat_receiver_bg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB341B3A3D6700028C4A /* chat_receiver_bg@2x.png */; }; + A978CB3F1B3A3D7100028C4A /* chat_location_annotation_someone@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB3B1B3A3D7100028C4A /* chat_location_annotation_someone@2x.png */; }; + A978CB401B3A3D7100028C4A /* chat_location_detail_disclosure@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB3C1B3A3D7100028C4A /* chat_location_detail_disclosure@2x.png */; }; + A978CB411B3A3D7100028C4A /* chat_location_detail_disclosureHL@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB3D1B3A3D7100028C4A /* chat_location_detail_disclosureHL@2x.png */; }; + A978CB421B3A3D7100028C4A /* chat_location_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB3E1B3A3D7100028C4A /* chat_location_preview@2x.png */; }; + A978CB441B3A3D8800028C4A /* chatListCellHead@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A978CB431B3A3D8800028C4A /* chatListCellHead@2x.png */; }; A97938751B20A63D00180C08 /* UserViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A97938741B20A63D00180C08 /* UserViewModel.m */; }; A97938781B20BB0900180C08 /* CommentViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A97938771B20BB0900180C08 /* CommentViewModel.m */; }; A97C54CD1AC8F10F0038818A /* BaseViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A97C54BD1AC8F10F0038818A /* BaseViewModel.m */; }; @@ -218,6 +289,11 @@ A9B6DFE41B202E950003C1BC /* night_user_comment_circle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9B6DFE31B202E950003C1BC /* night_user_comment_circle@2x.png */; }; A9B6DFE61B2033A80003C1BC /* toolbar_light_comment@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9B6DFE51B2033A80003C1BC /* toolbar_light_comment@2x.png */; }; A9B6DFEC1B2068790003C1BC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A9B6DFEE1B2068790003C1BC /* Localizable.strings */; }; + A9B8FEC51B32A4CF00619C7D /* ChatMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9B8FEC31B32A4CF00619C7D /* ChatMainViewController.m */; }; + A9B8FEC61B32A4CF00619C7D /* ChatMainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9B8FEC41B32A4CF00619C7D /* ChatMainViewController.xib */; }; + A9B8FEC91B32AC7000619C7D /* DXMessageToolBar.m in Sources */ = {isa = PBXBuildFile; fileRef = A9B8FEC81B32AC7000619C7D /* DXMessageToolBar.m */; }; + A9B8FECC1B32ACA900619C7D /* DXChatBarMoreView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9B8FECB1B32ACA900619C7D /* DXChatBarMoreView.m */; }; + A9B8FECF1B32B0F200619C7D /* MessageTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9B8FECE1B32B0F200619C7D /* MessageTableView.m */; }; A9BE23BF1ACD8CA20032171A /* libSocialSina.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9BE23BD1ACD8CA20032171A /* libSocialSina.a */; }; A9CF211C1B1C36D0007490EF /* mainCellCommentClickN@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9CF211A1B1C36D0007490EF /* mainCellCommentClickN@2x.png */; }; A9CF211D1B1C36D0007490EF /* mainCellCommentN@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9CF211B1B1C36D0007490EF /* mainCellCommentN@2x.png */; }; @@ -230,6 +306,35 @@ A9E2711C1ADB97ED000B1542 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = A9E2711A1ADB97ED000B1542 /* Default.png */; }; A9E2711E1ADBB25C000B1542 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E2711D1ADBB25C000B1542 /* AVFoundation.framework */; }; A9EA14C31B02E88300357529 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9EA14C21B02E88300357529 /* LaunchScreen.xib */; }; + A9F7F4571B33B37600317F3E /* LocationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F7F4561B33B37600317F3E /* LocationViewController.m */; }; + A9F7F4591B33B51F00317F3E /* back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4581B33B51F00317F3E /* back@2x.png */; }; + A9F7F45E1B33BC4E00317F3E /* callRing.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F45B1B33BC4E00317F3E /* callRing.mp3 */; }; + A9F7F45F1B33BC4E00317F3E /* CallViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F7F45D1B33BC4E00317F3E /* CallViewController.m */; }; + A9F7F4671B33BF6700317F3E /* call_out_h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4601B33BF6700317F3E /* call_out_h@2x.png */; }; + A9F7F4681B33BF6700317F3E /* call_out@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4611B33BF6700317F3E /* call_out@2x.png */; }; + A9F7F4691B33BF6700317F3E /* call_silence_h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4621B33BF6700317F3E /* call_silence_h@2x.png */; }; + A9F7F46A1B33BF6700317F3E /* call_silence@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4631B33BF6700317F3E /* call_silence@2x.png */; }; + A9F7F46B1B33BF6700317F3E /* callBg@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4641B33BF6700317F3E /* callBg@2x.png */; }; + A9F7F46C1B33BF6700317F3E /* imageDownloadFail@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4651B33BF6700317F3E /* imageDownloadFail@2x.png */; }; + A9F7F46D1B33BF6700317F3E /* messageSendFail@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9F7F4661B33BF6700317F3E /* messageSendFail@2x.png */; }; + A9F917AB1B3900270007A3AC /* ChatSendHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917AA1B3900270007A3AC /* ChatSendHelper.m */; }; + A9F917AE1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917AD1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.m */; }; + A9F917C31B39055A0007A3AC /* EMChatAudioBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917B21B39055A0007A3AC /* EMChatAudioBubbleView.m */; }; + A9F917C41B39055A0007A3AC /* EMChatBaseBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917B41B39055A0007A3AC /* EMChatBaseBubbleView.m */; }; + A9F917C51B39055A0007A3AC /* EMChatImageBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917B61B39055A0007A3AC /* EMChatImageBubbleView.m */; }; + A9F917C61B39055A0007A3AC /* EMChatLocationBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917B81B39055A0007A3AC /* EMChatLocationBubbleView.m */; }; + A9F917C71B39055A0007A3AC /* EMChatTextBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917BA1B39055A0007A3AC /* EMChatTextBubbleView.m */; }; + A9F917C81B39055A0007A3AC /* EMChatVideoBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917BC1B39055A0007A3AC /* EMChatVideoBubbleView.m */; }; + A9F917C91B39055A0007A3AC /* EMChatTimeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917BE1B39055A0007A3AC /* EMChatTimeCell.m */; }; + A9F917CA1B39055A0007A3AC /* EMChatViewBaseCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917C01B39055A0007A3AC /* EMChatViewBaseCell.m */; }; + A9F917CB1B39055A0007A3AC /* EMChatViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917C21B39055A0007A3AC /* EMChatViewCell.m */; }; + A9F917D21B3906150007A3AC /* MessageModel.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917CD1B3906150007A3AC /* MessageModel.m */; }; + A9F917D31B3906150007A3AC /* MessageModelManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917CF1B3906150007A3AC /* MessageModelManager.m */; }; + A9F917D41B3906150007A3AC /* MessageReadManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917D11B3906150007A3AC /* MessageReadManager.m */; }; + A9F917D71B39091A0007A3AC /* NSDate+Category.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917D61B39091A0007A3AC /* NSDate+Category.m */; }; + A9F917DA1B390A220007A3AC /* NSDateFormatter+Category.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917D91B390A220007A3AC /* NSDateFormatter+Category.m */; }; + A9F917DE1B390AE70007A3AC /* THProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917DD1B390AE70007A3AC /* THProgressView.m */; }; + A9F917E11B390AFE0007A3AC /* UIResponder+Router.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F917E01B390AFE0007A3AC /* UIResponder+Router.m */; }; A9FAD4221AC922A5007ADC10 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9FAD4201AC922A5007ADC10 /* MainViewController.m */; }; A9FAD4231AC922A5007ADC10 /* MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9FAD4211AC922A5007ADC10 /* MainViewController.xib */; }; A9FAD4271AC922BE007ADC10 /* NoteViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9FAD4251AC922BE007ADC10 /* NoteViewController.m */; }; @@ -385,9 +490,170 @@ A96F27F61B21C5C800DA0A66 /* PraiseUserListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PraiseUserListViewController.h; sourceTree = ""; }; A96F27F71B21C5C800DA0A66 /* PraiseUserListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PraiseUserListViewController.m; sourceTree = ""; }; A96F27F81B21C5C800DA0A66 /* PraiseUserListViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PraiseUserListViewController.xib; sourceTree = ""; }; + A971ED911B32B50A0023740E /* XHMessageTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XHMessageTextView.h; sourceTree = ""; }; + A971ED921B32B50A0023740E /* XHMessageTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XHMessageTextView.m; sourceTree = ""; }; + A971ED941B32B5200023740E /* DXFaceView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DXFaceView.h; sourceTree = ""; }; + A971ED951B32B5200023740E /* DXFaceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DXFaceView.m; sourceTree = ""; }; + A971ED971B32B5260023740E /* DXRecordView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DXRecordView.h; sourceTree = ""; }; + A971ED981B32B5260023740E /* DXRecordView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DXRecordView.m; sourceTree = ""; }; + A971ED9A1B32B53D0023740E /* FacialView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FacialView.h; sourceTree = ""; }; + A971ED9B1B32B53D0023740E /* FacialView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FacialView.m; sourceTree = ""; }; + A971ED9F1B32B5740023740E /* EMCDDeviceManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCDDeviceManagerDelegate.h; sourceTree = ""; }; + A971EDA01B32B5740023740E /* EMCDDeviceManagerProximitySensorDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCDDeviceManagerProximitySensorDelegate.h; sourceTree = ""; }; + A971EDA21B32B5740023740E /* EMAudioPlayerUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMAudioPlayerUtil.h; sourceTree = ""; }; + A971EDA31B32B5740023740E /* EMAudioPlayerUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMAudioPlayerUtil.m; sourceTree = ""; }; + A971EDA41B32B5740023740E /* EMAudioRecorderUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMAudioRecorderUtil.h; sourceTree = ""; }; + A971EDA51B32B5740023740E /* EMAudioRecorderUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMAudioRecorderUtil.m; sourceTree = ""; }; + A971EDA61B32B5740023740E /* EMCDDeviceManager+Media.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EMCDDeviceManager+Media.h"; sourceTree = ""; }; + A971EDA71B32B5740023740E /* EMCDDeviceManager+Media.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EMCDDeviceManager+Media.m"; sourceTree = ""; }; + A971EDA81B32B5740023740E /* EMCDDeviceManager+Microphone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EMCDDeviceManager+Microphone.h"; sourceTree = ""; }; + A971EDA91B32B5740023740E /* EMCDDeviceManager+Microphone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EMCDDeviceManager+Microphone.m"; sourceTree = ""; }; + A971EDAA1B32B5740023740E /* EMCDDeviceManager+ProximitySensor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EMCDDeviceManager+ProximitySensor.h"; sourceTree = ""; }; + A971EDAB1B32B5740023740E /* EMCDDeviceManager+ProximitySensor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EMCDDeviceManager+ProximitySensor.m"; sourceTree = ""; }; + A971EDAC1B32B5740023740E /* EMCDDeviceManager+Remind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EMCDDeviceManager+Remind.h"; sourceTree = ""; }; + A971EDAD1B32B5740023740E /* EMCDDeviceManager+Remind.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EMCDDeviceManager+Remind.m"; sourceTree = ""; }; + A971EDAE1B32B5740023740E /* EMCDDeviceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCDDeviceManager.h; sourceTree = ""; }; + A971EDAF1B32B5740023740E /* EMCDDeviceManagerBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCDDeviceManagerBase.h; sourceTree = ""; }; + A971EDB01B32B5740023740E /* EMCDDeviceManagerBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMCDDeviceManagerBase.m; sourceTree = ""; }; + A971EDBA1B32B6A40023740E /* amrFileCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amrFileCodec.h; sourceTree = ""; }; + A971EDBB1B32B6A40023740E /* amrFileCodec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = amrFileCodec.mm; sourceTree = ""; }; + A971EDBC1B32B6A40023740E /* wav.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wav.h; sourceTree = ""; }; + A971EDBD1B32B6A40023740E /* wav.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = wav.mm; sourceTree = ""; }; + A971EDBE1B32B6A40023740E /* EMVoiceConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMVoiceConverter.h; sourceTree = ""; }; + A971EDBF1B32B6A40023740E /* EMVoiceConverter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EMVoiceConverter.mm; sourceTree = ""; }; + A971EDC11B32B6A40023740E /* interf_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interf_dec.h; sourceTree = ""; }; + A971EDC21B32B6A40023740E /* interf_enc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = interf_enc.h; sourceTree = ""; }; + A971EDC31B32B6A40023740E /* libopencore-amrnb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopencore-amrnb.a"; sourceTree = ""; }; + A971EDC51B32B6A40023740E /* dec_if.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dec_if.h; sourceTree = ""; }; + A971EDC61B32B6A40023740E /* if_rom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_rom.h; sourceTree = ""; }; + A971EDC71B32B6A40023740E /* libopencore-amrwb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libopencore-amrwb.a"; sourceTree = ""; }; + A971EDCE1B32B6CF0023740E /* Emoji.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Emoji.h; sourceTree = ""; }; + A971EDCF1B32B6CF0023740E /* Emoji.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Emoji.m; sourceTree = ""; }; + A971EDD01B32B6CF0023740E /* EmojiEmoticons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmojiEmoticons.h; sourceTree = ""; }; + A971EDD11B32B6CF0023740E /* EmojiEmoticons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EmojiEmoticons.m; sourceTree = ""; }; + A971EDD41B32B7790023740E /* messageToolbarBg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "messageToolbarBg@2x.png"; sourceTree = ""; }; + A971EDD61B32B7960023740E /* chatBar_face@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_face@2x.png"; sourceTree = ""; }; + A971EDD71B32B7960023740E /* chatBar_faceSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_faceSelected@2x.png"; sourceTree = ""; }; + A971EDD81B32B7960023740E /* chatBar_keyboard@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_keyboard@2x.png"; sourceTree = ""; }; + A971EDD91B32B7960023740E /* chatBar_keyboardSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_keyboardSelected@2x.png"; sourceTree = ""; }; + A971EDDA1B32B7960023740E /* chatBar_more@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more@2x.png"; sourceTree = ""; }; + A971EDDB1B32B7960023740E /* chatBar_moreSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_moreSelected@2x.png"; sourceTree = ""; }; + A971EDE21B32B7A00023740E /* chatBar_record@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_record@2x.png"; sourceTree = ""; }; + A971EDE31B32B7A00023740E /* chatBar_recordBg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_recordBg@2x.png"; sourceTree = ""; }; + A971EDE41B32B7A00023740E /* chatBar_recordSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_recordSelected@2x.png"; sourceTree = ""; }; + A971EDE51B32B7A00023740E /* chatBar_recordSelectedBg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_recordSelectedBg@2x.png"; sourceTree = ""; }; + A971EDEA1B32B7AF0023740E /* chatBar_more_camera@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more_camera@2x.png"; sourceTree = ""; }; + A971EDEB1B32B7AF0023740E /* chatBar_more_cameraSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more_cameraSelected@2x.png"; sourceTree = ""; }; + A971EDEC1B32B7AF0023740E /* chatBar_more_location@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more_location@2x.png"; sourceTree = ""; }; + A971EDED1B32B7AF0023740E /* chatBar_more_locationSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more_locationSelected@2x.png"; sourceTree = ""; }; + A971EDEE1B32B7AF0023740E /* chatBar_more_photo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more_photo@2x.png"; sourceTree = ""; }; + A971EDEF1B32B7AF0023740E /* chatBar_more_photoSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_more_photoSelected@2x.png"; sourceTree = ""; }; + A971EDF61B32B7C40023740E /* chatBar_colorMore_audioCall@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_audioCall@2x.png"; sourceTree = ""; }; + A971EDF71B32B7C40023740E /* chatBar_colorMore_audioCallSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_audioCallSelected@2x.png"; sourceTree = ""; }; + A971EDF81B32B7C40023740E /* chatBar_colorMore_camera@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_camera@2x.png"; sourceTree = ""; }; + A971EDF91B32B7C40023740E /* chatBar_colorMore_cameraSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_cameraSelected@2x.png"; sourceTree = ""; }; + A971EDFA1B32B7C40023740E /* chatBar_colorMore_location@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_location@2x.png"; sourceTree = ""; }; + A971EDFB1B32B7C40023740E /* chatBar_colorMore_locationSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_locationSelected@2x.png"; sourceTree = ""; }; + A971EDFC1B32B7C40023740E /* chatBar_colorMore_photo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_photo@2x.png"; sourceTree = ""; }; + A971EDFD1B32B7C40023740E /* chatBar_colorMore_photoSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_photoSelected@2x.png"; sourceTree = ""; }; + A971EDFE1B32B7C40023740E /* chatBar_colorMore_video@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_video@2x.png"; sourceTree = ""; }; + A971EDFF1B32B7C40023740E /* chatBar_colorMore_videoCall@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_videoCall@2x.png"; sourceTree = ""; }; + A971EE001B32B7C40023740E /* chatBar_colorMore_videoCallSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_videoCallSelected@2x.png"; sourceTree = ""; }; + A971EE011B32B7C40023740E /* chatBar_colorMore_videoSelected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatBar_colorMore_videoSelected@2x.png"; sourceTree = ""; }; A9744EDA1B311DBA0082301D /* MessageCommentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageCommentViewController.h; sourceTree = ""; }; A9744EDB1B311DBA0082301D /* MessageCommentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageCommentViewController.m; sourceTree = ""; }; A9744EDC1B311DBA0082301D /* MessageCommentViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCommentViewController.xib; sourceTree = ""; }; + A9744EE41B3155150082301D /* EMCallManagerCallDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCallManagerCallDelegate.h; sourceTree = ""; }; + A9744EE51B3155150082301D /* EMCallManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCallManagerDelegate.h; sourceTree = ""; }; + A9744EE61B3155150082301D /* EaseMob+CallService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EaseMob+CallService.h"; sourceTree = ""; }; + A9744EE71B3155150082301D /* EMCallServiceDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCallServiceDefs.h; sourceTree = ""; }; + A9744EE81B3155150082301D /* ICallManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICallManager.h; sourceTree = ""; }; + A9744EEA1B3155150082301D /* ICallManagerBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICallManagerBase.h; sourceTree = ""; }; + A9744EEB1B3155150082301D /* ICallManagerCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICallManagerCall.h; sourceTree = ""; }; + A9744EED1B3155150082301D /* EMCallSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCallSession.h; sourceTree = ""; }; + A9744EEE1B3155150082301D /* IOpenGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOpenGLView.h; sourceTree = ""; }; + A9744EEF1B3155150082301D /* OpenGLView20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenGLView20.h; sourceTree = ""; }; + A9744EF31B3155150082301D /* IChatManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerDelegate.h; sourceTree = ""; }; + A9744EF51B3155150082301D /* EMChatManagerBuddyDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerBuddyDelegate.h; sourceTree = ""; }; + A9744EF61B3155150082301D /* EMChatManagerChatDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerChatDelegate.h; sourceTree = ""; }; + A9744EF71B3155150082301D /* EMChatManagerChatroomDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerChatroomDelegate.h; sourceTree = ""; }; + A9744EF81B3155150082301D /* EMChatManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerDelegate.h; sourceTree = ""; }; + A9744EF91B3155150082301D /* EMChatManagerDelegateBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerDelegateBase.h; sourceTree = ""; }; + A9744EFA1B3155150082301D /* EMChatManagerEncryptionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerEncryptionDelegate.h; sourceTree = ""; }; + A9744EFB1B3155150082301D /* EMChatManagerGroupDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerGroupDelegate.h; sourceTree = ""; }; + A9744EFC1B3155150082301D /* EMChatManagerLoginDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerLoginDelegate.h; sourceTree = ""; }; + A9744EFD1B3155150082301D /* EMChatManagerPushNotificationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerPushNotificationDelegate.h; sourceTree = ""; }; + A9744EFE1B3155150082301D /* EMChatManagerUtilDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerUtilDelegate.h; sourceTree = ""; }; + A9744EFF1B3155150082301D /* EMChatManagerDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatManagerDefs.h; sourceTree = ""; }; + A9744F001B3155150082301D /* EMGroupManagerDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMGroupManagerDefs.h; sourceTree = ""; }; + A9744F011B3155150082301D /* EMPushManagerDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMPushManagerDefs.h; sourceTree = ""; }; + A9744F021B3155150082301D /* IChatManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManager.h; sourceTree = ""; }; + A9744F041B3155150082301D /* IChatManagerBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerBase.h; sourceTree = ""; }; + A9744F051B3155150082301D /* IChatManagerBuddy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerBuddy.h; sourceTree = ""; }; + A9744F061B3155150082301D /* IChatManagerChat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerChat.h; sourceTree = ""; }; + A9744F071B3155150082301D /* IChatManagerChatroom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerChatroom.h; sourceTree = ""; }; + A9744F081B3155160082301D /* IChatManagerConversation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerConversation.h; sourceTree = ""; }; + A9744F091B3155160082301D /* IChatManagerEncryption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerEncryption.h; sourceTree = ""; }; + A9744F0A1B3155160082301D /* IChatManagerGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerGroup.h; sourceTree = ""; }; + A9744F0B1B3155160082301D /* IChatManagerLogin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerLogin.h; sourceTree = ""; }; + A9744F0C1B3155160082301D /* IChatManagerPushNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerPushNotification.h; sourceTree = ""; }; + A9744F0D1B3155160082301D /* IChatManagerSettingOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerSettingOptions.h; sourceTree = ""; }; + A9744F0E1B3155160082301D /* IChatManagerUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatManagerUtil.h; sourceTree = ""; }; + A9744F101B3155160082301D /* EMBuddy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMBuddy.h; sourceTree = ""; }; + A9744F111B3155160082301D /* EMChatCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatCommand.h; sourceTree = ""; }; + A9744F121B3155160082301D /* EMChatFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatFile.h; sourceTree = ""; }; + A9744F131B3155160082301D /* EMChatImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatImage.h; sourceTree = ""; }; + A9744F141B3155160082301D /* EMChatLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatLocation.h; sourceTree = ""; }; + A9744F151B3155160082301D /* EMChatroom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatroom.h; sourceTree = ""; }; + A9744F161B3155160082301D /* EMChatText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatText.h; sourceTree = ""; }; + A9744F171B3155160082301D /* EMChatVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatVideo.h; sourceTree = ""; }; + A9744F181B3155160082301D /* EMChatVoice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatVoice.h; sourceTree = ""; }; + A9744F191B3155160082301D /* EMCommandMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCommandMessageBody.h; sourceTree = ""; }; + A9744F1A1B3155160082301D /* EMConversation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMConversation.h; sourceTree = ""; }; + A9744F1B1B3155160082301D /* EMCursorResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCursorResult.h; sourceTree = ""; }; + A9744F1C1B3155160082301D /* EMFileMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMFileMessageBody.h; sourceTree = ""; }; + A9744F1D1B3155160082301D /* EMGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMGroup.h; sourceTree = ""; }; + A9744F1E1B3155160082301D /* EMGroupStyleSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMGroupStyleSetting.h; sourceTree = ""; }; + A9744F1F1B3155160082301D /* EMImageMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMImageMessageBody.h; sourceTree = ""; }; + A9744F201B3155160082301D /* EMLocationMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMLocationMessageBody.h; sourceTree = ""; }; + A9744F211B3155160082301D /* EMMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMMessage.h; sourceTree = ""; }; + A9744F221B3155160082301D /* EMPushNotificationOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMPushNotificationOptions.h; sourceTree = ""; }; + A9744F231B3155160082301D /* EMReceipt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMReceipt.h; sourceTree = ""; }; + A9744F241B3155160082301D /* EMReceiptBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMReceiptBase.h; sourceTree = ""; }; + A9744F251B3155160082301D /* EMTextMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMTextMessageBody.h; sourceTree = ""; }; + A9744F261B3155160082301D /* EMVideoMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMVideoMessageBody.h; sourceTree = ""; }; + A9744F271B3155160082301D /* EMVoiceMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMVoiceMessageBody.h; sourceTree = ""; }; + A9744F281B3155160082301D /* IChatImageOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IChatImageOptions.h; sourceTree = ""; }; + A9744F291B3155160082301D /* IEMChatCryptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEMChatCryptor.h; sourceTree = ""; }; + A9744F2A1B3155160082301D /* IEMChatFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEMChatFile.h; sourceTree = ""; }; + A9744F2B1B3155160082301D /* IEMChatObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEMChatObject.h; sourceTree = ""; }; + A9744F2C1B3155160082301D /* IEMChatProgressDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEMChatProgressDelegate.h; sourceTree = ""; }; + A9744F2D1B3155160082301D /* IEMFileMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEMFileMessageBody.h; sourceTree = ""; }; + A9744F2E1B3155160082301D /* IEMMessageBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IEMMessageBody.h; sourceTree = ""; }; + A9744F301B3155160082301D /* EaseMob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EaseMob.h; sourceTree = ""; }; + A9744F311B3155160082301D /* EaseMobHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EaseMobHeaders.h; sourceTree = ""; }; + A9744F321B3155160082301D /* EMSDKFull.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMSDKFull.h; sourceTree = ""; }; + A9744F331B3155160082301D /* EMSDKFullHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMSDKFullHeaders.h; sourceTree = ""; }; + A9744F351B3155160082301D /* EaseMob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EaseMob.h; sourceTree = ""; }; + A9744F361B3155160082301D /* EaseMobHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EaseMobHeaders.h; sourceTree = ""; }; + A9744F381B3155160082301D /* commonDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commonDefs.h; sourceTree = ""; }; + A9744F3B1B3155160082301D /* IDeviceManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDeviceManagerDelegate.h; sourceTree = ""; }; + A9744F3D1B3155160082301D /* EMDeviceManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMDeviceManagerDelegate.h; sourceTree = ""; }; + A9744F3E1B3155160082301D /* EMDeviceManagerDelegateBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMDeviceManagerDelegateBase.h; sourceTree = ""; }; + A9744F3F1B3155160082301D /* EMDeviceManagerNetworkDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMDeviceManagerNetworkDelegate.h; sourceTree = ""; }; + A9744F401B3155160082301D /* EMDeviceManagerDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMDeviceManagerDefs.h; sourceTree = ""; }; + A9744F411B3155160082301D /* IDeviceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDeviceManager.h; sourceTree = ""; }; + A9744F431B3155160082301D /* IDeviceManagerBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDeviceManagerBase.h; sourceTree = ""; }; + A9744F441B3155160082301D /* EMNetworkMonitorDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMNetworkMonitorDefs.h; sourceTree = ""; }; + A9744F461B3155160082301D /* EMError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMError.h; sourceTree = ""; }; + A9744F471B3155160082301D /* EMErrorDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMErrorDefs.h; sourceTree = ""; }; + A9744F491B3155160082301D /* libEaseMobClientSDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libEaseMobClientSDK.a; sourceTree = ""; }; + A9744F4C1B3155160082301D /* EaseMob.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = EaseMob.bundle; sourceTree = ""; }; + A9744F501B3155690082301D /* libstdc++.6.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.6.dylib"; path = "usr/lib/libstdc++.6.dylib"; sourceTree = SDKROOT; }; + A9744F521B31557A0082301D /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; }; + A9744F541B3155950082301D /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = usr/lib/libresolv.dylib; sourceTree = SDKROOT; }; + A9744F561B3155A60082301D /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + A9744F581B3155B00082301D /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; A9754A0E1ADC080E0018BAAD /* AudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioPlayer.h; sourceTree = ""; }; A9754A0F1ADC080E0018BAAD /* AudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioPlayer.m; sourceTree = ""; }; A9754A101ADC080E0018BAAD /* AutoRecoveringHttpDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoRecoveringHttpDataSource.h; sourceTree = ""; }; @@ -432,6 +698,23 @@ A97559CB1ACBF0BC004ADA42 /* btn_share@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "btn_share@2x.png"; sourceTree = ""; }; A97883871AD369DF00D46477 /* mainCellDingClick@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mainCellDingClick@2x.png"; sourceTree = ""; }; A97883891AD36A0500D46477 /* mainCellDing@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mainCellDing@2x.png"; sourceTree = ""; }; + A978CB231B3A3D5A00028C4A /* chat_sender_audio_playing_000@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_sender_audio_playing_000@2x.png"; sourceTree = ""; }; + A978CB241B3A3D5A00028C4A /* chat_sender_audio_playing_001@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_sender_audio_playing_001@2x.png"; sourceTree = ""; }; + A978CB251B3A3D5A00028C4A /* chat_sender_audio_playing_002@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_sender_audio_playing_002@2x.png"; sourceTree = ""; }; + A978CB261B3A3D5A00028C4A /* chat_sender_audio_playing_003@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_sender_audio_playing_003@2x.png"; sourceTree = ""; }; + A978CB271B3A3D5A00028C4A /* chat_sender_audio_playing_full@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_sender_audio_playing_full@2x.png"; sourceTree = ""; }; + A978CB281B3A3D5A00028C4A /* chat_sender_bg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_sender_bg@2x.png"; sourceTree = ""; }; + A978CB2F1B3A3D6700028C4A /* chat_receiver_audio_playing_full@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_receiver_audio_playing_full@2x.png"; sourceTree = ""; }; + A978CB301B3A3D6700028C4A /* chat_receiver_audio_playing000@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_receiver_audio_playing000@2x.png"; sourceTree = ""; }; + A978CB311B3A3D6700028C4A /* chat_receiver_audio_playing001@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_receiver_audio_playing001@2x.png"; sourceTree = ""; }; + A978CB321B3A3D6700028C4A /* chat_receiver_audio_playing002@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_receiver_audio_playing002@2x.png"; sourceTree = ""; }; + A978CB331B3A3D6700028C4A /* chat_receiver_audio_playing003@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_receiver_audio_playing003@2x.png"; sourceTree = ""; }; + A978CB341B3A3D6700028C4A /* chat_receiver_bg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_receiver_bg@2x.png"; sourceTree = ""; }; + A978CB3B1B3A3D7100028C4A /* chat_location_annotation_someone@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_location_annotation_someone@2x.png"; sourceTree = ""; }; + A978CB3C1B3A3D7100028C4A /* chat_location_detail_disclosure@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_location_detail_disclosure@2x.png"; sourceTree = ""; }; + A978CB3D1B3A3D7100028C4A /* chat_location_detail_disclosureHL@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_location_detail_disclosureHL@2x.png"; sourceTree = ""; }; + A978CB3E1B3A3D7100028C4A /* chat_location_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chat_location_preview@2x.png"; sourceTree = ""; }; + A978CB431B3A3D8800028C4A /* chatListCellHead@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "chatListCellHead@2x.png"; sourceTree = ""; }; A97938731B20A63D00180C08 /* UserViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserViewModel.h; sourceTree = ""; }; A97938741B20A63D00180C08 /* UserViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserViewModel.m; sourceTree = ""; }; A97938761B20BB0900180C08 /* CommentViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommentViewModel.h; sourceTree = ""; }; @@ -563,6 +846,16 @@ A9B6DFE51B2033A80003C1BC /* toolbar_light_comment@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "toolbar_light_comment@2x.png"; sourceTree = ""; }; A9B6DFED1B2068790003C1BC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; A9B6DFEF1B20687B0003C1BC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + A9B8FEBB1B32930100619C7D /* libEaseMobClientSDKLite.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libEaseMobClientSDKLite.a; sourceTree = ""; }; + A9B8FEC21B32A4CF00619C7D /* ChatMainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatMainViewController.h; sourceTree = ""; }; + A9B8FEC31B32A4CF00619C7D /* ChatMainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatMainViewController.m; sourceTree = ""; }; + A9B8FEC41B32A4CF00619C7D /* ChatMainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChatMainViewController.xib; sourceTree = ""; }; + A9B8FEC71B32AC6F00619C7D /* DXMessageToolBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DXMessageToolBar.h; sourceTree = ""; }; + A9B8FEC81B32AC7000619C7D /* DXMessageToolBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DXMessageToolBar.m; sourceTree = ""; }; + A9B8FECA1B32ACA900619C7D /* DXChatBarMoreView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DXChatBarMoreView.h; sourceTree = ""; }; + A9B8FECB1B32ACA900619C7D /* DXChatBarMoreView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DXChatBarMoreView.m; sourceTree = ""; }; + A9B8FECD1B32B0F200619C7D /* MessageTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageTableView.h; sourceTree = ""; }; + A9B8FECE1B32B0F200619C7D /* MessageTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageTableView.m; sourceTree = ""; }; A9BE23BD1ACD8CA20032171A /* libSocialSina.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libSocialSina.a; sourceTree = ""; }; A9BE23BE1ACD8CA20032171A /* UMSocialSinaHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UMSocialSinaHandler.h; sourceTree = ""; }; A9CF211A1B1C36D0007490EF /* mainCellCommentClickN@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "mainCellCommentClickN@2x.png"; sourceTree = ""; }; @@ -578,6 +871,55 @@ A9E2711A1ADB97ED000B1542 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; A9E2711D1ADBB25C000B1542 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; A9EA14C21B02E88300357529 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; + A9F7F4551B33B37600317F3E /* LocationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationViewController.h; sourceTree = ""; }; + A9F7F4561B33B37600317F3E /* LocationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocationViewController.m; sourceTree = ""; }; + A9F7F4581B33B51F00317F3E /* back@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "back@2x.png"; sourceTree = ""; }; + A9F7F45B1B33BC4E00317F3E /* callRing.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = callRing.mp3; sourceTree = ""; }; + A9F7F45C1B33BC4E00317F3E /* CallViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallViewController.h; sourceTree = ""; }; + A9F7F45D1B33BC4E00317F3E /* CallViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallViewController.m; sourceTree = ""; }; + A9F7F4601B33BF6700317F3E /* call_out_h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_out_h@2x.png"; sourceTree = ""; }; + A9F7F4611B33BF6700317F3E /* call_out@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_out@2x.png"; sourceTree = ""; }; + A9F7F4621B33BF6700317F3E /* call_silence_h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_silence_h@2x.png"; sourceTree = ""; }; + A9F7F4631B33BF6700317F3E /* call_silence@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "call_silence@2x.png"; sourceTree = ""; }; + A9F7F4641B33BF6700317F3E /* callBg@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "callBg@2x.png"; sourceTree = ""; }; + A9F7F4651B33BF6700317F3E /* imageDownloadFail@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "imageDownloadFail@2x.png"; sourceTree = ""; }; + A9F7F4661B33BF6700317F3E /* messageSendFail@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "messageSendFail@2x.png"; sourceTree = ""; }; + A9F917A91B3900270007A3AC /* ChatSendHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatSendHelper.h; sourceTree = ""; }; + A9F917AA1B3900270007A3AC /* ChatSendHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatSendHelper.m; sourceTree = ""; }; + A9F917AC1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConvertToCommonEmoticonsHelper.h; sourceTree = ""; }; + A9F917AD1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConvertToCommonEmoticonsHelper.m; sourceTree = ""; }; + A9F917B11B39055A0007A3AC /* EMChatAudioBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatAudioBubbleView.h; sourceTree = ""; }; + A9F917B21B39055A0007A3AC /* EMChatAudioBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatAudioBubbleView.m; sourceTree = ""; }; + A9F917B31B39055A0007A3AC /* EMChatBaseBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatBaseBubbleView.h; sourceTree = ""; }; + A9F917B41B39055A0007A3AC /* EMChatBaseBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatBaseBubbleView.m; sourceTree = ""; }; + A9F917B51B39055A0007A3AC /* EMChatImageBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatImageBubbleView.h; sourceTree = ""; }; + A9F917B61B39055A0007A3AC /* EMChatImageBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatImageBubbleView.m; sourceTree = ""; }; + A9F917B71B39055A0007A3AC /* EMChatLocationBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatLocationBubbleView.h; sourceTree = ""; }; + A9F917B81B39055A0007A3AC /* EMChatLocationBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatLocationBubbleView.m; sourceTree = ""; }; + A9F917B91B39055A0007A3AC /* EMChatTextBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatTextBubbleView.h; sourceTree = ""; }; + A9F917BA1B39055A0007A3AC /* EMChatTextBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatTextBubbleView.m; sourceTree = ""; }; + A9F917BB1B39055A0007A3AC /* EMChatVideoBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatVideoBubbleView.h; sourceTree = ""; }; + A9F917BC1B39055A0007A3AC /* EMChatVideoBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatVideoBubbleView.m; sourceTree = ""; }; + A9F917BD1B39055A0007A3AC /* EMChatTimeCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatTimeCell.h; sourceTree = ""; }; + A9F917BE1B39055A0007A3AC /* EMChatTimeCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatTimeCell.m; sourceTree = ""; }; + A9F917BF1B39055A0007A3AC /* EMChatViewBaseCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatViewBaseCell.h; sourceTree = ""; }; + A9F917C01B39055A0007A3AC /* EMChatViewBaseCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatViewBaseCell.m; sourceTree = ""; }; + A9F917C11B39055A0007A3AC /* EMChatViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMChatViewCell.h; sourceTree = ""; }; + A9F917C21B39055A0007A3AC /* EMChatViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMChatViewCell.m; sourceTree = ""; }; + A9F917CC1B3906150007A3AC /* MessageModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageModel.h; sourceTree = ""; }; + A9F917CD1B3906150007A3AC /* MessageModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageModel.m; sourceTree = ""; }; + A9F917CE1B3906150007A3AC /* MessageModelManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageModelManager.h; sourceTree = ""; }; + A9F917CF1B3906150007A3AC /* MessageModelManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageModelManager.m; sourceTree = ""; }; + A9F917D01B3906150007A3AC /* MessageReadManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessageReadManager.h; sourceTree = ""; }; + A9F917D11B3906150007A3AC /* MessageReadManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MessageReadManager.m; sourceTree = ""; }; + A9F917D51B39091A0007A3AC /* NSDate+Category.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+Category.h"; sourceTree = ""; }; + A9F917D61B39091A0007A3AC /* NSDate+Category.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Category.m"; sourceTree = ""; }; + A9F917D81B390A220007A3AC /* NSDateFormatter+Category.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDateFormatter+Category.h"; sourceTree = ""; }; + A9F917D91B390A220007A3AC /* NSDateFormatter+Category.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDateFormatter+Category.m"; sourceTree = ""; }; + A9F917DC1B390AE70007A3AC /* THProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = THProgressView.h; sourceTree = ""; }; + A9F917DD1B390AE70007A3AC /* THProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = THProgressView.m; sourceTree = ""; }; + A9F917DF1B390AFE0007A3AC /* UIResponder+Router.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIResponder+Router.h"; sourceTree = ""; }; + A9F917E01B390AFE0007A3AC /* UIResponder+Router.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIResponder+Router.m"; sourceTree = ""; }; A9FAD41F1AC922A5007ADC10 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; A9FAD4201AC922A5007ADC10 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; A9FAD4211AC922A5007ADC10 /* MainViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainViewController.xib; sourceTree = ""; }; @@ -606,10 +948,18 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9E2711E1ADBB25C000B1542 /* AVFoundation.framework in Frameworks */, + A9744F591B3155B00082301D /* MobileCoreServices.framework in Frameworks */, + A971EDCB1B32B6A40023740E /* libopencore-amrnb.a in Frameworks */, + A9744F571B3155A60082301D /* CFNetwork.framework in Frameworks */, + A9744F551B3155950082301D /* libresolv.dylib in Frameworks */, A98F98661ACA2A9F007C4594 /* libz.dylib in Frameworks */, + A9744F531B31557A0082301D /* libxml2.dylib in Frameworks */, + A9744F511B3155690082301D /* libstdc++.6.dylib in Frameworks */, + A9744F4D1B3155160082301D /* libEaseMobClientSDK.a in Frameworks */, + A9E2711E1ADBB25C000B1542 /* AVFoundation.framework in Frameworks */, A98F98641ACA2A95007C4594 /* libstdc++.dylib in Frameworks */, A98F98621ACA2A8E007C4594 /* CoreTelephony.framework in Frameworks */, + A971EDCC1B32B6A40023740E /* libopencore-amrwb.a in Frameworks */, A98F98601ACA2A86007C4594 /* libsqlite3.dylib in Frameworks */, A98F985E1ACA2A77007C4594 /* CoreGraphics.framework in Frameworks */, A98F985C1ACA2A6F007C4594 /* SystemConfiguration.framework in Frameworks */, @@ -856,6 +1206,370 @@ path = User; sourceTree = ""; }; + A971ED9D1B32B5740023740E /* DeviceUtil */ = { + isa = PBXGroup; + children = ( + A971ED9E1B32B5740023740E /* delegates */, + A971EDA11B32B5740023740E /* internal */, + ); + path = DeviceUtil; + sourceTree = ""; + }; + A971ED9E1B32B5740023740E /* delegates */ = { + isa = PBXGroup; + children = ( + A971ED9F1B32B5740023740E /* EMCDDeviceManagerDelegate.h */, + A971EDA01B32B5740023740E /* EMCDDeviceManagerProximitySensorDelegate.h */, + ); + path = delegates; + sourceTree = ""; + }; + A971EDA11B32B5740023740E /* internal */ = { + isa = PBXGroup; + children = ( + A971EDA21B32B5740023740E /* EMAudioPlayerUtil.h */, + A971EDA31B32B5740023740E /* EMAudioPlayerUtil.m */, + A971EDA41B32B5740023740E /* EMAudioRecorderUtil.h */, + A971EDA51B32B5740023740E /* EMAudioRecorderUtil.m */, + A971EDA61B32B5740023740E /* EMCDDeviceManager+Media.h */, + A971EDA71B32B5740023740E /* EMCDDeviceManager+Media.m */, + A971EDA81B32B5740023740E /* EMCDDeviceManager+Microphone.h */, + A971EDA91B32B5740023740E /* EMCDDeviceManager+Microphone.m */, + A971EDAA1B32B5740023740E /* EMCDDeviceManager+ProximitySensor.h */, + A971EDAB1B32B5740023740E /* EMCDDeviceManager+ProximitySensor.m */, + A971EDAC1B32B5740023740E /* EMCDDeviceManager+Remind.h */, + A971EDAD1B32B5740023740E /* EMCDDeviceManager+Remind.m */, + A971EDAE1B32B5740023740E /* EMCDDeviceManager.h */, + A971EDAF1B32B5740023740E /* EMCDDeviceManagerBase.h */, + A971EDB01B32B5740023740E /* EMCDDeviceManagerBase.m */, + ); + path = internal; + sourceTree = ""; + }; + A971EDB81B32B6A40023740E /* VoiceConvert */ = { + isa = PBXGroup; + children = ( + A971EDB91B32B6A40023740E /* amrwapper */, + A971EDBE1B32B6A40023740E /* EMVoiceConverter.h */, + A971EDBF1B32B6A40023740E /* EMVoiceConverter.mm */, + A971EDC01B32B6A40023740E /* opencore-amrnb */, + A971EDC41B32B6A40023740E /* opencore-amrwb */, + ); + path = VoiceConvert; + sourceTree = ""; + }; + A971EDB91B32B6A40023740E /* amrwapper */ = { + isa = PBXGroup; + children = ( + A971EDBA1B32B6A40023740E /* amrFileCodec.h */, + A971EDBB1B32B6A40023740E /* amrFileCodec.mm */, + A971EDBC1B32B6A40023740E /* wav.h */, + A971EDBD1B32B6A40023740E /* wav.mm */, + ); + path = amrwapper; + sourceTree = ""; + }; + A971EDC01B32B6A40023740E /* opencore-amrnb */ = { + isa = PBXGroup; + children = ( + A971EDC11B32B6A40023740E /* interf_dec.h */, + A971EDC21B32B6A40023740E /* interf_enc.h */, + A971EDC31B32B6A40023740E /* libopencore-amrnb.a */, + ); + path = "opencore-amrnb"; + sourceTree = ""; + }; + A971EDC41B32B6A40023740E /* opencore-amrwb */ = { + isa = PBXGroup; + children = ( + A971EDC51B32B6A40023740E /* dec_if.h */, + A971EDC61B32B6A40023740E /* if_rom.h */, + A971EDC71B32B6A40023740E /* libopencore-amrwb.a */, + ); + path = "opencore-amrwb"; + sourceTree = ""; + }; + A971EDCD1B32B6CF0023740E /* Emoji */ = { + isa = PBXGroup; + children = ( + A971EDCE1B32B6CF0023740E /* Emoji.h */, + A971EDCF1B32B6CF0023740E /* Emoji.m */, + A971EDD01B32B6CF0023740E /* EmojiEmoticons.h */, + A971EDD11B32B6CF0023740E /* EmojiEmoticons.m */, + ); + path = Emoji; + sourceTree = ""; + }; + A9744EDF1B3155150082301D /* EaseMobSDK */ = { + isa = PBXGroup; + children = ( + A9744EE01B3155150082301D /* include */, + A9744F481B3155160082301D /* lib */, + A9744F4B1B3155160082301D /* resources */, + ); + path = EaseMobSDK; + sourceTree = ""; + }; + A9744EE01B3155150082301D /* include */ = { + isa = PBXGroup; + children = ( + A9744EE11B3155150082301D /* CallService */, + A9744EF01B3155150082301D /* ChatService */, + A9744F2F1B3155160082301D /* EaseMobClientSDK */, + A9744F341B3155160082301D /* EaseMobClientSDKLite */, + A9744F371B3155160082301D /* Utility */, + ); + path = include; + sourceTree = ""; + }; + A9744EE11B3155150082301D /* CallService */ = { + isa = PBXGroup; + children = ( + A9744EE21B3155150082301D /* EMCallManager */, + ); + path = CallService; + sourceTree = ""; + }; + A9744EE21B3155150082301D /* EMCallManager */ = { + isa = PBXGroup; + children = ( + A9744EE31B3155150082301D /* delegates */, + A9744EE61B3155150082301D /* EaseMob+CallService.h */, + A9744EE71B3155150082301D /* EMCallServiceDefs.h */, + A9744EE81B3155150082301D /* ICallManager.h */, + A9744EE91B3155150082301D /* internal */, + A9744EEC1B3155150082301D /* types */, + ); + path = EMCallManager; + sourceTree = ""; + }; + A9744EE31B3155150082301D /* delegates */ = { + isa = PBXGroup; + children = ( + A9744EE41B3155150082301D /* EMCallManagerCallDelegate.h */, + A9744EE51B3155150082301D /* EMCallManagerDelegate.h */, + ); + path = delegates; + sourceTree = ""; + }; + A9744EE91B3155150082301D /* internal */ = { + isa = PBXGroup; + children = ( + A9744EEA1B3155150082301D /* ICallManagerBase.h */, + A9744EEB1B3155150082301D /* ICallManagerCall.h */, + ); + path = internal; + sourceTree = ""; + }; + A9744EEC1B3155150082301D /* types */ = { + isa = PBXGroup; + children = ( + A9744EED1B3155150082301D /* EMCallSession.h */, + A9744EEE1B3155150082301D /* IOpenGLView.h */, + A9744EEF1B3155150082301D /* OpenGLView20.h */, + ); + path = types; + sourceTree = ""; + }; + A9744EF01B3155150082301D /* ChatService */ = { + isa = PBXGroup; + children = ( + A9744EF11B3155150082301D /* EMChatManager */, + ); + path = ChatService; + sourceTree = ""; + }; + A9744EF11B3155150082301D /* EMChatManager */ = { + isa = PBXGroup; + children = ( + A9744EF21B3155150082301D /* delegates */, + A9744EFF1B3155150082301D /* EMChatManagerDefs.h */, + A9744F001B3155150082301D /* EMGroupManagerDefs.h */, + A9744F011B3155150082301D /* EMPushManagerDefs.h */, + A9744F021B3155150082301D /* IChatManager.h */, + A9744F031B3155150082301D /* internal */, + A9744F0F1B3155160082301D /* types */, + ); + path = EMChatManager; + sourceTree = ""; + }; + A9744EF21B3155150082301D /* delegates */ = { + isa = PBXGroup; + children = ( + A9744EF31B3155150082301D /* IChatManagerDelegate.h */, + A9744EF41B3155150082301D /* internal */, + ); + path = delegates; + sourceTree = ""; + }; + A9744EF41B3155150082301D /* internal */ = { + isa = PBXGroup; + children = ( + A9744EF51B3155150082301D /* EMChatManagerBuddyDelegate.h */, + A9744EF61B3155150082301D /* EMChatManagerChatDelegate.h */, + A9744EF71B3155150082301D /* EMChatManagerChatroomDelegate.h */, + A9744EF81B3155150082301D /* EMChatManagerDelegate.h */, + A9744EF91B3155150082301D /* EMChatManagerDelegateBase.h */, + A9744EFA1B3155150082301D /* EMChatManagerEncryptionDelegate.h */, + A9744EFB1B3155150082301D /* EMChatManagerGroupDelegate.h */, + A9744EFC1B3155150082301D /* EMChatManagerLoginDelegate.h */, + A9744EFD1B3155150082301D /* EMChatManagerPushNotificationDelegate.h */, + A9744EFE1B3155150082301D /* EMChatManagerUtilDelegate.h */, + ); + path = internal; + sourceTree = ""; + }; + A9744F031B3155150082301D /* internal */ = { + isa = PBXGroup; + children = ( + A9744F041B3155150082301D /* IChatManagerBase.h */, + A9744F051B3155150082301D /* IChatManagerBuddy.h */, + A9744F061B3155150082301D /* IChatManagerChat.h */, + A9744F071B3155150082301D /* IChatManagerChatroom.h */, + A9744F081B3155160082301D /* IChatManagerConversation.h */, + A9744F091B3155160082301D /* IChatManagerEncryption.h */, + A9744F0A1B3155160082301D /* IChatManagerGroup.h */, + A9744F0B1B3155160082301D /* IChatManagerLogin.h */, + A9744F0C1B3155160082301D /* IChatManagerPushNotification.h */, + A9744F0D1B3155160082301D /* IChatManagerSettingOptions.h */, + A9744F0E1B3155160082301D /* IChatManagerUtil.h */, + ); + path = internal; + sourceTree = ""; + }; + A9744F0F1B3155160082301D /* types */ = { + isa = PBXGroup; + children = ( + A9744F101B3155160082301D /* EMBuddy.h */, + A9744F111B3155160082301D /* EMChatCommand.h */, + A9744F121B3155160082301D /* EMChatFile.h */, + A9744F131B3155160082301D /* EMChatImage.h */, + A9744F141B3155160082301D /* EMChatLocation.h */, + A9744F151B3155160082301D /* EMChatroom.h */, + A9744F161B3155160082301D /* EMChatText.h */, + A9744F171B3155160082301D /* EMChatVideo.h */, + A9744F181B3155160082301D /* EMChatVoice.h */, + A9744F191B3155160082301D /* EMCommandMessageBody.h */, + A9744F1A1B3155160082301D /* EMConversation.h */, + A9744F1B1B3155160082301D /* EMCursorResult.h */, + A9744F1C1B3155160082301D /* EMFileMessageBody.h */, + A9744F1D1B3155160082301D /* EMGroup.h */, + A9744F1E1B3155160082301D /* EMGroupStyleSetting.h */, + A9744F1F1B3155160082301D /* EMImageMessageBody.h */, + A9744F201B3155160082301D /* EMLocationMessageBody.h */, + A9744F211B3155160082301D /* EMMessage.h */, + A9744F221B3155160082301D /* EMPushNotificationOptions.h */, + A9744F231B3155160082301D /* EMReceipt.h */, + A9744F241B3155160082301D /* EMReceiptBase.h */, + A9744F251B3155160082301D /* EMTextMessageBody.h */, + A9744F261B3155160082301D /* EMVideoMessageBody.h */, + A9744F271B3155160082301D /* EMVoiceMessageBody.h */, + A9744F281B3155160082301D /* IChatImageOptions.h */, + A9744F291B3155160082301D /* IEMChatCryptor.h */, + A9744F2A1B3155160082301D /* IEMChatFile.h */, + A9744F2B1B3155160082301D /* IEMChatObject.h */, + A9744F2C1B3155160082301D /* IEMChatProgressDelegate.h */, + A9744F2D1B3155160082301D /* IEMFileMessageBody.h */, + A9744F2E1B3155160082301D /* IEMMessageBody.h */, + ); + path = types; + sourceTree = ""; + }; + A9744F2F1B3155160082301D /* EaseMobClientSDK */ = { + isa = PBXGroup; + children = ( + A9744F301B3155160082301D /* EaseMob.h */, + A9744F311B3155160082301D /* EaseMobHeaders.h */, + A9744F321B3155160082301D /* EMSDKFull.h */, + A9744F331B3155160082301D /* EMSDKFullHeaders.h */, + ); + path = EaseMobClientSDK; + sourceTree = ""; + }; + A9744F341B3155160082301D /* EaseMobClientSDKLite */ = { + isa = PBXGroup; + children = ( + A9744F351B3155160082301D /* EaseMob.h */, + A9744F361B3155160082301D /* EaseMobHeaders.h */, + ); + path = EaseMobClientSDKLite; + sourceTree = ""; + }; + A9744F371B3155160082301D /* Utility */ = { + isa = PBXGroup; + children = ( + A9744F381B3155160082301D /* commonDefs.h */, + A9744F391B3155160082301D /* EMDeviceManager */, + A9744F441B3155160082301D /* EMNetworkMonitorDefs.h */, + A9744F451B3155160082301D /* ErrorManager */, + ); + path = Utility; + sourceTree = ""; + }; + A9744F391B3155160082301D /* EMDeviceManager */ = { + isa = PBXGroup; + children = ( + A9744F3A1B3155160082301D /* delegates */, + A9744F401B3155160082301D /* EMDeviceManagerDefs.h */, + A9744F411B3155160082301D /* IDeviceManager.h */, + A9744F421B3155160082301D /* internal */, + ); + path = EMDeviceManager; + sourceTree = ""; + }; + A9744F3A1B3155160082301D /* delegates */ = { + isa = PBXGroup; + children = ( + A9744F3B1B3155160082301D /* IDeviceManagerDelegate.h */, + A9744F3C1B3155160082301D /* internal */, + ); + path = delegates; + sourceTree = ""; + }; + A9744F3C1B3155160082301D /* internal */ = { + isa = PBXGroup; + children = ( + A9744F3D1B3155160082301D /* EMDeviceManagerDelegate.h */, + A9744F3E1B3155160082301D /* EMDeviceManagerDelegateBase.h */, + A9744F3F1B3155160082301D /* EMDeviceManagerNetworkDelegate.h */, + ); + path = internal; + sourceTree = ""; + }; + A9744F421B3155160082301D /* internal */ = { + isa = PBXGroup; + children = ( + A9744F431B3155160082301D /* IDeviceManagerBase.h */, + ); + path = internal; + sourceTree = ""; + }; + A9744F451B3155160082301D /* ErrorManager */ = { + isa = PBXGroup; + children = ( + A9744F461B3155160082301D /* EMError.h */, + A9744F471B3155160082301D /* EMErrorDefs.h */, + ); + path = ErrorManager; + sourceTree = ""; + }; + A9744F481B3155160082301D /* lib */ = { + isa = PBXGroup; + children = ( + A9744F491B3155160082301D /* libEaseMobClientSDK.a */, + A9B8FEBB1B32930100619C7D /* libEaseMobClientSDKLite.a */, + ); + path = lib; + sourceTree = ""; + }; + A9744F4B1B3155160082301D /* resources */ = { + isa = PBXGroup; + children = ( + A9744F4C1B3155160082301D /* EaseMob.bundle */, + ); + path = resources; + sourceTree = ""; + }; A9754A0D1ADC080E0018BAAD /* AudioPlayer */ = { isa = PBXGroup; children = ( @@ -936,6 +1650,7 @@ A97C54B71AC8F0370038818A /* ViewControllers */ = { isa = PBXGroup; children = ( + A9B8FEC11B32A35800619C7D /* Chat */, A96F27EF1B21B98900DA0A66 /* User */, A98D65971AD37BDF008668EE /* Message */, A9617A501ACC274C0024AE4A /* My */, @@ -1022,6 +1737,7 @@ A97C54D91AC9014D0038818A /* Vender */ = { isa = PBXGroup; children = ( + A9744EDF1B3155150082301D /* EaseMobSDK */, A96D2F231B2FFD9C00DC0284 /* DejalActivityView */, A9A3A7551B281392001AAB3A /* CExpandHeader */, A9754A0D1ADC080E0018BAAD /* AudioPlayer */, @@ -1062,6 +1778,53 @@ A97C54E21AC91FD70038818A /* Resource */ = { isa = PBXGroup; children = ( + A9F7F4581B33B51F00317F3E /* back@2x.png */, + A971EDF61B32B7C40023740E /* chatBar_colorMore_audioCall@2x.png */, + A971EDF71B32B7C40023740E /* chatBar_colorMore_audioCallSelected@2x.png */, + A971EDF81B32B7C40023740E /* chatBar_colorMore_camera@2x.png */, + A971EDF91B32B7C40023740E /* chatBar_colorMore_cameraSelected@2x.png */, + A971EDFA1B32B7C40023740E /* chatBar_colorMore_location@2x.png */, + A971EDFB1B32B7C40023740E /* chatBar_colorMore_locationSelected@2x.png */, + A971EDFC1B32B7C40023740E /* chatBar_colorMore_photo@2x.png */, + A971EDFD1B32B7C40023740E /* chatBar_colorMore_photoSelected@2x.png */, + A971EDFE1B32B7C40023740E /* chatBar_colorMore_video@2x.png */, + A971EDFF1B32B7C40023740E /* chatBar_colorMore_videoCall@2x.png */, + A978CB3B1B3A3D7100028C4A /* chat_location_annotation_someone@2x.png */, + A978CB3C1B3A3D7100028C4A /* chat_location_detail_disclosure@2x.png */, + A978CB3D1B3A3D7100028C4A /* chat_location_detail_disclosureHL@2x.png */, + A978CB3E1B3A3D7100028C4A /* chat_location_preview@2x.png */, + A971EE001B32B7C40023740E /* chatBar_colorMore_videoCallSelected@2x.png */, + A971EE011B32B7C40023740E /* chatBar_colorMore_videoSelected@2x.png */, + A971EDEA1B32B7AF0023740E /* chatBar_more_camera@2x.png */, + A971EDEB1B32B7AF0023740E /* chatBar_more_cameraSelected@2x.png */, + A971EDEC1B32B7AF0023740E /* chatBar_more_location@2x.png */, + A971EDED1B32B7AF0023740E /* chatBar_more_locationSelected@2x.png */, + A978CB2F1B3A3D6700028C4A /* chat_receiver_audio_playing_full@2x.png */, + A978CB301B3A3D6700028C4A /* chat_receiver_audio_playing000@2x.png */, + A978CB311B3A3D6700028C4A /* chat_receiver_audio_playing001@2x.png */, + A978CB321B3A3D6700028C4A /* chat_receiver_audio_playing002@2x.png */, + A978CB431B3A3D8800028C4A /* chatListCellHead@2x.png */, + A978CB331B3A3D6700028C4A /* chat_receiver_audio_playing003@2x.png */, + A978CB341B3A3D6700028C4A /* chat_receiver_bg@2x.png */, + A971EDEE1B32B7AF0023740E /* chatBar_more_photo@2x.png */, + A971EDEF1B32B7AF0023740E /* chatBar_more_photoSelected@2x.png */, + A978CB231B3A3D5A00028C4A /* chat_sender_audio_playing_000@2x.png */, + A978CB241B3A3D5A00028C4A /* chat_sender_audio_playing_001@2x.png */, + A978CB251B3A3D5A00028C4A /* chat_sender_audio_playing_002@2x.png */, + A978CB261B3A3D5A00028C4A /* chat_sender_audio_playing_003@2x.png */, + A978CB271B3A3D5A00028C4A /* chat_sender_audio_playing_full@2x.png */, + A978CB281B3A3D5A00028C4A /* chat_sender_bg@2x.png */, + A971EDE21B32B7A00023740E /* chatBar_record@2x.png */, + A971EDE31B32B7A00023740E /* chatBar_recordBg@2x.png */, + A971EDE41B32B7A00023740E /* chatBar_recordSelected@2x.png */, + A971EDE51B32B7A00023740E /* chatBar_recordSelectedBg@2x.png */, + A971EDD61B32B7960023740E /* chatBar_face@2x.png */, + A971EDD71B32B7960023740E /* chatBar_faceSelected@2x.png */, + A971EDD81B32B7960023740E /* chatBar_keyboard@2x.png */, + A971EDD91B32B7960023740E /* chatBar_keyboardSelected@2x.png */, + A971EDDA1B32B7960023740E /* chatBar_more@2x.png */, + A971EDDB1B32B7960023740E /* chatBar_moreSelected@2x.png */, + A971EDD41B32B7790023740E /* messageToolbarBg@2x.png */, A9A3A7531B281178001AAB3A /* PersonalTopBg@2x.jpg */, A9A3A7511B2810DB001AAB3A /* Pofile_coverImage@2x.jpg */, A9B6DFE51B2033A80003C1BC /* toolbar_light_comment@2x.png */, @@ -1122,6 +1885,13 @@ A90BA01E1AD606AE00728393 /* voice-record-icon@2x.png */, A90BA0161AD6067F00728393 /* voice-continue-record-bg@2x.png */, A90BA0171AD6067F00728393 /* voice-continue-record-bgN@2x.png */, + A9F7F4601B33BF6700317F3E /* call_out_h@2x.png */, + A9F7F4611B33BF6700317F3E /* call_out@2x.png */, + A9F7F4621B33BF6700317F3E /* call_silence_h@2x.png */, + A9F7F4631B33BF6700317F3E /* call_silence@2x.png */, + A9F7F4641B33BF6700317F3E /* callBg@2x.png */, + A9F7F4651B33BF6700317F3E /* imageDownloadFail@2x.png */, + A9F7F4661B33BF6700317F3E /* messageSendFail@2x.png */, A9E271191ADB97ED000B1542 /* Default-568h.png */, A9E2711A1ADB97ED000B1542 /* Default.png */, A90BA0201AD606B400728393 /* voice-record-level@2x.png */, @@ -1313,6 +2083,54 @@ path = UMAnalytics_Sdk_3.4.6; sourceTree = ""; }; + A9B8FEC11B32A35800619C7D /* Chat */ = { + isa = PBXGroup; + children = ( + A9F7F45A1B33BC4E00317F3E /* Call */, + A971EDCD1B32B6CF0023740E /* Emoji */, + A971EDB81B32B6A40023740E /* VoiceConvert */, + A971ED9D1B32B5740023740E /* DeviceUtil */, + A9B8FECD1B32B0F200619C7D /* MessageTableView.h */, + A9B8FECE1B32B0F200619C7D /* MessageTableView.m */, + A9B8FECA1B32ACA900619C7D /* DXChatBarMoreView.h */, + A9B8FECB1B32ACA900619C7D /* DXChatBarMoreView.m */, + A9B8FEC71B32AC6F00619C7D /* DXMessageToolBar.h */, + A9B8FEC81B32AC7000619C7D /* DXMessageToolBar.m */, + A971ED941B32B5200023740E /* DXFaceView.h */, + A971ED951B32B5200023740E /* DXFaceView.m */, + A971ED9A1B32B53D0023740E /* FacialView.h */, + A971ED9B1B32B53D0023740E /* FacialView.m */, + A971ED971B32B5260023740E /* DXRecordView.h */, + A971ED981B32B5260023740E /* DXRecordView.m */, + A971ED911B32B50A0023740E /* XHMessageTextView.h */, + A971ED921B32B50A0023740E /* XHMessageTextView.m */, + A9F7F4551B33B37600317F3E /* LocationViewController.h */, + A9F7F4561B33B37600317F3E /* LocationViewController.m */, + A9F917DF1B390AFE0007A3AC /* UIResponder+Router.h */, + A9F917E01B390AFE0007A3AC /* UIResponder+Router.m */, + A9B8FEC21B32A4CF00619C7D /* ChatMainViewController.h */, + A9B8FEC31B32A4CF00619C7D /* ChatMainViewController.m */, + A9B8FEC41B32A4CF00619C7D /* ChatMainViewController.xib */, + A9F917D81B390A220007A3AC /* NSDateFormatter+Category.h */, + A9F917D91B390A220007A3AC /* NSDateFormatter+Category.m */, + A9F917D51B39091A0007A3AC /* NSDate+Category.h */, + A9F917D61B39091A0007A3AC /* NSDate+Category.m */, + A9F917AC1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.h */, + A9F917AD1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.m */, + A9F917A91B3900270007A3AC /* ChatSendHelper.h */, + A9F917AA1B3900270007A3AC /* ChatSendHelper.m */, + A9F917CC1B3906150007A3AC /* MessageModel.h */, + A9F917CD1B3906150007A3AC /* MessageModel.m */, + A9F917CE1B3906150007A3AC /* MessageModelManager.h */, + A9F917CF1B3906150007A3AC /* MessageModelManager.m */, + A9F917D01B3906150007A3AC /* MessageReadManager.h */, + A9F917D11B3906150007A3AC /* MessageReadManager.m */, + A9F917DB1B390AE70007A3AC /* THProgressView */, + A9F917AF1B39055A0007A3AC /* ChatCell */, + ); + path = Chat; + sourceTree = ""; + }; A9BE23BC1ACD8CA20032171A /* Sina */ = { isa = PBXGroup; children = ( @@ -1338,6 +2156,58 @@ path = Common; sourceTree = ""; }; + A9F7F45A1B33BC4E00317F3E /* Call */ = { + isa = PBXGroup; + children = ( + A9F7F45B1B33BC4E00317F3E /* callRing.mp3 */, + A9F7F45C1B33BC4E00317F3E /* CallViewController.h */, + A9F7F45D1B33BC4E00317F3E /* CallViewController.m */, + ); + path = Call; + sourceTree = ""; + }; + A9F917AF1B39055A0007A3AC /* ChatCell */ = { + isa = PBXGroup; + children = ( + A9F917B01B39055A0007A3AC /* ChatCellBubble */, + A9F917BD1B39055A0007A3AC /* EMChatTimeCell.h */, + A9F917BE1B39055A0007A3AC /* EMChatTimeCell.m */, + A9F917BF1B39055A0007A3AC /* EMChatViewBaseCell.h */, + A9F917C01B39055A0007A3AC /* EMChatViewBaseCell.m */, + A9F917C11B39055A0007A3AC /* EMChatViewCell.h */, + A9F917C21B39055A0007A3AC /* EMChatViewCell.m */, + ); + path = ChatCell; + sourceTree = ""; + }; + A9F917B01B39055A0007A3AC /* ChatCellBubble */ = { + isa = PBXGroup; + children = ( + A9F917B11B39055A0007A3AC /* EMChatAudioBubbleView.h */, + A9F917B21B39055A0007A3AC /* EMChatAudioBubbleView.m */, + A9F917B31B39055A0007A3AC /* EMChatBaseBubbleView.h */, + A9F917B41B39055A0007A3AC /* EMChatBaseBubbleView.m */, + A9F917B51B39055A0007A3AC /* EMChatImageBubbleView.h */, + A9F917B61B39055A0007A3AC /* EMChatImageBubbleView.m */, + A9F917B71B39055A0007A3AC /* EMChatLocationBubbleView.h */, + A9F917B81B39055A0007A3AC /* EMChatLocationBubbleView.m */, + A9F917B91B39055A0007A3AC /* EMChatTextBubbleView.h */, + A9F917BA1B39055A0007A3AC /* EMChatTextBubbleView.m */, + A9F917BB1B39055A0007A3AC /* EMChatVideoBubbleView.h */, + A9F917BC1B39055A0007A3AC /* EMChatVideoBubbleView.m */, + ); + path = ChatCellBubble; + sourceTree = ""; + }; + A9F917DB1B390AE70007A3AC /* THProgressView */ = { + isa = PBXGroup; + children = ( + A9F917DC1B390AE70007A3AC /* THProgressView.h */, + A9F917DD1B390AE70007A3AC /* THProgressView.m */, + ); + path = THProgressView; + sourceTree = ""; + }; A9FAD41E1AC92293007ADC10 /* Main */ = { isa = PBXGroup; children = ( @@ -1372,6 +2242,11 @@ D600413F4BCED5BE80E26E1F /* Frameworks */ = { isa = PBXGroup; children = ( + A9744F581B3155B00082301D /* MobileCoreServices.framework */, + A9744F561B3155A60082301D /* CFNetwork.framework */, + A9744F541B3155950082301D /* libresolv.dylib */, + A9744F521B31557A0082301D /* libxml2.dylib */, + A9744F501B3155690082301D /* libstdc++.6.dylib */, A9E2711D1ADBB25C000B1542 /* AVFoundation.framework */, A98F98651ACA2A9F007C4594 /* libz.dylib */, A98F98631ACA2A95007C4594 /* libstdc++.dylib */, @@ -1446,41 +2321,62 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A9F7F4671B33BF6700317F3E /* call_out_h@2x.png in Resources */, A968624B1ACCF0B400DDAA6B /* MWPhotoBrowser.bundle in Resources */, A93442001ACA919F00A6B233 /* tabbarVoiceClick@2x.png in Resources */, A90BA0191AD6067F00728393 /* voice-continue-record-bgN@2x.png in Resources */, + A978CB291B3A3D5A00028C4A /* chat_sender_audio_playing_000@2x.png in Resources */, A97C55001AC933AD0038818A /* UMSCommentDetailController.xib in Resources */, A93441F21ACA916D00A6B233 /* tabbarQuotationClick@2x.png in Resources */, A90BA0011AD6031E00728393 /* MessagePublishViewController.xib in Resources */, A93442031ACA981D00A6B233 /* Default-568h@2x.png in Resources */, A9FAD4321AC923FC007ADC10 /* MyViewController.xib in Resources */, + A978CB2E1B3A3D5A00028C4A /* chat_sender_bg@2x.png in Resources */, + A9F7F45E1B33BC4E00317F3E /* callRing.mp3 in Resources */, + A978CB441B3A3D8800028C4A /* chatListCellHead@2x.png in Resources */, A9FD82B81B1D433800AC4DC9 /* accessoryN@2x.png in Resources */, A93441FF1ACA919F00A6B233 /* tabbarVoice@2x.png in Resources */, + A971EE0C1B32B7C40023740E /* chatBar_colorMore_videoCallSelected@2x.png in Resources */, A968627E1ACCF46E00DDAA6B /* cellmorebtnclickN@2x.png in Resources */, A9EA14C31B02E88300357529 /* LaunchScreen.xib in Resources */, A9CF211D1B1C36D0007490EF /* mainCellCommentN@2x.png in Resources */, + A978CB351B3A3D6700028C4A /* chat_receiver_audio_playing_full@2x.png in Resources */, A93441FA1ACA919500A6B233 /* tabbarQuotation-dark@2x.png in Resources */, A9B6DFE21B202E7D0003C1BC /* comment_support_plus@2x.png in Resources */, + A971EDE61B32B7A00023740E /* chatBar_record@2x.png in Resources */, + A971EDE71B32B7A00023740E /* chatBar_recordBg@2x.png in Resources */, A97559D01ACBF0BC004ADA42 /* btn_share_clicked@2x.png in Resources */, A90BA01F1AD606AE00728393 /* voice-record-icon@2x.png in Resources */, A9E2711B1ADB97ED000B1542 /* Default-568h.png in Resources */, A955109B1AC39E6A0006D16F /* Main.storyboard in Resources */, A966FB961AD62C5D00542068 /* icon_error@2x.png in Resources */, + A971EE021B32B7C40023740E /* chatBar_colorMore_audioCall@2x.png in Resources */, A97559A51ACB9748004ADA42 /* setup-head-default@2x.png in Resources */, A97DBE3F1ACAE29E00705682 /* Icon.png in Resources */, A98536871AEBDA1E000312BF /* OurLoginViewController.xib in Resources */, A9A3A75A1B281392001AAB3A /* image.png in Resources */, + A971EE061B32B7C40023740E /* chatBar_colorMore_location@2x.png in Resources */, + A971EE081B32B7C40023740E /* chatBar_colorMore_photo@2x.png in Resources */, A9754A271ADC199B0018BAAD /* MyMessageViewController.xib in Resources */, A94DF6361AD4D94E00DCDCB0 /* MyNoteViewController.xib in Resources */, + A978CB391B3A3D6700028C4A /* chat_receiver_audio_playing003@2x.png in Resources */, A9E2711C1ADB97ED000B1542 /* Default.png in Resources */, + A978CB381B3A3D6700028C4A /* chat_receiver_audio_playing002@2x.png in Resources */, + A9F7F46D1B33BF6700317F3E /* messageSendFail@2x.png in Resources */, A93441ED1ACA8C8F00A6B233 /* defaultUserIcon.png in Resources */, A97559CF1ACBF0BC004ADA42 /* btn_good@2x.png in Resources */, A97559CC1ACBF0BC004ADA42 /* btn_bad_clicked@2x.png in Resources */, + A9F7F46A1B33BF6700317F3E /* call_silence@2x.png in Resources */, A97DBE461ACAE7B500705682 /* iconWeixin@2x.png in Resources */, + A971EE041B32B7C40023740E /* chatBar_colorMore_camera@2x.png in Resources */, A94691CD1B26EACE00B5D26B /* PersonalInfoViewController.xib in Resources */, A96862421ACCF0B400DDAA6B /* LICENCE.txt in Resources */, A985367D1AEB8F89000312BF /* RegistInfoViewController.xib in Resources */, + A978CB2D1B3A3D5A00028C4A /* chat_sender_audio_playing_full@2x.png in Resources */, A9CF21281B1C53E3007490EF /* CommentGoodListCellTableViewCell.xib in Resources */, + A971EDF31B32B7AF0023740E /* chatBar_more_locationSelected@2x.png in Resources */, + A971EDF41B32B7AF0023740E /* chatBar_more_photo@2x.png in Resources */, + A971EE0A1B32B7C40023740E /* chatBar_colorMore_video@2x.png in Resources */, A99AA12F1ADD028400574B12 /* Icon120.png in Resources */, A98536821AEBC7BB000312BF /* SetUserInfoViewController.xib in Resources */, A97C55071AC933AD0038818A /* UMSShareListController.xib in Resources */, @@ -1491,13 +2387,16 @@ A90BA0081AD6060600728393 /* playButton@2x.png in Resources */, A9B6DFD61B201E4E0003C1BC /* share_close@2x.png in Resources */, A97C54FE1AC933AD0038818A /* UMSocialLocalizable.strings in Resources */, + A978CB3F1B3A3D7100028C4A /* chat_location_annotation_someone@2x.png in Resources */, A9B6DFD51B201E4E0003C1BC /* share_cancel_highlighted@2x.png in Resources */, A93441E91ACA8AD200A6B233 /* Profile_filter_ImageIcon@2x.png in Resources */, A97C55041AC933AD0038818A /* UMShareEditViewControlleriPad.xib in Resources */, + A971EDDC1B32B7960023740E /* chatBar_face@2x.png in Resources */, A978838A1AD36A0500D46477 /* mainCellDing@2x.png in Resources */, A98F98541ACA29B5007C4594 /* TencentOpenApi_IOS_Bundle.bundle in Resources */, A9CF211C1B1C36D0007490EF /* mainCellCommentClickN@2x.png in Resources */, A9617A591ACC2EBC0024AE4A /* mine-setting-icon@2x.png in Resources */, + A9744F4F1B3155160082301D /* EaseMob.bundle in Resources */, A968627C1ACCF3D200DDAA6B /* cellmorebtnnormalN@2x.png in Resources */, A96F27FA1B21C5C800DA0A66 /* PraiseUserListViewController.xib in Resources */, A93442041ACA981D00A6B233 /* Default@2x.png in Resources */, @@ -1511,26 +2410,39 @@ A9A3A7541B281178001AAB3A /* PersonalTopBg@2x.jpg in Resources */, A9B6DFE41B202E950003C1BC /* night_user_comment_circle@2x.png in Resources */, A9B4A9551AEDC3620017C655 /* FeedbackViewController.xib in Resources */, + A9F7F4591B33B51F00317F3E /* back@2x.png in Resources */, + A971EDDE1B32B7960023740E /* chatBar_keyboard@2x.png in Resources */, + A971EE071B32B7C40023740E /* chatBar_colorMore_locationSelected@2x.png in Resources */, + A978CB2A1B3A3D5A00028C4A /* chat_sender_audio_playing_001@2x.png in Resources */, A98F986C1ACA2FA9007C4594 /* BaseRefreshViewController.xib in Resources */, A955109D1AC39E6A0006D16F /* Images.xcassets in Resources */, A97DBE4C1ACAEBE300705682 /* first-login-sina@2x.png in Resources */, A9FAD4281AC922BE007ADC10 /* NoteViewController.xib in Resources */, A93441E61ACA8AC400A6B233 /* Profile_filter_contentIconClick@2x.png in Resources */, + A971EDF51B32B7AF0023740E /* chatBar_more_photoSelected@2x.png in Resources */, A97559C51ACBEE99004ADA42 /* NoteTableViewCell.xib in Resources */, A90BA0151AD6066000728393 /* voice-bottom-sure@2x.png in Resources */, + A971EDDD1B32B7960023740E /* chatBar_faceSelected@2x.png in Resources */, A9CF212A1B1C65A2007490EF /* praise-wall-white@2x.png in Resources */, A9617A551ACC27860024AE4A /* SetUpViewController.xib in Resources */, A97559D11ACBF0BC004ADA42 /* btn_share@2x.png in Resources */, A98D659E1AD37F18008668EE /* MessageTableViewCell.xib in Resources */, + A971EDE01B32B7960023740E /* chatBar_more@2x.png in Resources */, A93441E11ACA89AA00A6B233 /* Profile_filter_voiceIcon@2x.png in Resources */, A950AB411AEC8B5E00D0F6DD /* closeButtonClick@2x.png in Resources */, + A978CB2B1B3A3D5A00028C4A /* chat_sender_audio_playing_002@2x.png in Resources */, A97C55031AC933AD0038818A /* UMShareEditViewController.xib in Resources */, A97DBE4E1ACAED4900705682 /* camera-close-select@2x.png in Resources */, + A971EE031B32B7C40023740E /* chatBar_colorMore_audioCallSelected@2x.png in Resources */, + A971EDE91B32B7A00023740E /* chatBar_recordSelectedBg@2x.png in Resources */, A96F27F51B21C5AC00DA0A66 /* PraiseUserListTableViewCell.xib in Resources */, A97559A91ACB9DE4004ADA42 /* navigationButtonPublishClick@2x.png in Resources */, A93441E21ACA89AA00A6B233 /* Profile_filter_voiceIconClick@2x.png in Resources */, + A971EDE11B32B7960023740E /* chatBar_moreSelected@2x.png in Resources */, A97559A81ACB9DE4004ADA42 /* navigationButtonPublish@2x.png in Resources */, + A971EDD51B32B7790023740E /* messageToolbarBg@2x.png in Resources */, A98536781AEB7400000312BF /* RegistAccountViewController.xib in Resources */, + A971EDF01B32B7AF0023740E /* chatBar_more_camera@2x.png in Resources */, A97559CE1ACBF0BC004ADA42 /* btn_good_clicked@2x.png in Resources */, A9B6DFE61B2033A80003C1BC /* toolbar_light_comment@2x.png in Resources */, A97883881AD369DF00D46477 /* mainCellDingClick@2x.png in Resources */, @@ -1541,44 +2453,64 @@ A97C55061AC933AD0038818A /* UMSnsAccountViewController.xib in Resources */, A966FB9A1AD62CAE00542068 /* errormark@2x.png in Resources */, A9CF21221B1C4C70007490EF /* NoteCommentViewController.xib in Resources */, + A9B8FEC61B32A4CF00619C7D /* ChatMainViewController.xib in Resources */, A97559CD1ACBF0BC004ADA42 /* btn_bad@2x.png in Resources */, A93441F71ACA918100A6B233 /* tabbarSetup@2x.png in Resources */, A9B6DFDE1B2028B80003C1BC /* share_cancel@2x.png in Resources */, A90BA0091AD6060600728393 /* playButtonClick@2x.png in Resources */, A9A3A7501B2805EA001AAB3A /* PersonalTopView.xib in Resources */, + A971EDF21B32B7AF0023740E /* chatBar_more_location@2x.png in Resources */, A9FD82BD1B1D544300AC4DC9 /* CommentTableViewCell.xib in Resources */, + A971EE091B32B7C40023740E /* chatBar_colorMore_photoSelected@2x.png in Resources */, A98536731AEB66F9000312BF /* ReportViewController.xib in Resources */, A97C55011AC933AD0038818A /* UMSCommentInputController.xib in Resources */, + A971EE0D1B32B7C40023740E /* chatBar_colorMore_videoSelected@2x.png in Resources */, A97559AD1ACB9DF0004ADA42 /* navigationButtonRefreshClick@2x.png in Resources */, A90BA00B1AD6060600728393 /* playButtonPlay@2x.png in Resources */, + A971EE0B1B32B7C40023740E /* chatBar_colorMore_videoCall@2x.png in Resources */, + A978CB371B3A3D6700028C4A /* chat_receiver_audio_playing001@2x.png in Resources */, + A978CB411B3A3D7100028C4A /* chat_location_detail_disclosureHL@2x.png in Resources */, + A978CB421B3A3D7100028C4A /* chat_location_preview@2x.png in Resources */, + A9F7F4681B33BF6700317F3E /* call_out@2x.png in Resources */, + A9F7F46B1B33BF6700317F3E /* callBg@2x.png in Resources */, + A978CB2C1B3A3D5A00028C4A /* chat_sender_audio_playing_003@2x.png in Resources */, A90BA0131AD6066000728393 /* voice-bottom-close@2x.png in Resources */, A93441F81ACA918100A6B233 /* tabbarSetupClick@2x.png in Resources */, + A978CB3A1B3A3D6700028C4A /* chat_receiver_bg@2x.png in Resources */, A93441FE1ACA919F00A6B233 /* tabbarVoice-dark@2x.png in Resources */, A9B6DFDA1B201E5B0003C1BC /* share_send@2x.png in Resources */, A9B6DFD21B20054B0003C1BC /* CommentTextView.xib in Resources */, A9617A581ACC2EBC0024AE4A /* mine-setting-icon-click@2x.png in Resources */, A985368C1AEBDDAB000312BF /* ModifyPassWordViewController.xib in Resources */, + A971EDDF1B32B7960023740E /* chatBar_keyboardSelected@2x.png in Resources */, A90BA0071AD6060600728393 /* play@2x.png in Resources */, A93441E51ACA8AC400A6B233 /* Profile_filter_contentIcon@2x.png in Resources */, + A971EDF11B32B7AF0023740E /* chatBar_more_cameraSelected@2x.png in Resources */, A97559B31ACBC683004ADA42 /* NotePublishViewController.xib in Resources */, A966FB991AD62CAE00542068 /* checkmark@2x.png in Resources */, + A978CB401B3A3D7100028C4A /* chat_location_detail_disclosure@2x.png in Resources */, A9B6DFEC1B2068790003C1BC /* Localizable.strings in Resources */, A9FAD4231AC922A5007ADC10 /* MainViewController.xib in Resources */, + A971EDE81B32B7A00023740E /* chatBar_recordSelected@2x.png in Resources */, A90BA01D1AD606A700728393 /* voice-record-bg@2x.png in Resources */, A90BA0231AD619B500728393 /* voice-record-level-bg@2x.png in Resources */, + A9F7F46C1B33BF6700317F3E /* imageDownloadFail@2x.png in Resources */, A93441F61ACA918100A6B233 /* tabbarSetup-dark@2x.png in Resources */, + A971EE051B32B7C40023740E /* chatBar_colorMore_cameraSelected@2x.png in Resources */, A9744EDE1B311DBA0082301D /* MessageCommentViewController.xib in Resources */, A97DBE421ACAE4E300705682 /* first-login-icon.png in Resources */, A97C55051AC933AD0038818A /* UMSLoginViewController.xib in Resources */, A97C55081AC933AD0038818A /* UMSocialSDKResourcesNew.bundle in Resources */, A9FD82B71B1D433800AC4DC9 /* accessory@2x.png in Resources */, A90BA01B1AD6069A00728393 /* voice-play-start@2x.png in Resources */, + A978CB361B3A3D6700028C4A /* chat_receiver_audio_playing000@2x.png in Resources */, A97DBE341ACAE10800705682 /* LoginViewController.xib in Resources */, A93441EA1ACA8AD200A6B233 /* Profile_filter_ImageIconClick@2x.png in Resources */, A97C55021AC933AD0038818A /* UMSCommentInputControlleriPad.xib in Resources */, A9A3A7521B2810DB001AAB3A /* Pofile_coverImage@2x.jpg in Resources */, A93441F11ACA916D00A6B233 /* tabbarQuotation@2x.png in Resources */, A90BA00D1AD6062300728393 /* repeatVideoStarticon@2x.png in Resources */, + A9F7F4691B33BF6700317F3E /* call_silence_h@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1622,24 +2554,35 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A971EDB11B32B5740023740E /* EMAudioPlayerUtil.m in Sources */, + A9B8FEC51B32A4CF00619C7D /* ChatMainViewController.m in Sources */, + A9F917C31B39055A0007A3AC /* EMChatAudioBubbleView.m in Sources */, + A971EDD31B32B6CF0023740E /* EmojiEmoticons.m in Sources */, A9FAD4271AC922BE007ADC10 /* NoteViewController.m in Sources */, A97559A01ACB88FE004ADA42 /* AWordDefault.m in Sources */, A97C54D31AC8F10F0038818A /* XiaoYuAPIClient.m in Sources */, A9CF21211B1C4C70007490EF /* NoteCommentViewController.m in Sources */, + A9F917C51B39055A0007A3AC /* EMChatImageBubbleView.m in Sources */, A97559C41ACBEE99004ADA42 /* NoteTableViewCell.m in Sources */, A96862481ACCF0B400DDAA6B /* MWTapDetectingImageView.m in Sources */, + A971EDB21B32B5740023740E /* EMAudioRecorderUtil.m in Sources */, A9FAD4311AC923FC007ADC10 /* MyViewController.m in Sources */, A9754A221ADC080E0018BAAD /* LocalFileDataSource.m in Sources */, A97559BF1ACBE6C6004ADA42 /* NotePublishViewModel.m in Sources */, A96862781ACCF13300DDAA6B /* PSTGridLayoutItem.m in Sources */, A9744EDD1B311DBA0082301D /* MessageCommentViewController.m in Sources */, + A9F917C71B39055A0007A3AC /* EMChatTextBubbleView.m in Sources */, A97938781B20BB0900180C08 /* CommentViewModel.m in Sources */, A97559B21ACBC683004ADA42 /* NotePublishViewController.m in Sources */, + A971EDB31B32B5740023740E /* EMCDDeviceManager+Media.m in Sources */, A9754A1F1ADC080E0018BAAD /* DataSource.m in Sources */, + A971EDB41B32B5740023740E /* EMCDDeviceManager+Microphone.m in Sources */, A97C54DD1AC901980038818A /* MBProgressHUD+Util.m in Sources */, A96D2F261B2FFDA300DC0284 /* DejalActivityView.m in Sources */, + A9F917DA1B390A220007A3AC /* NSDateFormatter+Category.m in Sources */, A96862721ACCF13300DDAA6B /* PSTCollectionViewData.m in Sources */, A97DBE331ACAE10800705682 /* LoginViewController.m in Sources */, + A9F917DE1B390AE70007A3AC /* THProgressView.m in Sources */, A98536721AEB66F9000312BF /* ReportViewController.m in Sources */, A97559A31ACB8CE0004ADA42 /* AWordUser.m in Sources */, A9754A1C1ADC080E0018BAAD /* AudioPlayer.m in Sources */, @@ -1649,6 +2592,8 @@ A9617A541ACC27860024AE4A /* SetUpViewController.m in Sources */, A97C54D21AC8F10F0038818A /* AFgzipResponseSerializer.m in Sources */, A9FAD4221AC922A5007ADC10 /* MainViewController.m in Sources */, + A971ED9C1B32B53D0023740E /* FacialView.m in Sources */, + A9F917AE1B3901730007A3AC /* ConvertToCommonEmoticonsHelper.m in Sources */, A96862761ACCF13300DDAA6B /* PSTCollectionViewUpdateItem.m in Sources */, A968626E1ACCF13300DDAA6B /* NSIndexPath+PSTCollectionViewAdditions.m in Sources */, A9FAD42C1AC923E2007ADC10 /* MessageViewController.m in Sources */, @@ -1657,40 +2602,57 @@ A9CF21271B1C53E3007490EF /* CommentGoodListCellTableViewCell.m in Sources */, A98536811AEBC7BB000312BF /* SetUserInfoViewController.m in Sources */, A968627A1ACCF13300DDAA6B /* PSTGridLayoutSection.m in Sources */, + A9F917C61B39055A0007A3AC /* EMChatLocationBubbleView.m in Sources */, + A9F917D21B3906150007A3AC /* MessageModel.m in Sources */, + A971ED991B32B5260023740E /* DXRecordView.m in Sources */, A96862771ACCF13300DDAA6B /* PSTGridLayoutInfo.m in Sources */, A985368B1AEBDDAB000312BF /* ModifyPassWordViewController.m in Sources */, A96862751ACCF13300DDAA6B /* PSTCollectionViewLayout.m in Sources */, A96862791ACCF13300DDAA6B /* PSTGridLayoutRow.m in Sources */, + A9F917D31B3906150007A3AC /* MessageModelManager.m in Sources */, A9754A1D1ADC080E0018BAAD /* AutoRecoveringHttpDataSource.m in Sources */, + A971EDB61B32B5740023740E /* EMCDDeviceManager+Remind.m in Sources */, A97C54CD1AC8F10F0038818A /* BaseViewModel.m in Sources */, A9754A261ADC199B0018BAAD /* MyMessageViewController.m in Sources */, A9617A4F1ACC0D0F0024AE4A /* NoteViewModel.m in Sources */, A94691CE1B26EACE00B5D26B /* PersonalInfoViewController.m in Sources */, + A971EDB51B32B5740023740E /* EMCDDeviceManager+ProximitySensor.m in Sources */, A96862461ACCF0B400DDAA6B /* MWPhoto.m in Sources */, A96F27F41B21C5AC00DA0A66 /* PraiseUserListTableViewCell.m in Sources */, A968624A1ACCF0B400DDAA6B /* MWZoomingScrollView.m in Sources */, A97C54CF1AC8F10F0038818A /* NSString+HXAddtions.m in Sources */, + A971ED961B32B5200023740E /* DXFaceView.m in Sources */, A96862501ACCF12300DDAA6B /* DACircularProgressView.m in Sources */, + A9F917C91B39055A0007A3AC /* EMChatTimeCell.m in Sources */, A90BA0001AD6031E00728393 /* MessagePublishViewController.m in Sources */, A95510951AC39E6A0006D16F /* AppDelegate.m in Sources */, A94D0EDD1AD5757A0002DEB1 /* UpdateViewModel.m in Sources */, A99AA12C1ADCCB3C00574B12 /* MessagePublihViewModel.m in Sources */, A97C54D11AC8F10F0038818A /* RequireEngine.m in Sources */, + A9B8FECF1B32B0F200619C7D /* MessageTableView.m in Sources */, A96862731ACCF13300DDAA6B /* PSTCollectionViewFlowLayout.m in Sources */, + A9F917C41B39055A0007A3AC /* EMChatBaseBubbleView.m in Sources */, A96862441ACCF0B400DDAA6B /* MWGridCell.m in Sources */, A94DF6351AD4D94E00DCDCB0 /* MyNoteViewController.m in Sources */, A9754A211ADC080E0018BAAD /* HttpDataSource.m in Sources */, A9754A201ADC080E0018BAAD /* DataSourceWrapper.m in Sources */, + A9F917D71B39091A0007A3AC /* NSDate+Category.m in Sources */, + A971EDB71B32B5740023740E /* EMCDDeviceManagerBase.m in Sources */, A96862741ACCF13300DDAA6B /* PSTCollectionViewItemKey.m in Sources */, A96862451ACCF0B400DDAA6B /* MWGridViewController.m in Sources */, A97C54D01AC8F10F0038818A /* PropertyEntity.m in Sources */, A96F27F91B21C5C800DA0A66 /* PraiseUserListViewController.m in Sources */, A93441DE1ACA311700A6B233 /* Ash_UIUtil.m in Sources */, + A9B8FEC91B32AC7000619C7D /* DXMessageToolBar.m in Sources */, A968624C1ACCF0B400DDAA6B /* README.md in Sources */, A9754A1E1ADC080E0018BAAD /* CoreFoundationDataSource.m in Sources */, A96862701ACCF13300DDAA6B /* PSTCollectionViewCell.m in Sources */, + A971ED931B32B50A0023740E /* XHMessageTextView.m in Sources */, + A9F917D41B3906150007A3AC /* MessageReadManager.m in Sources */, + A9F917E11B390AFE0007A3AC /* UIResponder+Router.m in Sources */, A98536771AEB7400000312BF /* RegistAccountViewController.m in Sources */, A97559B71ACBD99E004ADA42 /* UIPlaceHolderTextView.m in Sources */, + A9F917C81B39055A0007A3AC /* EMChatVideoBubbleView.m in Sources */, A97C54E11AC91DA10038818A /* CommonUtil.m in Sources */, A96862491ACCF0B400DDAA6B /* MWTapDetectingView.m in Sources */, A99AA12D1ADCCB3C00574B12 /* MessageViewModel.m in Sources */, @@ -1699,11 +2661,21 @@ A9A3A7591B281392001AAB3A /* CExpandHeader.m in Sources */, A98536861AEBDA1E000312BF /* OurLoginViewController.m in Sources */, A95510921AC39E6A0006D16F /* main.m in Sources */, + A9B8FECC1B32ACA900619C7D /* DXChatBarMoreView.m in Sources */, A95CE2EB1B1DFD030017AE68 /* NoteCommentViewModel.m in Sources */, + A9F7F4571B33B37600317F3E /* LocationViewController.m in Sources */, + A971EDC81B32B6A40023740E /* amrFileCodec.mm in Sources */, A98D659D1AD37F18008668EE /* MessageTableViewCell.m in Sources */, A96862711ACCF13300DDAA6B /* PSTCollectionViewController.m in Sources */, + A971EDD21B32B6CF0023740E /* Emoji.m in Sources */, + A971EDC91B32B6A40023740E /* wav.mm in Sources */, + A9F917AB1B3900270007A3AC /* ChatSendHelper.m in Sources */, + A9F917CB1B39055A0007A3AC /* EMChatViewCell.m in Sources */, + A9F917CA1B39055A0007A3AC /* EMChatViewBaseCell.m in Sources */, A9A3A74E1B2805DA001AAB3A /* PersonalTopView.m in Sources */, A96862431ACCF0B400DDAA6B /* MWCaptionView.m in Sources */, + A9F7F45F1B33BC4E00317F3E /* CallViewController.m in Sources */, + A971EDCA1B32B6A40023740E /* EMVoiceConverter.mm in Sources */, A9FD82BC1B1D544300AC4DC9 /* CommentTableViewCell.m in Sources */, A9B6DFCC1B1FFDB20003C1BC /* CommentTextView.m in Sources */, A96F27EE1B2195BA00DA0A66 /* UIImageView+Reloading.m in Sources */, @@ -1843,9 +2815,12 @@ "$(PROJECT_DIR)/Ash_AWord/Vender/UMSocial_Sdk_Extra_Frameworks/Wechat", "$(PROJECT_DIR)/Ash_AWord/Vender/UMAnalytics_Sdk_3.4.6", "$(PROJECT_DIR)/Ash_AWord/Vender/UMSocial_Sdk_Extra_Frameworks/Sina", + "$(PROJECT_DIR)/Ash_AWord/Vender/EaseMobSDK/lib", + "$(PROJECT_DIR)/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb", + "$(PROJECT_DIR)/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb", ); PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "e0b4f9a8-771b-4fcc-afb8-a404945e92fa"; + PROVISIONING_PROFILE = "b33bbace-362f-4f05-be3d-6af1812b44e0"; VALID_ARCHS = "arm64 armv7 armv7s x86_64"; }; name = Debug; @@ -1872,9 +2847,12 @@ "$(PROJECT_DIR)/Ash_AWord/Vender/UMSocial_Sdk_Extra_Frameworks/Wechat", "$(PROJECT_DIR)/Ash_AWord/Vender/UMAnalytics_Sdk_3.4.6", "$(PROJECT_DIR)/Ash_AWord/Vender/UMSocial_Sdk_Extra_Frameworks/Sina", + "$(PROJECT_DIR)/Ash_AWord/Vender/EaseMobSDK/lib", + "$(PROJECT_DIR)/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb", + "$(PROJECT_DIR)/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb", ); PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "e0b4f9a8-771b-4fcc-afb8-a404945e92fa"; + PROVISIONING_PROFILE = "b33bbace-362f-4f05-be3d-6af1812b44e0"; VALID_ARCHS = "arm64 armv7 armv7s x86_64"; }; name = Release; diff --git a/Ash_AWord.xcworkspace/xcuserdata/xmfish.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Ash_AWord.xcworkspace/xcuserdata/xmfish.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 9b17021..7744512 100644 --- a/Ash_AWord.xcworkspace/xcuserdata/xmfish.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Ash_AWord.xcworkspace/xcuserdata/xmfish.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -10,12 +10,12 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Ash_AWord/AppDelegate.m" - timestampString = "449679166.085695" + timestampString = "456376944.815543" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "95" - endingLineNumber = "95" - landmarkName = "-setUmeng" + startingLineNumber = "106" + endingLineNumber = "106" + landmarkName = "+visibleViewController" landmarkType = "5"> @@ -26,31 +26,31 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Ash_AWord/AppDelegate.m" - timestampString = "449679166.085695" + timestampString = "456376944.815543" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "59" - endingLineNumber = "59" + startingLineNumber = "68" + endingLineNumber = "68" + landmarkName = "-applicationDidBecomeActive:" + landmarkType = "5"> + + + + - - - - @@ -442,11 +442,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Ash_AWord/ViewControllers/Login/LoginViewController.m" - timestampString = "451664979.302049" + timestampString = "456300113.691928" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "149" - endingLineNumber = "149" + startingLineNumber = "150" + endingLineNumber = "150" landmarkName = "-loginWithOpenId:withName:withGender:withFigureUrl:" landmarkType = "5"> @@ -490,11 +490,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Ash_AWord/ViewControllers/Login/LoginViewController.m" - timestampString = "451819141.449598" + timestampString = "456302036.416834" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "179" - endingLineNumber = "179" + startingLineNumber = "180" + endingLineNumber = "180" landmarkName = "-loginWithOpenId:withName:withGender:withFigureUrl:" landmarkType = "5"> @@ -553,11 +553,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Ash_AWord/ViewControllers/Login/LoginViewController.m" - timestampString = "451664979.302049" + timestampString = "456302036.416834" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "160" - endingLineNumber = "160" + startingLineNumber = "161" + endingLineNumber = "161" landmarkName = "-loginWithOpenId:withName:withGender:withFigureUrl:" landmarkType = "5"> @@ -569,11 +569,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "Ash_AWord/ViewControllers/Login/LoginViewController.m" - timestampString = "451664979.302049" + timestampString = "456300113.691928" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "156" - endingLineNumber = "156" + startingLineNumber = "157" + endingLineNumber = "157" landmarkName = "-loginWithOpenId:withName:withGender:withFigureUrl:" landmarkType = "5"> @@ -2389,7 +2389,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ash_AWord/AppDelegate.m b/Ash_AWord/AppDelegate.m index 7dbd089..532f3f0 100644 --- a/Ash_AWord/AppDelegate.m +++ b/Ash_AWord/AppDelegate.m @@ -13,6 +13,7 @@ #import "UMSocialSinaHandler.h" #import "MobClick.h" #import "MainViewController.h" +#import "EaseMob.h" @interface AppDelegate () @end @@ -27,6 +28,18 @@ self.window.rootViewController = _mainViewController; _mainViewController.delegate = self; + + + //注册 APNS文件的名字, 需要与后台上传证书时的名字一一对应 + [[EaseMob sharedInstance] registerSDKWithAppKey:EaseMobAppKey apnsCertName:EaseMobApnsCertName]; + // 需要在注册sdk后写上该方法 + [[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; + //登陆聊天的 + if ([AWordUser sharedInstance].isLogin) + { + [Ash_UIUtil EaseMobLoginWithUserName:[AWordUser sharedInstance].uid]; + } + [self setUmeng]; return YES; @@ -40,10 +53,14 @@ - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + [[EaseMob sharedInstance] applicationDidEnterBackground:application]; + } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + [[EaseMob sharedInstance] applicationWillEnterForeground:application]; + } - (void)applicationDidBecomeActive:(UIApplication *)application { @@ -52,6 +69,8 @@ - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + [[EaseMob sharedInstance] applicationWillTerminate:application]; + } - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url diff --git a/Ash_AWord/Config/Common.h b/Ash_AWord/Config/Common.h index 239db47..6eff77c 100644 --- a/Ash_AWord/Config/Common.h +++ b/Ash_AWord/Config/Common.h @@ -67,6 +67,12 @@ //#define Ash_AWord_API_URL @"http://192.168.1.3:8080/QuestionServer" #define Sign_Key @"yjn@jjyy123" +/** + *环信信息 + */ +#define EaseMobApnsCertName @"ashyujianni" +#define EaseMobAppKey @"ash#ashyujianni" +#define EasePassword @"123456" /** * 微信开放平台信息 */ diff --git a/Ash_AWord/Info.plist b/Ash_AWord/Info.plist index 375aafc..2363b39 100644 --- a/Ash_AWord/Info.plist +++ b/Ash_AWord/Info.plist @@ -26,6 +26,8 @@ 2.0 CFBundleSignature ???? + NSLocationWhenInUseUsageDescription + 需要使用定位 CFBundleURLTypes diff --git a/Ash_AWord/PrefixHeader.pch b/Ash_AWord/PrefixHeader.pch index aae7e3c..5f27edf 100644 --- a/Ash_AWord/PrefixHeader.pch +++ b/Ash_AWord/PrefixHeader.pch @@ -40,6 +40,8 @@ #import "LoginViewController.h" #import "UIImageView+Reloading.h" #import "DejalActivityView.h" +#import "EMErrorDefs.h" +#import "EaseMob.h" #endif #endif diff --git a/Ash_AWord/Resource/back@2x.png b/Ash_AWord/Resource/back@2x.png new file mode 100755 index 0000000..e6a4b63 Binary files /dev/null and b/Ash_AWord/Resource/back@2x.png differ diff --git a/Ash_AWord/Resource/callBg@2x.png b/Ash_AWord/Resource/callBg@2x.png new file mode 100644 index 0000000..07834d8 Binary files /dev/null and b/Ash_AWord/Resource/callBg@2x.png differ diff --git a/Ash_AWord/Resource/call_out@2x.png b/Ash_AWord/Resource/call_out@2x.png new file mode 100755 index 0000000..bf941ff Binary files /dev/null and b/Ash_AWord/Resource/call_out@2x.png differ diff --git a/Ash_AWord/Resource/call_out_h@2x.png b/Ash_AWord/Resource/call_out_h@2x.png new file mode 100755 index 0000000..8cf8fb4 Binary files /dev/null and b/Ash_AWord/Resource/call_out_h@2x.png differ diff --git a/Ash_AWord/Resource/call_silence@2x.png b/Ash_AWord/Resource/call_silence@2x.png new file mode 100755 index 0000000..9f2c62a Binary files /dev/null and b/Ash_AWord/Resource/call_silence@2x.png differ diff --git a/Ash_AWord/Resource/call_silence_h@2x.png b/Ash_AWord/Resource/call_silence_h@2x.png new file mode 100755 index 0000000..cecc185 Binary files /dev/null and b/Ash_AWord/Resource/call_silence_h@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_audioCall@2x.png b/Ash_AWord/Resource/chatBar_colorMore_audioCall@2x.png new file mode 100644 index 0000000..6620508 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_audioCall@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_audioCallSelected@2x.png b/Ash_AWord/Resource/chatBar_colorMore_audioCallSelected@2x.png new file mode 100644 index 0000000..55b7e00 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_audioCallSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_camera@2x.png b/Ash_AWord/Resource/chatBar_colorMore_camera@2x.png new file mode 100644 index 0000000..af351fe Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_camera@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_cameraSelected@2x.png b/Ash_AWord/Resource/chatBar_colorMore_cameraSelected@2x.png new file mode 100644 index 0000000..ec45ef6 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_cameraSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_location@2x.png b/Ash_AWord/Resource/chatBar_colorMore_location@2x.png new file mode 100644 index 0000000..71476a7 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_location@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_locationSelected@2x.png b/Ash_AWord/Resource/chatBar_colorMore_locationSelected@2x.png new file mode 100644 index 0000000..15f0ee8 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_locationSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_photo@2x.png b/Ash_AWord/Resource/chatBar_colorMore_photo@2x.png new file mode 100644 index 0000000..e3afe61 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_photo@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_photoSelected@2x.png b/Ash_AWord/Resource/chatBar_colorMore_photoSelected@2x.png new file mode 100644 index 0000000..a16e9c1 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_photoSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_video@2x.png b/Ash_AWord/Resource/chatBar_colorMore_video@2x.png new file mode 100644 index 0000000..93d8d90 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_video@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_videoCall@2x.png b/Ash_AWord/Resource/chatBar_colorMore_videoCall@2x.png new file mode 100644 index 0000000..b07217b Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_videoCall@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_videoCallSelected@2x.png b/Ash_AWord/Resource/chatBar_colorMore_videoCallSelected@2x.png new file mode 100644 index 0000000..7de3b5e Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_videoCallSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_colorMore_videoSelected@2x.png b/Ash_AWord/Resource/chatBar_colorMore_videoSelected@2x.png new file mode 100644 index 0000000..59ea991 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_colorMore_videoSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_face@2x.png b/Ash_AWord/Resource/chatBar_face@2x.png new file mode 100755 index 0000000..08a200b Binary files /dev/null and b/Ash_AWord/Resource/chatBar_face@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_faceSelected@2x.png b/Ash_AWord/Resource/chatBar_faceSelected@2x.png new file mode 100755 index 0000000..3536d96 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_faceSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_keyboard@2x.png b/Ash_AWord/Resource/chatBar_keyboard@2x.png new file mode 100755 index 0000000..aa1da1d Binary files /dev/null and b/Ash_AWord/Resource/chatBar_keyboard@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_keyboardSelected@2x.png b/Ash_AWord/Resource/chatBar_keyboardSelected@2x.png new file mode 100755 index 0000000..b57c520 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_keyboardSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more@2x.png b/Ash_AWord/Resource/chatBar_more@2x.png new file mode 100755 index 0000000..5838b32 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_moreSelected@2x.png b/Ash_AWord/Resource/chatBar_moreSelected@2x.png new file mode 100755 index 0000000..7d065dc Binary files /dev/null and b/Ash_AWord/Resource/chatBar_moreSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more_camera@2x.png b/Ash_AWord/Resource/chatBar_more_camera@2x.png new file mode 100755 index 0000000..d2f8ba1 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more_camera@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more_cameraSelected@2x.png b/Ash_AWord/Resource/chatBar_more_cameraSelected@2x.png new file mode 100755 index 0000000..8a1fae8 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more_cameraSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more_location@2x.png b/Ash_AWord/Resource/chatBar_more_location@2x.png new file mode 100755 index 0000000..6badfd6 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more_location@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more_locationSelected@2x.png b/Ash_AWord/Resource/chatBar_more_locationSelected@2x.png new file mode 100755 index 0000000..bda5e59 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more_locationSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more_photo@2x.png b/Ash_AWord/Resource/chatBar_more_photo@2x.png new file mode 100755 index 0000000..e156531 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more_photo@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_more_photoSelected@2x.png b/Ash_AWord/Resource/chatBar_more_photoSelected@2x.png new file mode 100755 index 0000000..34903ec Binary files /dev/null and b/Ash_AWord/Resource/chatBar_more_photoSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_record@2x.png b/Ash_AWord/Resource/chatBar_record@2x.png new file mode 100755 index 0000000..f7e2fa3 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_record@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_recordBg@2x.png b/Ash_AWord/Resource/chatBar_recordBg@2x.png new file mode 100755 index 0000000..df6aa59 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_recordBg@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_recordSelected@2x.png b/Ash_AWord/Resource/chatBar_recordSelected@2x.png new file mode 100755 index 0000000..af27e52 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_recordSelected@2x.png differ diff --git a/Ash_AWord/Resource/chatBar_recordSelectedBg@2x.png b/Ash_AWord/Resource/chatBar_recordSelectedBg@2x.png new file mode 100755 index 0000000..37a4121 Binary files /dev/null and b/Ash_AWord/Resource/chatBar_recordSelectedBg@2x.png differ diff --git a/Ash_AWord/Resource/chatListCellHead@2x.png b/Ash_AWord/Resource/chatListCellHead@2x.png new file mode 100644 index 0000000..870edd8 Binary files /dev/null and b/Ash_AWord/Resource/chatListCellHead@2x.png differ diff --git a/Ash_AWord/Resource/chat_location_annotation_someone@2x.png b/Ash_AWord/Resource/chat_location_annotation_someone@2x.png new file mode 100644 index 0000000..44fbeb9 Binary files /dev/null and b/Ash_AWord/Resource/chat_location_annotation_someone@2x.png differ diff --git a/Ash_AWord/Resource/chat_location_detail_disclosure@2x.png b/Ash_AWord/Resource/chat_location_detail_disclosure@2x.png new file mode 100644 index 0000000..da3a98e Binary files /dev/null and b/Ash_AWord/Resource/chat_location_detail_disclosure@2x.png differ diff --git a/Ash_AWord/Resource/chat_location_detail_disclosureHL@2x.png b/Ash_AWord/Resource/chat_location_detail_disclosureHL@2x.png new file mode 100644 index 0000000..cb8d576 Binary files /dev/null and b/Ash_AWord/Resource/chat_location_detail_disclosureHL@2x.png differ diff --git a/Ash_AWord/Resource/chat_location_preview@2x.png b/Ash_AWord/Resource/chat_location_preview@2x.png new file mode 100644 index 0000000..079f02b Binary files /dev/null and b/Ash_AWord/Resource/chat_location_preview@2x.png differ diff --git a/Ash_AWord/Resource/chat_receiver_audio_playing000@2x.png b/Ash_AWord/Resource/chat_receiver_audio_playing000@2x.png new file mode 100644 index 0000000..5d499af Binary files /dev/null and b/Ash_AWord/Resource/chat_receiver_audio_playing000@2x.png differ diff --git a/Ash_AWord/Resource/chat_receiver_audio_playing001@2x.png b/Ash_AWord/Resource/chat_receiver_audio_playing001@2x.png new file mode 100644 index 0000000..b1045d3 Binary files /dev/null and b/Ash_AWord/Resource/chat_receiver_audio_playing001@2x.png differ diff --git a/Ash_AWord/Resource/chat_receiver_audio_playing002@2x.png b/Ash_AWord/Resource/chat_receiver_audio_playing002@2x.png new file mode 100644 index 0000000..fc02a0a Binary files /dev/null and b/Ash_AWord/Resource/chat_receiver_audio_playing002@2x.png differ diff --git a/Ash_AWord/Resource/chat_receiver_audio_playing003@2x.png b/Ash_AWord/Resource/chat_receiver_audio_playing003@2x.png new file mode 100644 index 0000000..6d8a451 Binary files /dev/null and b/Ash_AWord/Resource/chat_receiver_audio_playing003@2x.png differ diff --git a/Ash_AWord/Resource/chat_receiver_audio_playing_full@2x.png b/Ash_AWord/Resource/chat_receiver_audio_playing_full@2x.png new file mode 100644 index 0000000..c46de79 Binary files /dev/null and b/Ash_AWord/Resource/chat_receiver_audio_playing_full@2x.png differ diff --git a/Ash_AWord/Resource/chat_receiver_bg@2x.png b/Ash_AWord/Resource/chat_receiver_bg@2x.png new file mode 100755 index 0000000..aadb9de Binary files /dev/null and b/Ash_AWord/Resource/chat_receiver_bg@2x.png differ diff --git a/Ash_AWord/Resource/chat_sender_audio_playing_000@2x.png b/Ash_AWord/Resource/chat_sender_audio_playing_000@2x.png new file mode 100644 index 0000000..5d499af Binary files /dev/null and b/Ash_AWord/Resource/chat_sender_audio_playing_000@2x.png differ diff --git a/Ash_AWord/Resource/chat_sender_audio_playing_001@2x.png b/Ash_AWord/Resource/chat_sender_audio_playing_001@2x.png new file mode 100644 index 0000000..74d39a1 Binary files /dev/null and b/Ash_AWord/Resource/chat_sender_audio_playing_001@2x.png differ diff --git a/Ash_AWord/Resource/chat_sender_audio_playing_002@2x.png b/Ash_AWord/Resource/chat_sender_audio_playing_002@2x.png new file mode 100644 index 0000000..9602973 Binary files /dev/null and b/Ash_AWord/Resource/chat_sender_audio_playing_002@2x.png differ diff --git a/Ash_AWord/Resource/chat_sender_audio_playing_003@2x.png b/Ash_AWord/Resource/chat_sender_audio_playing_003@2x.png new file mode 100644 index 0000000..d21295b Binary files /dev/null and b/Ash_AWord/Resource/chat_sender_audio_playing_003@2x.png differ diff --git a/Ash_AWord/Resource/chat_sender_audio_playing_full@2x.png b/Ash_AWord/Resource/chat_sender_audio_playing_full@2x.png new file mode 100644 index 0000000..478224d Binary files /dev/null and b/Ash_AWord/Resource/chat_sender_audio_playing_full@2x.png differ diff --git a/Ash_AWord/Resource/chat_sender_bg@2x.png b/Ash_AWord/Resource/chat_sender_bg@2x.png new file mode 100755 index 0000000..1db9023 Binary files /dev/null and b/Ash_AWord/Resource/chat_sender_bg@2x.png differ diff --git a/Ash_AWord/Resource/en.lproj/Localizable.strings b/Ash_AWord/Resource/en.lproj/Localizable.strings index cdab33c..4fccf66 100644 --- a/Ash_AWord/Resource/en.lproj/Localizable.strings +++ b/Ash_AWord/Resource/en.lproj/Localizable.strings @@ -7,4 +7,71 @@ */ "Saving" = "Saving"; "SaveFailed" = "SaveFailed"; -"Saved" = "Saved"; \ No newline at end of file +"Saved" = "Saved"; + +//message +"message.image" = "image"; +"message.location" = "location"; +"message.voice" = "audio"; +"message.vidio" = "vidio"; +"message.image1" = "[image]"; +"message.location1" = "[location]"; +"message.voice1" = "[audio]"; +"message.vidio1" = "[vidio]"; +"message.beginReceiveOffine" = "begin to receive offline messages"; +"message.endReceiveOffine" = "end to receive offline messages"; +"message.toolBar.inputPlaceHolder" = "input a new message"; +"message.toolBar.record.upCancel" = " Fingers up slide, cancel sending "; +"message.toolBar.record.loosenCancel" = " loosen the fingers, to cancel sending "; +"message.toolBar.record.touch" = "hold down to talk"; +"message.toolBar.record.send" = "loosen to send"; +"DXMessageToolBarDelegate.record" = "hold down to talk"; +"DXMessageToolBarDelegate.send" = "loosen to send"; + +"message.downloadingAudio" = "downloading voice, click later"; +"message.downloadingVideo" = "downloading video..."; +"message.videoFail" = "video for failure!"; +"message.downloadingImage" = "downloading a image..."; +"message.imageFail" = "image for failure!"; +"message.thumImageFail" = "thumbnail for failure!"; +"message.simulatorNotSupportCamera" = "simulator does not support taking picture"; +"message.simulatorNotSupportVideo" = "simulator does not support vidio"; +"message.startRecordFail" = "failure to start recording"; +"message.noMessage" = "no messages"; + + +//location +"location.messageType" = "location message"; +"location.fail" = "locate failure"; +"location.ongoning" = "locating..."; + +"search" = "Search"; +"error" = "Error"; +"delete" = "Delete"; +"copy" = "Copy"; +"save" = "Save"; +"prompt" = "Prompt"; +"add" = "Add"; +"send" = "Send"; +"open" = "Open"; +"down" = "Down"; +"choose" = "Choose"; +"accept" = "Accept"; +"reject" = "Reject"; +"wait" = "Please wait..."; + +//NSDateCategory +"NSDateCategory.text1" = "one minute"; +"NSDateCategory.text2" = "%.f minutes ago"; +"NSDateCategory.text3" = "%.f hours ago"; +"NSDateCategory.text4" = "%.f days ago"; +"NSDateCategory.text5" = "M-d"; +"NSDateCategory.text6" = "%.f years ago"; +"NSDateCategory.text7" = "M-d %@"; +"NSDateCategory.text8" = "M-d HH:mm"; +"NSDateCategory.text9" = "aa hh:mm"; +"NSDateCategory.text10" = "aa hh:mm"; +"NSDateCategory.text11" = "aa hh:mm"; +"NSDateCategory.text12" = "aa hh:mm"; +"NSDateCategory.text13" = "M-d HH:mm"; +"NSDateCategory.text14" = "today %@"; diff --git a/Ash_AWord/Resource/imageDownloadFail@2x.png b/Ash_AWord/Resource/imageDownloadFail@2x.png new file mode 100644 index 0000000..de1eef1 Binary files /dev/null and b/Ash_AWord/Resource/imageDownloadFail@2x.png differ diff --git a/Ash_AWord/Resource/messageSendFail@2x.png b/Ash_AWord/Resource/messageSendFail@2x.png new file mode 100644 index 0000000..dbd4b72 Binary files /dev/null and b/Ash_AWord/Resource/messageSendFail@2x.png differ diff --git a/Ash_AWord/Resource/messageToolbarBg@2x.png b/Ash_AWord/Resource/messageToolbarBg@2x.png new file mode 100755 index 0000000..356051e Binary files /dev/null and b/Ash_AWord/Resource/messageToolbarBg@2x.png differ diff --git a/Ash_AWord/Resource/zh-Hans.lproj/Localizable.strings b/Ash_AWord/Resource/zh-Hans.lproj/Localizable.strings index e4b6a35..6ac0c87 100644 --- a/Ash_AWord/Resource/zh-Hans.lproj/Localizable.strings +++ b/Ash_AWord/Resource/zh-Hans.lproj/Localizable.strings @@ -8,4 +8,69 @@ "Saving" = "保存中"; "SaveFailed" = "保存失败"; -"Saved" = "保存成功"; \ No newline at end of file +"Saved" = "保存成功"; + +//message +"message.image" = "图片"; +"message.location" = "位置"; +"message.voice" = "音频"; +"message.vidio" = "视频"; +"message.image1" = "[图片]"; +"message.location1" = "[位置]"; +"message.voice1" = "[音频]"; +"message.vidio1" = "[视频]"; +"message.beginReceiveOffine" = "开始接收离线消息"; +"message.endReceiveOffine" = "离线消息接收成功"; +"message.toolBar.inputPlaceHolder" = "输入新消息"; +"message.toolBar.record.upCancel" = " 手指上滑,取消发送 "; +"message.toolBar.record.loosenCancel" = " 松开手指,取消发送 "; +"message.toolBar.record.touch" = "按住说话"; +"message.toolBar.record.send" = "松开发送"; + +"message.downloadingAudio" = "正在下载语音,稍后点击"; +"message.downloadingVideo" = "正在获取视频..."; +"message.videoFail" = "视频获取失败!"; +"message.downloadingImage" = "正在获取大图..."; +"message.imageFail" = "大图获取失败!"; +"message.thumImageFail" = "缩略图获取失败!"; +"message.simulatorNotSupportCamera" = "模拟器不支持拍照"; +"message.simulatorNotSupportVideo" = "模拟器不支持录像"; +"message.startRecordFail" = "开始录音失败"; +"message.noMessage" = "消息已经清空"; + +"search" = "搜索"; +"error" = "错误"; +"delete" = "删除"; +"copy" = "复制"; +"save" = "保存"; +"prompt" = "提示"; +"add" = "添加"; +"send" = "发送"; +"open" = "打开"; +"down" = "完成"; +"choose" = "选择"; +"accept" = "接受"; +"reject" = "拒绝"; +"wait" = "请等待..."; + +//location +"location.messageType" = "位置信息"; +"location.fail" = "定位失败"; +"location.ongoning" = "正在定位..."; + + +//NSDateCategory +"NSDateCategory.text1" = "1分钟内"; +"NSDateCategory.text2" = "%.f分钟前"; +"NSDateCategory.text3" = "%.f小时前"; +"NSDateCategory.text4" = "%.f天前"; +"NSDateCategory.text5" = "M月d日"; +"NSDateCategory.text6" = "%.f年前"; +"NSDateCategory.text7" = "昨天 %@"; +"NSDateCategory.text8" = "昨天HH:mm"; +"NSDateCategory.text9" = "凌晨hh:mm"; +"NSDateCategory.text10" = "上午hh:mm"; +"NSDateCategory.text11" = "下午hh:mm"; +"NSDateCategory.text12" = "晚上hh:mm"; +"NSDateCategory.text13" = "昨天HH:mm"; +"NSDateCategory.text14" = "今天 %@"; \ No newline at end of file diff --git a/Ash_AWord/Utility/Tool/Ash_UIUtil.h b/Ash_AWord/Utility/Tool/Ash_UIUtil.h index 983f79b..a4d205e 100644 --- a/Ash_AWord/Utility/Tool/Ash_UIUtil.h +++ b/Ash_AWord/Utility/Tool/Ash_UIUtil.h @@ -10,6 +10,7 @@ @interface Ash_UIUtil : NSObject ++(void)EaseMobLoginWithUserName:(NSString*)userName; +(CABasicAnimation*)getrotationAnimation; +(CGSize)downloadImageSizeWithURL:(id)imageURL; diff --git a/Ash_AWord/Utility/Tool/Ash_UIUtil.m b/Ash_AWord/Utility/Tool/Ash_UIUtil.m index 8412a23..c971623 100644 --- a/Ash_AWord/Utility/Tool/Ash_UIUtil.m +++ b/Ash_AWord/Utility/Tool/Ash_UIUtil.m @@ -8,8 +8,33 @@ #import "Ash_UIUtil.h" #import +#import "EaseMob.h" @implementation Ash_UIUtil ++(void)EaseMobLoginWithUserName:(NSString *)userName +{ + [[EaseMob sharedInstance].chatManager asyncRegisterNewAccount:userName password:EasePassword withCompletion:^(NSString *username, NSString *password, EMError *error) { + if (!error) { + DLog(@"注册成功"); + [[EaseMob sharedInstance].chatManager asyncLoginWithUsername:userName password:EasePassword completion:^(NSDictionary *loginInfo, EMError *error) { + if (!error && loginInfo) { + // 设置自动登录 + [[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES]; + DLog(@"登陆成功"); + } + } onQueue:nil]; + }else if (error.errorCode == EMErrorServerDuplicatedAccount) { + [[EaseMob sharedInstance].chatManager asyncLoginWithUsername:userName password:EasePassword completion:^(NSDictionary *loginInfo, EMError *error) { + if (!error && loginInfo) { + // 设置自动登录 + [[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES]; + DLog(@"登陆成功"); + } + } onQueue:nil]; + } + } onQueue:nil]; + +} +(CABasicAnimation*)getrotationAnimation { CABasicAnimation* rotationAnimation; diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/EMCallServiceDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/EMCallServiceDefs.h new file mode 100644 index 0000000..0705988 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/EMCallServiceDefs.h @@ -0,0 +1,64 @@ +/*! + @header EMCallServiceDefs.h + @abstract CallManager相关宏定义 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#ifndef EaseMobClientSDK_EMCallServiceDefs_h +#define EaseMobClientSDK_EMCallServiceDefs_h + +/*! + @enum + @brief 实时通话状态 + @constant eCallSessionStatusDisconnected 通话没开始 + @constant eCallSessionStatusRinging 通话响铃 + @constant eCallSessionStatusAnswering 通话双方正在协商 + @constant eCallSessionStatusPausing 通话暂停 + @constant eCallSessionStatusConnecting 通话已经准备好,等待接听 + @constant eCallSessionStatusConnected 通话已连接 + @constant eCallSessionStatusAccepted 通话双方同意协商 + */ +typedef NS_ENUM(NSInteger, EMCallSessionStatus){ + eCallSessionStatusDisconnected = 0, + eCallSessionStatusRinging, + eCallSessionStatusAnswering, + eCallSessionStatusPausing, + eCallSessionStatusConnecting, + eCallSessionStatusConnected, + eCallSessionStatusAccepted, +}; + +/*! + @enum + @brief 实时通话类型 + @constant eCallSessionTypeAudio 实时语音 + @constant eCallSessionTypeVideo 实时视频 + @constant eCallSessionTypeContent 暂时不支持的类型 + */ +typedef NS_ENUM(NSInteger, EMCallSessionType){ + eCallSessionTypeAudio = 0, + eCallSessionTypeVideo, + eCallSessionTypeContent, +}; + +/*! + @enum + @brief 实时通话结束原因 + @constant eCallReason_Null 正常挂断 + @constant eCallReason_Offline 对方不在线 + @constant eCallReason_NoResponse 对方没有响应 + @constant eCallReason_Hangup 对方挂断 + @constant eCallReason_Reject 对方拒接 + @constant eCallReason_Busy 对方占线 + */ +typedef NS_ENUM(NSInteger, EMCallStatusChangedReason){ + eCallReason_Null = 0, + eCallReason_Offline, + eCallReason_NoResponse, + eCallReason_Hangup, + eCallReason_Reject, + eCallReason_Busy, +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/EaseMob+CallService.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/EaseMob+CallService.h new file mode 100644 index 0000000..b45198c --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/EaseMob+CallService.h @@ -0,0 +1,37 @@ +/*! + @header EaseMob+CallService.h + @abstract EaseMob的实时通话功能扩展 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import "EaseMob.h" + +// defs headers +#import "EMCallServiceDefs.h" + +//manager +#import "ICallManager.h" + +//delegate +#import "EMCallManagerDelegate.h" + +//type +#import "EMCallSession.h" +#import "OpenGLView20.h" + +@protocol ICallManager; + +/*! + @category EaseMob(CallService) + @discussion 该Category为EaseMob类提供了实时通话的能力. + */ +@interface EaseMob (CallService) + +/*! + @property + @brief 由EaseMob类提供的ICallManager属性 + */ +@property (strong, readonly, nonatomic) id callManager; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/ICallManager.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/ICallManager.h new file mode 100644 index 0000000..9df1066 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/ICallManager.h @@ -0,0 +1,17 @@ +/*! + @header ICallManager.h + @abstract 此接口提供了实时通话的基本操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "ICallManagerBase.h" +#import "ICallManagerCall.h" + +@protocol ICallManager + +@required + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/delegates/EMCallManagerCallDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/delegates/EMCallManagerCallDelegate.h new file mode 100644 index 0000000..e51db1e --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/delegates/EMCallManagerCallDelegate.h @@ -0,0 +1,33 @@ +/*! + @header EMCallManagerCallDelegate.h + @abstract 关于CallManager的异步回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMCallServiceDefs.h" + +@class EMCallSession; +@class EMError; + +/** + * 本类主要处理实时通话时的一些回调操作 + */ +@protocol EMCallManagerCallDelegate + +@optional + +/*! + @method + @brief 实时通话状态发生变化时的回调 + @param callSession 实时通话的实例 + @param reason 变化原因 + @param error 错误信息 + */ +- (void)callSessionStatusChanged:(EMCallSession *)callSession + changeReason:(EMCallStatusChangedReason)reason + error:(EMError *)error; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/delegates/EMCallManagerDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/delegates/EMCallManagerDelegate.h new file mode 100644 index 0000000..6fdec43 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/delegates/EMCallManagerDelegate.h @@ -0,0 +1,19 @@ +/*! + @header EMCallManagerCallDelegate.h + @abstract 关于CallManager的异步回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMCallManagerCallDelegate.h" + +/** + * 本类主要处理实时通话时的一些回调操作 + */ +@protocol EMCallManagerDelegate + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/internal/ICallManagerBase.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/internal/ICallManagerBase.h new file mode 100644 index 0000000..25d0adf --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/internal/ICallManagerBase.h @@ -0,0 +1,40 @@ +/*! + @header ICallManagerBase.h + @abstract 为CallManager提供基础消息操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +@protocol EMCallManagerDelegate; + +/*! + @protocol + @brief 实时通话的基础协议, 用于注册对象到监听列表和从监听列表中移除对象 + @discussion + */ +@protocol ICallManagerBase + +@required + +/*! + @method + @brief 注册一个监听对象到监听列表中 + @discussion 把监听对象添加到监听列表中准备接收相应的事件 + @param delegate 需要注册的监听对象 + @param queue 通知监听对象时的线程 + @result + */ +- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)queue; + +/*! + @method + @brief 从监听列表中移除一个监听对象 + @discussion 把监听对象从监听列表中移除,取消接收相应的事件 + @param delegate 需要移除的监听对象 + @result + */ +- (void)removeDelegate:(id)delegate; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/internal/ICallManagerCall.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/internal/ICallManagerCall.h new file mode 100644 index 0000000..0a578ea --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/internal/ICallManagerCall.h @@ -0,0 +1,137 @@ +/*! + @header ICallManagerCall.h + @abstract 为CallManager提供实时通话操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMCallServiceDefs.h" + +@class EMCallSession; +@class EMError; + +/*! + @protocol + @brief 本协议主要处理实时通话操作 + @discussion 所有不带Block回调的异步方法, 需要监听回调时, 需要先将要接受回调的对象注册到delegate中, 示例代码如下: + [[[EMSDKFull sharedInstance] callManager] addDelegate:self delegateQueue:dispatch_get_main_queue()] + */ +@protocol ICallManagerCall + +@required + +#pragma mark - call + +/*! + @method + @brief 接收方同意语音通话的请求 + @param sessionId 要进行的语音通话的ID + @result 检查语音通话条件是否具备,不具备则返回错误信息(未进行实际的拨打动作) + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMError *)asyncAnswerCall:(NSString *)sessionId; + +/*! + @method + @brief 发起方或接收方结束通话 + @param sessionId 要进行的语音通话的ID + @param reason 结束原因 + @result 检查挂断语音通话条件是否具备,不具备则返回错误信息 + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMError *)asyncEndCall:(NSString *)sessionId + reason:(EMCallStatusChangedReason)reason; + +#pragma mark - call audio + +/*! + @method + @brief 将实时语音静音 + @param sessionId 要进行的实时通话的ID + @param isSilence 是否静音 + @result 错误信息 + @discussion + */ +- (EMError *)markCallSession:(NSString *)sessionId + asSilence:(BOOL)isSilence; + +/*! + @method + @brief 进行实时语音 + @param chatter 要进行语音通话的username(不能与自己通话) + @param timeout 超时时间(传0,使用SDK默认超时时间) + @param pError 检查语音通话条件是否具备,不具备则返回错误信息(未进行实际的拨打动作) + @result 语音通话的实例 + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMCallSession *)asyncMakeVoiceCall:(NSString *)chatter + timeout:(NSUInteger)timeout + error:(EMError **)pError; + +#pragma makr - call video + +/*! + @method + @brief 进行实时视频 + @param chatter 要进行视频通话的username(不能与自己通话) + @param timeout 超时时间(传0,使用SDK默认超时时间) + @param pError 检查视频通话条件是否具备,不具备则返回错误信息(未进行实际的拨打动作) + @result 视频通话的实例 + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMCallSession *)asyncMakeVideoCall:(NSString *)chatter + timeout:(NSUInteger)timeout + error:(EMError **)pError; + +/*! + @method + @brief 实时视频传送摄像头数据 + @param data 摄像头数据,必须是待编码的yuv数据 + @param width 图像的宽 + @param height 图像的高 + */ +- (void)processPreviewData:(char *)data + width:(int)width + height:(int)height; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @method + @brief 接收方同意语音通话的请求 + @param sessionId 要进行的语音通话的ID + @result 检查语音通话条件是否具备,不具备则返回错误信息(未进行实际的拨打动作) + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMError *)asyncAcceptCallSessionWithId:(NSString *)sessionId EM_DEPRECATED_IOS(2_1_2, 2_1_4, "Use - asyncAnswerCall"); + +/*! + @method + @brief 发起方或接收方结束通话 + @param sessionId 要进行的语音通话的ID + @param reason 结束原因 + @result 检查挂断语音通话条件是否具备,不具备则返回错误信息 + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMError *)asyncTerminateCallSessionWithId:(NSString *)sessionId + reason:(EMCallStatusChangedReason)reason EM_DEPRECATED_IOS(2_1_2, 2_1_4, "Use - asyncEndCall:reason:"); + +/*! + @method + @brief 进行实时语音 + @param chatter 要进行语音通话的username(不能与自己通话) + @param timeout 超时时间(传0,使用SDK默认超时时间) + @param pError 检查语音通话条件是否具备,不具备则返回错误信息(未进行实际的拨打动作) + @result 语音通话的实例 + @discussion 需监听[callSessionStatusChanged:changeReason:error:] + */ +- (EMCallSession *)asyncCallAudioWithChatter:(NSString *)chatter + timeout:(NSUInteger)timeout + error:(EMError **)pError EM_DEPRECATED_IOS(2_1_2, 2_1_4, "Use - asyncMakeVoiceCall:timeout:error:"); + + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/EMCallSession.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/EMCallSession.h new file mode 100644 index 0000000..04fc713 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/EMCallSession.h @@ -0,0 +1,56 @@ +/*! + @header EMCallSession.h + @abstract 实时通话实例 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMCallServiceDefs.h" + +@class OpenGLView20; +@interface EMCallSession : NSObject + +/*! + @class + @brief 通话实例的id,唯一 + */ +@property (strong, nonatomic, readonly) NSString *sessionId; + +/*! + @class + @brief 通话对方的username + */ +@property (strong, nonatomic) NSString *sessionChatter; + +/*! + @class + @brief 通话的类型 + */ +@property (nonatomic, readonly) EMCallSessionType type; + +/*! + @class + @brief 通话的状态 + */ +@property (nonatomic) EMCallSessionStatus status; + +/*! + @class + @brief 视频时对方的图像显示区域 + */ +@property (strong, nonatomic) OpenGLView20 *displayView; + +/*! +@method +@brief 创建通话实例(不支持外部调用) +@discussion +@param sessionId 通话实例的id +@param type 通话的类型 +@result 通话实例 +*/ +- (instancetype)initWithSessionId:(NSString *)sessionId + type:(EMCallSessionType)type; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/IOpenGLView.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/IOpenGLView.h new file mode 100644 index 0000000..c5f8f54 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/IOpenGLView.h @@ -0,0 +1,36 @@ +// +// IOpenGLView.h +// EaseMobClientSDK +// +// Created by dhc on 15/5/5. +// Copyright (c) 2015年 EaseMob. All rights reserved. +// + +#import + +@protocol IOpenGLView + +/*! + @method + @brief 将数据画到屏幕上 + @param data 数据 + @param width 宽度 + @param height 高度 + */ +- (void)displayYUV420pData:(char *)data width:(GLuint)width height:(GLuint)height; + +/*! + @method + @brief 设置视频显示区域大小 + @param width 宽度 + @param height 高度 + */ +- (void)setVideoSize:(GLuint)width height:(GLuint)height; + +/*! + @method + @brief 清除画面 + */ +- (void)clearFrame; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/OpenGLView20.h b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/OpenGLView20.h new file mode 100755 index 0000000..5fb4f51 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/CallService/EMCallManager/types/OpenGLView20.h @@ -0,0 +1,84 @@ +/*! + @header OpenGLView20.h + @abstract CallManager的视频显示页面 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import +#import +#import +#import +#import +#include +#import +#import +#import "IOpenGLView.h" + +@interface OpenGLView20 : UIView +{ + /** + OpenGL绘图上下文 + */ + EAGLContext *_glContext; + + /** + 帧缓冲区 + */ + GLuint _framebuffer; + + /** + 渲染缓冲区 + */ + GLuint _renderBuffer; + + /** + 着色器句柄 + */ + GLuint _program; + + /** + YUV纹理数组 + */ + GLuint _textureYUV[3]; + + /** + 视频宽度 + */ + GLuint _videoW; + + /** + 视频高度 + */ + GLuint _videoH; + + //屏幕分辨率 + GLsizei _screenScale; + +#ifdef DEBUG + struct timeval _time; + NSInteger _frameRate; +#endif +} + +/*! + @method + @brief 发给对方的视频分辨率,目前只支持AVCaptureSessionPreset352x288和AVCaptureSessionPreset640x480。 + 默认为AVCaptureSessionPreset640x480。 + */ +@property (strong, nonatomic) NSString *sessionPreset; + +/*! + @method + @brief 摄像头输出设置 + */ +@property (strong, nonatomic, readonly) NSDictionary *outputSettings; + +/*! + @method + @brief 摄像头帧率设置 + */ +@property (nonatomic, readonly) CMTime videoMinFrameDuration; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMChatManagerDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMChatManagerDefs.h new file mode 100644 index 0000000..7a1864a --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMChatManagerDefs.h @@ -0,0 +1,129 @@ +/*! + @header EMChatManagerDefs.h + @abstract ChatManager相关宏定义 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#ifndef EaseMobClientSDK_EMChatManagerDefs_h +#define EaseMobClientSDK_EMChatManagerDefs_h + +#import "commonDefs.h" +#import "EMPushManagerDefs.h" +#import "EMGroupManagerDefs.h" + +/*! + @enum + @brief 聊天类型 + @constant eMessageBodyType_Text 文本类型 + @constant eMessageBodyType_Image 图片类型 + @constant eMessageBodyType_Video 视频类型 + @constant eMessageBodyType_Location 位置类型 + @constant eMessageBodyType_Voice 语音类型 + @constant eMessageBodyType_File 文件类型 + @constant eMessageBodyType_Command 命令类型 + */ +typedef NS_ENUM(NSInteger, MessageBodyType) { + eMessageBodyType_Text = 1, + eMessageBodyType_Image, + eMessageBodyType_Video, + eMessageBodyType_Location, + eMessageBodyType_Voice, + eMessageBodyType_File, + eMessageBodyType_Command +}; + +/*! + @enum + @brief 聊天消息发送状态 + @constant eMessageDeliveryState_Pending 待发送 + @constant eMessageDeliveryState_Delivering 正在发送 + @constant eMessageDeliveryState_Delivered 已发送, 成功 + @constant eMessageDeliveryState_Failure 已发送, 失败 + */ +typedef NS_ENUM(NSInteger, MessageDeliveryState) { + eMessageDeliveryState_Pending = 0, + eMessageDeliveryState_Delivering, + eMessageDeliveryState_Delivered, + eMessageDeliveryState_Failure +}; + +/*! + @brief 消息回执类型 + @constant eReceiptTypeRequest 回执请求 + @constant eReceiptTypeResponse 回执响应 + */ +typedef NS_ENUM(NSInteger, EMReceiptType){ + eReceiptTypeRequest = 0, + eReceiptTypeResponse, +}; + +/* +@brief 会话类型 +@constant eConversationTypeChat 单聊会话 +@constant eConversationTypeGroupChat 群聊会话 +@constant eConversationTypeChatRoom 聊天室会话 +*/ +typedef NS_ENUM(NSInteger, EMConversationType){ + eConversationTypeChat, + eConversationTypeGroupChat, + eConversationTypeChatRoom +}; + +/*! + @brief 消息类型 + @constant eMessageTypeChat 单聊消息 + @constant eMessageTypeGroupChat 群聊消息 + @constant eMessageTypeChatRoom 聊天室消息 + */ +typedef NS_ENUM(NSInteger, EMMessageType){ + eMessageTypeChat, + eMessageTypeGroupChat, + eMessageTypeChatRoom +}; + +/*! + @enum + @brief 备份消息状态 + @constant eBackupMessagesStatusNone 初始状态 + @constant eBackupMessagesStatusFormatting 格式化消息 + @constant eBackupMessagesStatusCompressing 压缩消息 + @constant eBackupMessagesStatusUploading 上传消息 + @constant eBackupMessagesStatusUpdating 更新云端备份 + @constant eBackupMessagesStatusCancelled 取消备份 + @constant eBackupMessagesStatusFailed 备份失败 + @constant eBackupMessagesStatusSucceeded 备份成功 + */ +typedef NS_ENUM(NSInteger, EMBackupMessagesStatus) { + eBackupMessagesStatusNone = 0, + eBackupMessagesStatusFormatting, + eBackupMessagesStatusCompressing, + eBackupMessagesStatusUploading, + eBackupMessagesStatusUpdating, + eBackupMessagesStatusCancelled, + eBackupMessagesStatusFailed, + eBackupMessagesStatusSucceeded, +}; + +/*! + @enum + @brief 恢复备份消息状态 + @constant eRestoreBackupStatusNone 初始状态 + @constant eRestoreBackupStatusDownload 备份下载 + @constant eRestoreBackupStatusDecompressing 解压缩 + @constant eRestoreBackupStatusImporting 导入 + @constant eRestoreBackupStatusCancelled 取消恢复 + @constant eRestoreBackupStatusFailed 恢复备份失败 + @constant eRestoreBackupStatusSucceeded 恢复备份成功 + */ +typedef NS_ENUM(NSInteger, EMRestoreBackupStatus) { + eRestoreBackupStatusNone = 0, + eRestoreBackupStatusDownloading, + eRestoreBackupStatusDecompressing, + eRestoreBackupStatusImporting, + eRestoreBackupStatusCancelled, + eRestoreBackupStatusFailed, + eRestoreBackupStatusSucceeded, +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMGroupManagerDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMGroupManagerDefs.h new file mode 100644 index 0000000..47dbfc0 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMGroupManagerDefs.h @@ -0,0 +1,38 @@ +/*! + @header EMGroupManagerDefs.h + @abstract GroupManager相关宏定义 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#ifndef EaseMobClientSDK_EMGroupManagerDefs_h +#define EaseMobClientSDK_EMGroupManagerDefs_h + +/*! + @enum + @brief 退出群组的原因 + @constant eGroupLeaveReason_BeRemoved 被管理员移除出该群组 + @constant eGroupLeaveReason_UserLeave 用户主动退出该群组 + @constant eGroupLeaveReason_Destroyed 该群组被别人销毁 + */ +typedef NS_ENUM(NSInteger, EMGroupLeaveReason) { + eGroupLeaveReason_BeRemoved = 1, + eGroupLeaveReason_UserLeave, + eGroupLeaveReason_Destroyed +}; + +/*! + @enum + @brief 群组中的成员角色 + @constant eGroupMemberRole_Member 普通成员 + @constant eGroupMemberRole_Admin 群组管理员 + @constant eGroupMemberRole_Owner 群组创建者 + */ +typedef NS_ENUM(NSInteger, EMGroupMemberRole) { + eGroupMemberRole_Member = 0, + eGroupMemberRole_Admin, + eGroupMemberRole_Owner, +} ; + + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMPushManagerDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMPushManagerDefs.h new file mode 100644 index 0000000..efbf509 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/EMPushManagerDefs.h @@ -0,0 +1,42 @@ +/*! + @header EMPushManagerDefs.h + @abstract PushManager相关宏定义 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#ifndef EaseMobClientSDK_EMPushManagerDefs_h +#define EaseMobClientSDK_EMPushManagerDefs_h + +#define kPushNotificationMaskDisplayStyle 0x01 +#define kPushNotificationMaskNickname 0x01<<1 +#define kPushNotificationMaskNoDisturbing 0x01<<2 +#define kPushNotificationMaskNoDisturbingStart 0x01<<3 +#define kPushNotificationMaskNoDisturbingEnd 0x01<<4 +#define kPushNotificationMaskAll 0x01<<7 + +/*! + @enum + @brief 推送消息的定制信息 + @constant ePushNotificationDisplayStyle_simpleBanner 简单显示一条"您有一条新消息"的文本 + @constant ePushNotificationDisplayStyle_messageSummary 会显示一条具有消息内容的推送消息 + */ +typedef NS_ENUM(NSInteger, EMPushNotificationDisplayStyle) { + ePushNotificationDisplayStyle_simpleBanner = 0, + ePushNotificationDisplayStyle_messageSummary = 1, +}; + +/*! + @enum + @brief 推送消息免打扰设置的状态 + @constant ePushNotificationNoDisturbStatusDay 全天免打扰 + @constant ePushNotificationNoDisturbStatusCustom 自定义时间段免打扰 + @constant ePushNotificationNoDisturbStatusClose 关闭免打扰模式 + */ +typedef NS_ENUM(NSInteger, EMPushNotificationNoDisturbStatus) { + ePushNotificationNoDisturbStatusDay = 0, + ePushNotificationNoDisturbStatusCustom = 1, + ePushNotificationNoDisturbStatusClose = 2, +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/IChatManager.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/IChatManager.h new file mode 100644 index 0000000..fd22b9b --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/IChatManager.h @@ -0,0 +1,39 @@ +/*! + @header IChatManager.h + @abstract 此接口提供了聊天的基本操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IChatManagerChat.h" +#import "IChatManagerEncryption.h" +#import "IChatManagerConversation.h" +#import "IChatManagerUtil.h" +#import "IChatManagerLogin.h" +#import "IChatManagerBuddy.h" +#import "IChatManagerGroup.h" +#import "IChatManagerSettingOptions.h" +#import "IChatManagerPushNotification.h" +#import "IChatManagerChatroom.h" + +/*! + @protocol + @brief 登录、聊天、保存会话、加解密、多媒体支持等协议的集合 + @discussion 可以通过EaseMob类获得此接口的实例, 示例代码如下: + [[EaseMob sharedInstance] chatManager] + */ +@protocol IChatManager + +@required + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/IChatManagerDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/IChatManagerDelegate.h new file mode 100644 index 0000000..68d7508 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/IChatManagerDelegate.h @@ -0,0 +1,18 @@ +/*! + @header EMChatManagerDelegate.h + @abstract 关于ChatManager的异步回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EMChatManagerDelegate.h" + +/** + * 本协议主要处理聊天时的一些回调操作(如发送消息成功、收到消息、收到添加好友邀请等消息时的回调操作) + */ +@protocol IChatManagerDelegate + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerBuddyDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerBuddyDelegate.h new file mode 100644 index 0000000..a0edc7e --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerBuddyDelegate.h @@ -0,0 +1,133 @@ +/*! + @header EMChatManagerBuddyDelegate.h + @abstract 添加好友,删除好友,接收到好友请求时的回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ +#import +#import "EMChatManagerDelegateBase.h" +#import "IChatManager.h" + +@class EMBuddy; +/*! + @protocol + @brief 添加好友,删除好友,接收到好友请求时的回调协议 + @discussion + */ +@protocol EMChatManagerBuddyDelegate + +@optional + +/*! + @method + @brief 接收到好友请求时的通知 + @discussion + @param username 发起好友请求的用户username + @param message 收到好友请求时的say hello消息 + */ +- (void)didReceiveBuddyRequest:(NSString *)username + message:(NSString *)message; + +/*! + @method + @brief 好友请求被接受时的回调 + @discussion + @param username 之前发出的好友请求被用户username接受了 + */ +- (void)didAcceptedByBuddy:(NSString *)username; + +/*! + @method + @brief 好友请求被拒绝时的回调 + @discussion + @param username 之前发出的好友请求被用户username拒绝了 + */ +- (void)didRejectedByBuddy:(NSString *)username; + +/*! + @method + @brief 接受好友请求成功的回调 + @discussion + @param username 登录用户接受了"username发过来的好友请求"成功的回调 + */ +- (void)didAcceptBuddySucceed:(NSString *)username; + +/*! + @method + @brief 登录的用户被好友从列表中删除了 + @discussion + @param username 删除的好友username + */ +- (void)didRemovedByBuddy:(NSString *)username; + +/*! + @method + @brief 通讯录信息发生变化时的通知 + @discussion + @param buddyList 好友信息列表 + @param changedBuddies 修改了的用户列表 + @param isAdd (YES为新添加好友, NO为删除好友) + */ +- (void)didUpdateBuddyList:(NSArray *)buddyList + changedBuddies:(NSArray *)changedBuddies + isAdd:(BOOL)isAdd; + +/*! + @method + @brief 好友分组信息发生变化时的通知 + @discussion + @param buddyGroupList 好友分组信息 + @since + */ +- (void)didUpdateBuddyGroupList:(NSArray *)buddyGroupList EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @method + @brief 获取好友列表成功时的回调 + @discussion + @param buddyList 好友列表 + @param error 错误信息 + */ +- (void)didFetchedBuddyList:(NSArray *)buddyList + error:(EMError *)error; + +/*! + @method + @brief 好友上线和下线时的通知 + @discussion + @param isOnline 好友信息列表 + @param username 修改了状态的用户 + */ +- (void)didChangedOnlineStatus:(BOOL)isOnline + forBuddy:(NSString *)username EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +#pragma mark - block + +/*! + @method + @brief 好友黑名单有更新时的回调 + @discussion + @param blockedList 被加入黑名单的好友的列表 + */ +- (void)didUpdateBlockedList:(NSArray *)blockedList; + +/*! + @method + @brief 将好友加到黑名单完成后的回调 + @discussion + @param username 加入黑名单的好友 + @param pError 错误信息 + */ +- (void)didBlockBuddy:(NSString *)username error:(EMError *)pError; + +/*! + @method + @brief 将好友移出黑名单完成后的回调 + @discussion + @param username 移出黑名单的好友 + @param pError 错误信息 + */ +- (void)didUnblockBuddy:(NSString *)username error:(EMError *)pError; + + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerChatDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerChatDelegate.h new file mode 100644 index 0000000..35f84ca --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerChatDelegate.h @@ -0,0 +1,186 @@ +/*! + @header EMChatManagerChatDelegate.h + @abstract 关于ChatManager中聊天相关功能的异步回调 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EMChatManagerDelegateBase.h" + +@class EMMessage; +@class EMConversation; +@class EMError; +@class EMReceipt; + +/*! + @protocol + @brief 本协议包括:发送消息时的回调、接收到消息时的回调等其它操作 + @discussion + */ +@protocol EMChatManagerChatDelegate + +@optional + +/*! + @method + @brief 将要发送消息时的回调 + @discussion + @param message 将要发送的消息对象 + @param error 错误信息 + @result + */ +- (void)willSendMessage:(EMMessage *)message + error:(EMError *)error; + +/*! + @method + @brief 发送消息后的回调 + @discussion + @param message 已发送的消息对象 + @param error 错误信息 + @result + */ +- (void)didSendMessage:(EMMessage *)message + error:(EMError *)error; + +/*! + @method + @brief 收到消息时的回调 + @param message 消息对象 + @discussion 当EMConversation对象的enableReceiveMessage属性为YES时, 会触发此回调 + 针对有附件的消息, 此时附件还未被下载. + 附件下载过程中的进度回调请参考didFetchingMessageAttachments:progress:, + 下载完所有附件后, 回调didMessageAttachmentsStatusChanged:error:会被触发 + */ +- (void)didReceiveMessage:(EMMessage *)message; + +/*! + @method + @brief 收到消息时的回调 + @param cmdMessage 消息对象 + @discussion 当EMConversation对象的enableReceiveMessage属性为YES时, 会触发此回调 + 针对有附件的消息, 此时附件还未被下载. + 附件下载过程中的进度回调请参考didFetchingMessageAttachments:progress:, + 下载完所有附件后, 回调didMessageAttachmentsStatusChanged:error:会被触发 + */ +- (void)didReceiveCmdMessage:(EMMessage *)cmdMessage; + +/*! + @method + @brief 收到发送消错误的回调 + @param messageId 消息Id + @param conversationChatter 会话的username/groupId + @param error 错误信息 + */ +- (void)didReceiveMessageId:(NSString *)messageId + chatter:(NSString *)conversationChatter + error:(EMError *)error; + +/*! + @method + @brief SDK接收到消息时, 下载附件的进度回调, 回调方法有不在主线程中调用, 需要App自己切换到主线程中执行UI的刷新等操作 + @discussion SDK接收到消息时, 有以下两种情况: + 1. 如果是带缩略图的消息时(图片或Video), 会自动下载缩略图, + 下载完成后, 会调用 didMessageAttachmentsStatusChanged:error这个回调 + 2. 如果是语音消息时, 会自动下载语音附件, + 会调用 didMessageAttachmentsStatusChanged:error这个回调 + @param message 正在下载的消息对象 + @param progress 下载进度 + @result + */ +- (void)didFetchingMessageAttachments:(EMMessage *)message + progress:(float)progress; + +/*! + @method + @brief SDK接收到消息时, 下载附件成功或失败的回调 + @discussion SDK接收到消息时, 有以下两种情况: + 1. 如果是带缩略图的消息时(图片或Video), 会自动下载缩略图, + 2. 如果是语音消息时, 会自动下载语音附件, + @param message 下载完成的消息对象 + @param error 若附件下载成功, error为nil, 若下载失败, 则会返回相应的error信息 + @result + */ +- (void)didMessageAttachmentsStatusChanged:(EMMessage *)message error:(EMError *)error; + +/*! + @method + @brief 收到"已读回执"时的回调方法 + @discussion 发送方收到接收方发送的一个收到消息的回执, 意味着接收方已阅读了该消息 + @param resp 收到的"已读回执"对象, 包括 from, to, chatId等 + @result + */ +- (void)didReceiveHasReadResponse:(EMReceipt *)resp; + +/*! + @method + @brief 收到"已送达回执"时的回调方法 + @discussion 发送方收到接收方发送的一个收到消息的回执, 但不意味着接收方已阅读了该消息 + @param resp 收到的"已送达回执"对象, 包括 from, to, chatId等 + @result + */ +- (void)didReceiveHasDeliveredResponse:(EMReceipt *)resp; + +/*! + @method + @brief 会话列表信息更新时的回调 + @discussion 1. 当会话列表有更改时(新添加,删除), 2. 登陆成功时, 以上两种情况都会触发此回调 + @param conversationList 会话列表 + @result + */ +- (void)didUpdateConversationList:(NSArray *)conversationList; + +/*! + @method + @brief 未读消息数改变时的回调 + @discussion 当EMConversation对象的enableUnreadMessagesCountEvent为YES时,会触发此回调 + @result + */ +- (void)didUnreadMessagesCountChanged; + +/*! + @method + @brief 将要接收离线消息的回调 + @discussion + @result + */ +- (void)willReceiveOfflineMessages; + +/*! + @method + @brief 接收到离线非透传消息的回调 + @discussion + @param offlineMessages 接收到的离线列表 + @result + */ +- (void)didReceiveOfflineMessages:(NSArray *)offlineMessages; + +/*! + @method + @brief 接收到离线透传消息的回调 + @discussion + @param offlineCmdMessages 接收到的离线透传消息列表 + @result + */ +- (void)didReceiveOfflineCmdMessages:(NSArray *)offlineCmdMessages; + +/*! + @method + @brief 离线非透传消息接收完成的回调 + @discussion + @param offlineMessages 接收到的离线列表 + @result + */ +- (void)didFinishedReceiveOfflineMessages:(NSArray *)offlineMessages; + +/*! + @method + @brief 离线透传消息接收完成的回调 + @discussion + @param offlineCmdMessages 接收到的离线透传消息列表 + @result + */ +- (void)didFinishedReceiveOfflineCmdMessages:(NSArray *)offlineCmdMessages; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerChatroomDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerChatroomDelegate.h new file mode 100644 index 0000000..680e9a0 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerChatroomDelegate.h @@ -0,0 +1,68 @@ +/*! + @header EMChatManagerChatroomDelegate.h + @abstract 聊天室回调协议 + @author EaseMob Inc. + @version 1.00 2015/04/09 Creation (1.00) + */ + +#import +#import "EMChatManagerDelegateBase.h" + +/*! + @enum + @brief 被踢出聊天室的原因 + @constant eChatroomBeKickedReason_BeRemoved 被管理员移出该聊天室 + @constant eChatroomBeKickedReason_Destroyed 聊天室被销毁 + */ +typedef NS_ENUM(NSInteger, EMChatroomBeKickedReason) { + eChatroomBeKickedReason_BeRemoved = 1, + eChatroomBeKickedReason_Destroyed +}; + +@class EMChatroom; + +/*! + @protocol + @brief 此协议提供了聊天室操作的回调 + @discussion + */ +@protocol EMChatManagerChatroomDelegate + +@optional + +/*! + @method + @brief 有用户加入聊天室 + @param chatroom 加入的聊天室 + @param username 加入者名称 + */ +- (void)chatroom:(EMChatroom *)chatroom occupantDidJoin:(NSString *)username; + +/*! + @method + @brief 有用户离开聊天室 + @param chatroom 离开的聊天室 + @param username 离开者名称 + */ +- (void)chatroom:(EMChatroom *)chatroom occupantDidLeave:(NSString *)username; + +/*! + @method + @brief 被踢出聊天室 + @param chatroom 被踢出的聊天室 + @param reason 被踢出聊天室的原因 + */ +- (void)beKickedOutFromChatroom:(EMChatroom *)chatroom reason:(EMChatroomBeKickedReason)reason; + +/*! + @method + @brief 收到加入聊天室的邀请 + @param chatroomId 聊天室ID + @param username 邀请人名称 + @param message 邀请信息 + @discussion + */ +- (void)didReceiveChatroomInvitationFrom:(NSString *)chatroomId + inviter:(NSString *)username + message:(NSString *)message; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerDelegate.h new file mode 100644 index 0000000..dfa2e96 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerDelegate.h @@ -0,0 +1,34 @@ +/*! + @header EMChatManagerDelegate.h + @abstract 关于ChatManager的异步回调内部协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EMChatManagerChatDelegate.h" +#import "EMChatManagerEncryptionDelegate.h" +#import "EMChatManagerLoginDelegate.h" +#import "EMChatManagerBuddyDelegate.h" +#import "EMChatManagerUtilDelegate.h" +#import "EMChatManagerGroupDelegate.h" +#import "EMChatManagerPushNotificationDelegate.h" +#import "EMChatManagerChatroomDelegate.h" + +/*! + @protocol + @brief 本协议包括:收发消息, 登陆注销, 加密解密, 媒体操作的回调等其它操作 + @discussion + */ +@protocol EMChatManagerDelegate + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerDelegateBase.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerDelegateBase.h new file mode 100644 index 0000000..1cd5235 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerDelegateBase.h @@ -0,0 +1,19 @@ +/*! + @header EMChatManagerDelegateBase.h + @abstract 关于ChatManager中基本的异步回调 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +/*! + @protocol + @brief 聊天回调基类 + @discussion 所有聊天回调接口皆派生于此基类 + */ +@protocol EMChatManagerDelegateBase + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerEncryptionDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerEncryptionDelegate.h new file mode 100644 index 0000000..69b5b24 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerEncryptionDelegate.h @@ -0,0 +1,19 @@ +/*! + @header EMChatManagerEncryptionDelegate.h + @abstract 关于ChatManager中加密解密相关功能的异步回调 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +/*! + @protocol + @brief 关于ChatManager中加密解密相关功能的异步回调协议接口 + @discussion + */ +@protocol EMChatManagerEncryptionDelegate + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerGroupDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerGroupDelegate.h new file mode 100644 index 0000000..6af67e0 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerGroupDelegate.h @@ -0,0 +1,291 @@ +/*! + @header EMChatManagerUtilDelegate.h + @abstract 此协议提供了一些群组操作的回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EMChatManagerDelegateBase.h" + +@class EMGroup; + +/*! + @protocol + @brief 此协议提供了一些群组操作的回调 + @discussion + */ +@protocol EMChatManagerGroupDelegate + +@optional + +/*! + @method + @brief 创建一个群组后的回调 + @param group 所创建的群组对象 + @param error 错误信息 + @discussion + */ +- (void)group:(EMGroup *)group didCreateWithError:(EMError *)error; + +/*! + @method + @brief 离开一个群组后的回调 + @param group 所要离开的群组对象 + @param reason 离开的原因 + @param error 错误信息 + @discussion + 离开的原因包含主动退出, 被别人请出, 和销毁群组三种情况 + */ +- (void)group:(EMGroup *)group + didLeave:(EMGroupLeaveReason)reason + error:(EMError *)error; + +/*! + @method + @brief 群组信息更新后的回调 + @param group 发生更新的群组 + @param error 错误信息 + @discussion + 当添加/移除/更改角色/更改主题/更改群组信息之后,都会触发此回调 + */ +- (void)groupDidUpdateInfo:(EMGroup *)group + error:(EMError *)error; + +/*! + @method + @brief 收到了其它群组的加入邀请 + @param groupId 群组ID + @param username 邀请人名称 + @param message 邀请信息 + @discussion + */ +- (void)didReceiveGroupInvitationFrom:(NSString *)groupId + inviter:(NSString *)username + message:(NSString *)message EM_DEPRECATED_IOS(2_0_0, 2_0_6, "Use -didAutoAcceptedGroupInvitationFrom:inviter:message:"); + +/*! + @method + @brief 收到了已自动加入某个群组的通知(你收到通知时已是该群成员) + @param groupId 群组ID + @param username 邀请人名称 + @param message 邀请信息 + @discussion + 主要发生 1、于创建群组时,被选为默认成员;2、isAutoAcceptGroupInvitation为YES + */ +- (void)didAutoAcceptedGroupInvitationFrom:(NSString *)groupId + inviter:(NSString *)username + message:(NSString *)message EM_DEPRECATED_IOS(2_0_6, 2_1_1, "didAcceptInvitationFromGroup:error:"); + +/*! + @method + @brief 接受群组邀请并加入群组后的回调 + @param group 所接受的群组 + @param error 错误信息 + */ +- (void)didAcceptInvitationFromGroup:(EMGroup *)group + error:(EMError *)error; + +/*! + @method + @brief 收到了其它群组的加入邀请 + 发送邀人申请失败 + @param groupId 群组ID + @param username 邀请人名称 + @param message 邀请信息 + @param error 错误信息 + @discussion + */ +- (void)didReceiveGroupInvitationFrom:(NSString *)groupId + inviter:(NSString *)username + message:(NSString *)message + error:(EMError *)error; + +/*! + @method + @brief 邀请别人加入群组, 但被别人拒绝后的回调 + @param groupId 群组ID + @param username 拒绝的人的用户名 + @param reason 拒绝理由 + @discussion + */ +- (void)didReceiveGroupRejectFrom:(NSString *)groupId + invitee:(NSString *)username + reason:(NSString *)reason EM_DEPRECATED_IOS(2_0_0, 2_0_6, "Use -didReceiveGroupRejectFrom:invitee:reason:error:"); + +/*! + @method + @brief 邀请别人加入群组, 但被别人拒绝后的回调 + 拒绝群组邀请发生错误 + @param groupId 群组ID + @param username 拒绝的人的用户名 + @param reason 拒绝理由 + @param error 错误信息 + @discussion + */ +- (void)didReceiveGroupRejectFrom:(NSString *)groupId + invitee:(NSString *)username + reason:(NSString *)reason + error:(EMError *)error; + +/*! + @method + @brief 收到加入群组的申请 + @param groupId 要加入的群组ID + @param groupname 申请人的用户名 + @param username 申请人的昵称 + @param reason 申请理由 + @discussion + */ +- (void)didReceiveApplyToJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + applyUsername:(NSString *)username + reason:(NSString *)reason EM_DEPRECATED_IOS(2_0_0, 2_0_6, "Use -didReceiveApplyToJoinGroup:groupname:applyUsername:reason:error:"); + +/*! + @method + @brief 收到加入群组的申请 + 申请入群发生错误 + @param groupId 要加入的群组ID + @param groupname 申请人的用户名 + @param username 申请人的昵称 + @param reason 申请理由 + @param error 错误信息 + @discussion + */ +- (void)didReceiveApplyToJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + applyUsername:(NSString *)username + reason:(NSString *)reason + error:(EMError *)error; + +/*! + @method + @brief 申请加入群组,被拒绝后的回调 + @param fromId 拒绝的人的ID + @param groupname 申请加入的群组名称 + @param reason 拒绝理由 + */ +- (void)didReceiveRejectApplyToJoinGroupFrom:(NSString *)fromId + groupname:(NSString *)groupname + reason:(NSString *)reason EM_DEPRECATED_IOS(2_0_0, 2_0_6, "Use -didReceiveRejectApplyToJoinGroupFrom:groupname:reason:error:"); + +/*! + @method + @brief 申请加入群组,被拒绝后的回调 + 群主拒绝入群申请发生错误 + @param fromId 拒绝的人的ID + @param groupname 申请加入的群组名称 + @param reason 拒绝理由 + @param error 错误信息 + */ +- (void)didReceiveRejectApplyToJoinGroupFrom:(NSString *)fromId + groupname:(NSString *)groupname + reason:(NSString *)reason + error:(EMError *)error; + +/*! + @method + @brief 申请加入群组,同意后的回调 + @param groupId 申请加入的群组的ID + @param groupname 申请加入的群组名称 + */ +- (void)didReceiveAcceptApplyToJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname EM_DEPRECATED_IOS(2_0_0, 2_0_6, "Use -didReceiveAcceptApplyToJoinGroup:groupname:error:"); + +/*! + @method + @brief 用户申请加入群组,群主同意后,用户收到回调 + 用户申请入群,群主同意申请发生错误 + @param groupId 申请加入的群组的ID + @param groupname 申请加入的群组名称 + @param error 错误信息 + */ +- (void)didReceiveAcceptApplyToJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + error:(EMError *)error; + +/*! + @method + @brief 同意入群申请后,同意者收到的回调 + @param groupId 申请加入的群组的ID + @param username 申请加入的人的username + @param error 错误信息 + */ +- (void)didAcceptApplyJoinGroup:(NSString *)groupId + username:(NSString *)username + error:(EMError *)error; + +/*! + @method + @brief 群组列表变化后的回调 + @param groupList 新的群组列表 + @param error 错误信息 + */ +- (void)didUpdateGroupList:(NSArray *)groupList + error:(EMError *)error; + +/*! + @method + @brief 获取所有公开群组后的回调 + @param groups 公开群组列表 + @param error 错误信息 + */ +- (void)didFetchAllPublicGroups:(NSArray *)groups + error:(EMError *)error; + +/*! + @method + @brief 获取群组信息后的回调 + @param group 群组对象 + @param error 错误信息 + */ +- (void)didFetchGroupInfo:(EMGroup *)group + error:(EMError *)error; + +/*! + @method + @brief 获取群组成员列表后的回调 + @param occupantsList 群组成员列表(包含创建者) + @param error 错误信息 + */ +- (void)didFetchGroupOccupantsList:(NSArray *)occupantsList + error:(EMError *)error; + +/*! + @method + @brief 获取群组黑名单列表后的回调 + @param groupId 群组id + @param bansList 群组黑名单列表 + @param error 错误信息 + */ +- (void)didFetchGroupBans:(NSString *)groupId + list:(NSArray *)bansList + error:(EMError *)error; + +/*! + @method + @brief 加入公开群组后的回调 + @param group 群组对象 + @param error 错误信息 + */ +- (void)didJoinPublicGroup:(EMGroup *)group + error:(EMError *)error; + +/*! + @method + @brief 申请加入公开群组后的回调 + @param group 群组对象 + @param error 错误信息 + */ +- (void)didApplyJoinPublicGroup:(EMGroup *)group + error:(EMError *)error; + +#pragma mark - Anonymous Group nickname + +/*! + @method + @brief 删除App后, 重新join匿名群时, 获取不到 nickname, 需要app主动提供一个nickname, 如果未主动提供或返回nil, SDK会随机生成一个nickname(字母+数字) + @param account 当前登录的用户 + @param groupId 用户所在的(匿名)群组id + @result 用户在该群组中的昵称 + */ +- (NSString *)nicknameForAccount:(NSString *)account + inGroup:(NSString *)groupId; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerLoginDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerLoginDelegate.h new file mode 100644 index 0000000..b16b686 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerLoginDelegate.h @@ -0,0 +1,111 @@ +/*! + @header EMChatManagerLoginDelegate.h + @abstract 关于ChatManager中登陆相关功能的异步回调 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +@class EMError; + +/*! + @protocol + @brief 本协议包括:登录成功的回调、登录失败的回调、修改密码的回调、账号在其它设置上登录时的回调操作 + @discussion + */ +@protocol EMChatManagerLoginDelegate + +@optional + +/*! + @method + @brief 用户将要进行自动登录操作的回调 + @discussion + @param loginInfo 登录的用户信息 + @param error 错误信息 + @result + */ +- (void)willAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error; + +/*! + @method + @brief 用户自动登录完成后的回调 + @discussion + @param loginInfo 登录的用户信息 + @param error 错误信息 + @result + */ +- (void)didAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error; + +/*! + @method + @brief 用户登录后的回调 + @discussion + @param loginInfo 登录的用户信息 + @param error 错误信息 + @result + */ +- (void)didLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error; + +/*! + @method + @brief 用户注销后的回调 + @discussion + @param error 错误信息 + @result + */ +- (void)didLogoffWithError:(EMError *)error; + +/*! + @method + @brief 当前登录账号在其它设备登录时的通知回调 + @discussion + @result + */ +- (void)didLoginFromOtherDevice; + +/*! + @method + @brief 当前登录账号已经被从服务器端删除 + @discussion + @result + */ +- (void)didRemovedFromServer; + +/*! + @method + @brief 当前登陆用户掉线重连后发生的通知回调 + @discussion + @result + */ +- (void)didReconnect __attribute__((deprecated("需要使用 willAutoReconnect 与 didAutoReconnectFinishedWithError: 方法判断是否正在重连"))); + +/*! + @method + @brief 注册新用户后的回调 + @param error 错误信息 + @discussion + @result + */ +- (void)didRegisterNewAccount:(NSString *)username + password:(NSString *)password + error:(EMError *)error; + +/*! + @method + @brief 将要发起自动重连操作 + @discussion + @result + */ +- (void)willAutoReconnect; + +/*! + @method + @brief 自动重连操作完成后的回调(成功的话,error为nil,失败的话,查看error的错误信息) + @discussion + @result + */ +- (void)didAutoReconnectFinishedWithError:(NSError *)error; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerPushNotificationDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerPushNotificationDelegate.h new file mode 100644 index 0000000..e3cba33 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerPushNotificationDelegate.h @@ -0,0 +1,41 @@ +/*! + @header EMChatManagerPushNotificationDelegate.h + @abstract 为推送通知提供基础操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EMChatManagerDelegateBase.h" + +@class EMPushNotificationOptions; +@class EMError; + +/*! + @protocol + @brief 本协议包括:更新推送设置后的回调 + @discussion + */ +@protocol EMChatManagerPushNotificationDelegate + +@optional + +/*! + @method + @brief 更新全局推送设置后的回调 + @param options 更新后的全局推送设置 + @param error 错误信息 + */ +- (void)didUpdatePushOptions:(EMPushNotificationOptions *)options + error:(EMError *)error; + +/*! + @method + @brief 屏蔽/取消屏蔽 群推送消息后的回调 + @param ignoredGroupList 被屏蔽的群ID列表 + @param error 错误信息 + */ +- (void)didIgnoreGroupPushNotification:(NSArray *)ignoredGroupList + error:(EMError *)error; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerUtilDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerUtilDelegate.h new file mode 100644 index 0000000..b463f36 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/delegates/internal/EMChatManagerUtilDelegate.h @@ -0,0 +1,53 @@ +/*! + @header EMChatManagerUtilDelegate.h + @abstract 此协议提供了一些实用工具类的回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMNetworkMonitorDefs.h" + +@protocol IEMFileMessageBody; + +/*! + @protocol + @brief 此协议提供了一些实用工具类的回调 + @discussion + */ +@protocol EMChatManagerUtilDelegate + +@optional + +/*! + @method + @brief 收取消息体对象后的回调 + @discussion 当获取完消息体对象后,此回调会被触发;如果此消息体所在的消息对象在服务器端已被加密,那么下载完成后会自动进行解压 + @param aMessage 要获取的消息对象 + @param error 错误信息 + */ +- (void)didFetchMessage:(EMMessage *)aMessage error:(EMError *)error; + +/*! + @method + @brief 下载消息缩略图完成后的回调 + @discussion 当获取完缩略图后, 此回调会被触发;如果此消息体所在的消息对象在服务器端已被加密,那么下载完成后会自动进行解压 + @param aMessage 要获取的消息对象 + @param error 错误信息 + */ +- (void)didFetchMessageThumbnail:(EMMessage *)aMessage error:(EMError *)error; + +/*! + @method + @brief SDK连接服务器的状态变化时的回调 + @discussion 有以下几种情况, 会引起该方法的调用: + 1. 登录成功后, 手机无法上网时, 会调用该回调 + 2. 登录成功后, 网络状态变化时, 会调用该回调 + 由于网络变化时, 都会调用到该方法, + 如果需要保存前一次的connectionState, 需要自己手动保存该变量 + @param connectionState 当前SDK连接服务器的状态变化 + */ +- (void)didConnectionStateChanged:(EMConnectionState)connectionState; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerBase.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerBase.h new file mode 100644 index 0000000..26b4c76 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerBase.h @@ -0,0 +1,42 @@ +/*! + @header IChatManagerBase.h + @abstract 为ChatManager提供基础操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "commonDefs.h" + +@protocol EMChatManagerDelegate; + +/*! + @protocol + @brief 聊天的基础协议, 用于注册对象到监听列表和从监听列表中移除对象 + @discussion + */ +@protocol IChatManagerBase + +@required + +/*! + @method + @brief 注册一个监听对象到监听列表中 + @discussion 把监听对象添加到监听列表中准备接收相应的事件 + @param delegate 需要注册的监听对象 + @param queue 通知监听对象时的线程 + @result + */ +- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)queue; + +/*! + @method + @brief 从监听列表中移除一个监听对象 + @discussion 把监听对象从监听列表中移除,取消接收相应的事件 + @param delegate 需要移除的监听对象 + @result + */ +- (void)removeDelegate:(id)delegate; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerBuddy.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerBuddy.h new file mode 100644 index 0000000..6d17522 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerBuddy.h @@ -0,0 +1,309 @@ +/*! + @header IChatManagerBuddy.h + @abstract 为ChatManager提供添加好友,删除好友接受好友等操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IChatManagerBase.h" + +/*! + @enum + @brief 好友关系 + @constant eRelationshipBoth 双向定制 + @constant eRelationshipFrom + @constant eRelationshipTo + */ + +typedef NS_ENUM(NSInteger, EMRelationship){ + eRelationshipBoth = 0, + eRelationshipFrom, + eRelationshipTo, +}; + +/*! + @protocol + @brief 本协议包括:添加好友,删除好友,接受好友请求等方法 + @discussion + */ +@protocol IChatManagerBuddy + +@required + +/*! + @property + @brief 好友列表(由EMBuddy对象组成) + */ +@property (nonatomic, strong, readonly) NSArray *buddyList; + +/*! + @property + @brief 好友黑名单列表(由EMBuddy对象组成) + */ +@property (nonatomic, strong, readonly) NSArray *blockedList; + +#pragma mark - fetch buddy from server + +/*! + @method + @brief 手动获取好友列表 + @discussion + @result 好友列表 + */ +- (NSArray *)fetchBuddyListWithError:(EMError **)pError; + +/*! + @method + @brief 手动获取好友列表(异步方法) + @discussion 好友列表获取完成时, 会调用 didFetchedBuddyList:error(EMChatManagerBuddyDelegate.h 中) 回调方法 + */ +- (void *)asyncFetchBuddyList; + +/*! + @method + @brief 手动获取好友列表(异步方法) + @discussion + @param completion 获取好友列表完成后的回调 + @param queue completion block 回调时的线程 + */ +- (void *)asyncFetchBuddyListWithCompletion:(void (^)(NSArray *buddyList, EMError *error))completion + onQueue:(dispatch_queue_t)queue; + +#pragma mark - add buddy + +/*! + @method + @brief 申请添加某个用户为好友 + @discussion + @param username 需要添加为好友的username + @param message 申请添加好友时的附带信息 + @param pError 错误信息 + @result 好友申请是否发送成功 + */ +- (BOOL)addBuddy:(NSString *)username + message:(NSString *)message + error:(EMError **)pError; + +/*! + @method + @brief 申请添加某个用户为好友,同时将该好友添加到分组中,好友与分组可以多对多 + @discussion + @param username 需要添加为好友的username + @param message 申请添加好友时的附带信息 + @param groupNames 将好友添加到分组中(groupNames由NSString对象组成) + @param pError 错误信息 + @result 好友申请是否发送成功 + */ +- (BOOL)addBuddy:(NSString *)username + message:(NSString *)message + toGroups:(NSArray *)groupNames + error:(EMError **)pError; + +#pragma mark - remove buddy + +/*! + @method + @brief 将某个用户从好友列表中移除 + @discussion + @param username 需要移除的好友username + @param removeFromRemote 是否将自己从对方好友列表中移除 + @param pError 错误信息 + @result 是否移除成功 + */ +- (BOOL)removeBuddy:(NSString *)username + removeFromRemote:(BOOL)removeFromRemote + error:(EMError **)pError; + +#pragma mark - accept buddy request + +/*! + @method + @brief 接受某个好友发送的好友请求 + @discussion + @param username 需要接受的好友username + @param pError 错误信息 + @result 是否接受成功 + */ +- (BOOL)acceptBuddyRequest:(NSString *)username + error:(EMError **)pError; + +#pragma mark - reject buddy request + +/*! + @method + @brief 拒绝某个好友发送的好友请求 + @discussion + @param username 需要拒绝的好友username + @param pError 错误信息 + @result 是否拒绝成功 + */ +- (BOOL)rejectBuddyRequest:(NSString *)username + reason:(NSString *)reason + error:(EMError **)pError; + +#pragma mark - fetch block + +/*! + @method + @brief 获取黑名单(同步方法) + @discussion + @param pError 错误信息 + @result 黑名单(username) + */ +- (NSArray *)fetchBlockedList:(EMError **)pError; + +/*! + @method + @brief 获取黑名单(异步方法) + @discussion + 函数执行完, 回调[didUpdateBlockedList:]会被触发 + */ +- (void)asyncFetchBlockedList; + +/*! + @method + @brief 获取黑名单(异步方法) + @param completion 创建完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 获取黑名单成功 判断条件:completion中,error == nil + 函数执行完, 会调用参数completion + */ +- (void)asyncFetchBlockedListWithCompletion:(void (^)(NSArray *blockedList, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - block buddy + +/*! + @method + @brief 将username的用户加到黑名单(该用户不会被从好友中删除,若想删除,请自行调用删除接口) + @discussion + @param username 加入黑名单的用户username + @param relationship 黑名单关系(both:双向都不接受消息; + from:能给黑名单中的人发消息,接收不到黑名单中的人发的消息; + to:暂不支持) + @result 是否成功的向服务器发送了block信息(不包含 服务器是否成功将用户加入黑名单) + */ +- (EMError *)blockBuddy:(NSString *)username + relationship:(EMRelationship)relationship; + +/*! + @method + @brief 异步方法,将username的用户加到黑名单(该用户不会被从好友中删除,若想删除,请自行调用删除接口) + @param username 加入黑名单的用户username + @param relationship 黑名单关系(both:双向都不接受消息; + from:能给黑名单中的人发消息,接收不到黑名单中的人发的消息; + to:暂不支持) + @discussion + 函数执行完, 回调[didBlockBuddy:error:]会被触发 + */ +- (void)asyncBlockBuddy:(NSString *)username + relationship:(EMRelationship)relationship; + +/*! + @method + @brief 异步方法,将username的用户加到黑名单(该用户不会被从好友中删除,若想删除,请自行调用删除接口) + @param username 加入黑名单的用户username + @param relationship 黑名单关系(both:双向都不接受消息; + from:能给黑名单中的人发消息,接收不到黑名单中的人发的消息; + to:暂不支持) + @param completion 完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 加黑名单成功 判断条件:completion中,error == nil 函数执行完, 会调用参数completion + */ +- (void)asyncBlockBuddy:(NSString *)username + relationship:(EMRelationship)relationship + withCompletion:(void (^)(NSString *username, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - unblock buddy + +/*! + @method + @brief 将username的用户移出黑名单 + @discussion + @param username 移出黑名单的用户username + @result 是否成功的向服务器发送了unblock信息(不包含 服务器是否成功将用户移出黑名单) + */ +- (EMError *)unblockBuddy:(NSString *)username; + +/*! + @method + @brief 异步方法,将username的用户移出黑名单 + @param username 加入黑名单的用户username + @discussion + 函数执行完, 回调[didUnblockBuddy:error:]会被触发 + */ +- (void)asyncUnblockBuddy:(NSString *)username; + +/*! + @method + @brief 异步方法,将username的用户移出黑名单 + @param username 加入黑名单的用户username + @param completion 完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 移出黑名单成功 判断条件:completion中,error == nil 函数执行完, 会调用参数completion + */ +- (void)asyncUnblockBuddy:(NSString *)username + withCompletion:(void (^)(NSString *username, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @property + @brief 群组分组列表 + */ +@property (nonatomic, strong, readonly) NSArray *buddyGroupList EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @method + @brief 申请添加某个用户为好友 + @discussion + @param username 需要添加为好友的username + @param nickname 添加好友后的昵称 + @param message 申请添加好友时的附带信息 + @param pError 错误信息 + @result 好友申请是否发送成功 + */ +- (BOOL)addBuddy:(NSString *)username + withNickname:(NSString *)nickname + message:(NSString *)message + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_6, 2_0_7, "Use- addBuddy:message:error:"); + +/*! + @method + @brief 申请添加某个用户为好友,同时将该好友添加到分组中,好友与分组可以多对多 + @discussion + @param username 需要添加为好友的username + @param nickname 添加好友后的昵称 + @param message 申请添加好友时的附带信息 + @param groupNames 将好友添加到分组中(groupNames由NSString对象组成) + @param pError 错误信息 + @result 好友申请是否发送成功 + */ +- (BOOL)addBuddy:(NSString *)username + withNickname:(NSString *)nickname + message:(NSString *)message + toGroups:(NSArray *)groupNames + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_6, 2_0_7, "Use- addBuddy:message:toGroups:error:"); + +/*! + @method + @brief 获取黑名单(异步方法) + @param completion 创建完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 获取黑名单成功 判断条件:completion中,error == nil + 函数执行完, 会调用参数completion + */ + +- (void)asyncFetchBlockListWithCompletion:(void (^)(NSArray *blockedList, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_6, 2_0_7, "Use -asyncFetchBlockedListWithCompletion:onQueue:"); + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerChat.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerChat.h new file mode 100644 index 0000000..39359c3 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerChat.h @@ -0,0 +1,342 @@ +/*! + @header IChatManagerChat.h + @abstract 为ChatManager提供基础消息操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IChatManagerBase.h" +#import "EMChatManagerDefs.h" + +@class EMMessage; +@class EMError; +@protocol IEMChatProgressDelegate; + +/*! + @protocol + @brief 用户聊天协议, 用于发送, 转发信息 + @discussion 所有不带Block回调的异步方法, 需要监听回调时, 需要先将要接受回调的对象注册到delegate中, 示例代码如下: + [[[EaseMob sharedInstance] chatManager] addDelegate:self delegateQueue:dispatch_get_main_queue()] + */ +@protocol IChatManagerChat + +@required +#pragma mark - send message + +/*! + @method + @brief 发送一条消息 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改 + @param message 消息对象(包括from, to, body列表等信息) + @param progress 发送多媒体信息时的progress回调对象 + @param pError 错误信息 + @result 发送完成后的消息对象 + */ +- (EMMessage *)sendMessage:(EMMessage *)message + progress:(id)progress + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 发送一条消息 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. 在发送过程中, willSendMessage:error:和didSendMessage:error:这两个回调会被触发 + @param message 消息对象(包括from, to, body列表等信息) + @param progress 发送多媒体信息时的progress回调对象 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncSendMessage:(EMMessage *)message + progress:(id)progress; + +/*! + @method + @brief 异步方法, 发送一条消息 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改 + @param message 消息对象(包括from, to, body列表等信息) + @param progress 发送多媒体信息时的progress回调对象 + @param prepare 将要发送消息前的回调block + @param aPrepareQueue 回调block时的线程 + @param completion 发送消息完成后的回调 + @param aCompletionQueue 回调block时的线程 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncSendMessage:(EMMessage *)message + progress:(id)progress + prepare:(void (^)(EMMessage *message, + EMError *error))prepare + onQueue:(dispatch_queue_t)aPrepareQueue + completion:(void (^)(EMMessage *message, + EMError *error))completion + onQueue:(dispatch_queue_t)aCompletionQueue; + +#pragma mark - message ack + +/*! + @method + @brief 发送一个"已读消息"(在UI上显示了或者阅后即焚的销毁的时候发送)的回执到服务器 + @discussion + @param message 从服务器收到的消息 + @result + */ +- (void)sendReadAckForMessage:(EMMessage *)message; + +#pragma mark - resend message + +/*! + @method + @brief 重新发送某一条消息 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改 + @param message 消息对象(包括from, to, body列表等信息) + @param progress 发送多媒体信息时的progress回调对象 + @param pError 错误信息 + @result + */ +- (EMMessage *)resendMessage:(EMMessage *)message + progress:(id)progress + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 重新发送某一条消息 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. 在发送过程中, EMChatManagerChatDelegate中的willSendMessage:error:和didSendMessage:error:这两个回调会被触发 + @param message 消息对象(包括from, to, body列表等信息) + @param progress 发送多媒体信息时的progress回调对象 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncResendMessage:(EMMessage *)message + progress:(id)progress; + +/*! + @method + @brief 异步方法, 重新发送某一条消息 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改 + @param message 消息对象(包括from, to, body列表等信息) + @param progress 发送多媒体信息时的progress回调对象 + @param prepare 将要发送消息前的回调block + @param aPrepareQueue 回调block时的线程 + @param completion 发送消息完成后的回调 + @param aCompletionQueue 回调block时的线程 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncResendMessage:(EMMessage *)message + progress:(id)progress + prepare:(void (^)(EMMessage *message, + EMError *error))prepare + onQueue:(dispatch_queue_t)aPrepareQueue + completion:(void (^)(EMMessage *message, + EMError *error))completion + onQueue:(dispatch_queue_t)aCompletionQueue; + +#pragma mark - forward message + +/*! + @method + @brief 将某一条消息转发给另一个聊天用户 + @discussion + @param message 需要转发的消息对象 + @param ext 转发时需要修改的ext(原有需要转发的message的ext不会进行转发) + @param username 需要转发给聊天对象的username + @param isGroup 是否是转发到一个群组 + @param progress 发送多媒体信息时的progress回调对象 + @param pError 错误信息 + @result 发送的消息对象 + */ +- (EMMessage *)forwardMessage:(EMMessage *)message + ext:(NSDictionary *)ext + to:(NSString *)username + isGroup:(BOOL)isGroup + progress:(id)progress + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 将某一条消息转发给另一个聊天用户 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. 在发送过程中, EMChatManagerChatDelegate中的willSendMessage:error:和didSendMessage:error:这两个回调会被触发 + @param message 需要转发的消息对象 + @param ext 转发时需要修改的ext(原有需要转发的message的ext不会进行转发) + @param username 需要转发给聊天对象的username + @param isGroup 是否是转发到一个群组 + @param progress 发送多媒体信息时的progress回调对象 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncForwardMessage:(EMMessage *)message + ext:(NSDictionary *)ext + to:(NSString *)username + isGroup:(BOOL)isGroup + progress:(id)progress; + +/*! + @method + @brief 异步方法, 将某一条消息转发给另一个聊天用户 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. + @param message 需要转发的消息对象 + @param ext 转发时需要修改的ext(原有需要转发的message的ext不会进行转发) + @param username 需要转发给聊天对象的username + @param isGroup 是否是转发到一个群组 + @param progress 发送多媒体信息时的progress回调对象 + @param prepare 将要发送消息前的回调block + @param aPrepareQueue 回调block时的线程 + @param completion 发送消息完成后的回调 + @param aCompletionQueue 回调block时的线程 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncForwardMessage:(EMMessage *)message + ext:(NSDictionary *)ext + to:(NSString *)username + isGroup:(BOOL)isGroup + progress:(id)progress + prepare:(void (^)(EMMessage *message, + EMError *error))prepare + onQueue:(dispatch_queue_t)aPrepareQueue + completion:(void (^)(EMMessage *message, + EMError *error))completion + onQueue:(dispatch_queue_t)aCompletionQueue; + +#pragma mark - Backup + +- (void)asyncBackupMessagesWithProgress:(id)progress + statusCompletion:(void (^)(EMBackupMessagesStatus status, EMError *error))statusCompletion; + +- (void)cancelBackupMessages; + +#pragma mark - Restore + +- (void)asyncRestoreBackupsWithProgress:(id)progress + statusCompletion:(void (^)(EMRestoreBackupStatus status, EMError *error))statusCompletion; +- (void)cancelRestoreBackups; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @method + @brief 发送一个"已读消息"(在UI上显示了或者阅后即焚的销毁的时候发送)的回执到服务器 + @discussion + @param message 从服务器收到的消息 + @result + */ +- (void)sendHasReadResponseForMessage:(EMMessage *)message EM_DEPRECATED_IOS(2_0_0, 2_1_6, "Use - sendReadAckForMessage:"); + +/*! + @method + @brief 将某一条消息转发给另一个聊天用户 + @discussion + @param message 需要转发的消息对象 + @param username 需要转发给聊天对象的username + @param isGroup 是否是转发到一个群组 + @param progress 发送多媒体信息时的progress回调对象 + @param pError 错误信息 + @result 发送的消息对象 + */ +- (EMMessage *)forwardMessage:(EMMessage *)message + to:(NSString *)username + isGroup:(BOOL)isGroup + progress:(id)progress + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_0, 2_0_9, "请使用带 ext 的方法"); + +/*! + @method + @brief 异步方法, 将某一条消息转发给另一个聊天用户 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. 在发送过程中, EMChatManagerChatDelegate中的willSendMessage:error:和didSendMessage:error:这两个回调会被触发 + @param message 需要转发的消息对象 + @param username 需要转发给聊天对象的username + @param isGroup 是否是转发到一个群组 + @param progress 发送多媒体信息时的progress回调对象 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncForwardMessage:(EMMessage *)message + to:(NSString *)username + isGroup:(BOOL)isGroup + progress:(id)progress EM_DEPRECATED_IOS(2_0_0, 2_0_9, "请使用带 ext 的方法"); + +/*! + @method + @brief 异步方法, 将某一条消息转发给另一个聊天用户 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. + @param message 需要转发的消息对象 + @param username 需要转发给聊天对象的username + @param isGroup 是否是转发到一个群组 + @param progress 发送多媒体信息时的progress回调对象 + @param prepare 将要发送消息前的回调block + @param aPrepareQueue 回调block时的线程 + @param completion 发送消息完成后的回调 + @param aCompletionQueue 回调block时的线程 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncForwardMessage:(EMMessage *)message + to:(NSString *)username + isGroup:(BOOL)isGroup + progress:(id)progress + prepare:(void (^)(EMMessage *message, + EMError *error))prepare + onQueue:(dispatch_queue_t)aPrepareQueue + completion:(void (^)(EMMessage *message, + EMError *error))completion + onQueue:(dispatch_queue_t)aCompletionQueue EM_DEPRECATED_IOS(2_0_0, 2_0_9, "请使用带 ext 的方法"); + +/*! + @method + @brief 将某一条消息转发给另一个聊天用户 + @discussion + @param message 需要转发的消息对象 + @param ext 转发时需要修改的ext(原有需要转发的message的ext不会进行转发) + @param username 需要转发给聊天对象的username + @param type 转发对象的类型 + @param progress 发送多媒体信息时的progress回调对象 + @param pError 错误信息 + @result 发送的消息对象 + */ +- (EMMessage *)forwardMessage:(EMMessage *)message + ext:(NSDictionary *)ext + to:(NSString *)username + messageType:(EMMessageType)type + progress:(id)progress + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 将某一条消息转发给另一个聊天用户 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. 在发送过程中, EMChatManagerChatDelegate中的willSendMessage:error:和didSendMessage:error:这两个回调会被触发 + @param message 需要转发的消息对象 + @param ext 转发时需要修改的ext(原有需要转发的message的ext不会进行转发) + @param username 需要转发给聊天对象的username + @param type 转发对象的类型 + @param progress 发送多媒体信息时的progress回调对象 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncForwardMessage:(EMMessage *)message + ext:(NSDictionary *)ext + to:(NSString *)username + messageType:(EMMessageType)type + progress:(id)progress; + +/*! + @method + @brief 异步方法, 将某一条消息转发给另一个聊天用户 + @discussion 待发送的消息对象和发送后的消息对象是同一个对象, 在发送过程中对象属性可能会被更改. + @param message 需要转发的消息对象 + @param ext 转发时需要修改的ext(原有需要转发的message的ext不会进行转发) + @param username 需要转发给聊天对象的username + @param type 转发对象的类型 + @param progress 发送多媒体信息时的progress回调对象 + @param prepare 将要发送消息前的回调block + @param aPrepareQueue 回调block时的线程 + @param completion 发送消息完成后的回调 + @param aCompletionQueue 回调block时的线程 + @result 发送的消息对象(因为是异步方法, 不能作为发送完成或发送成功失败与否的判断) + */ +- (EMMessage *)asyncForwardMessage:(EMMessage *)message + ext:(NSDictionary *)ext + to:(NSString *)username + messageType:(EMMessageType)type + progress:(id)progress + prepare:(void (^)(EMMessage *message, + EMError *error))prepare + onQueue:(dispatch_queue_t)aPrepareQueue + completion:(void (^)(EMMessage *message, + EMError *error))completion + onQueue:(dispatch_queue_t)aCompletionQueue; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerChatroom.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerChatroom.h new file mode 100644 index 0000000..ba379cd --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerChatroom.h @@ -0,0 +1,141 @@ +/*! + @header IChatManagerChatroom.h + @abstract 聊天室操作接口 + @author EaseMob Inc. + @version 1.00 2015/04/09 Creation (1.00) + */ + +#import + +#import "IChatManagerBase.h" +#import "EMGroupManagerDefs.h" +#import "EMChatroom.h" + +@class EMCursorResult; + +@protocol IChatManagerChatroom + +@required + +#pragma mark - fetch all chatrooms + +/*! + @method + @brief 获取指定范围内的聊天室 + @param cursor 获取聊天室的cursor,首次调用传空即可 + @param pageSize 期望结果的数量, 如果 < 0 则一次返回所有结果 + @param pError 出错信息 + @return 获取的聊天室结果 + @discussion + 这是一个阻塞方法,用户应当在一个独立线程中执行此方法,用户可以连续调用此方法以获得所有聊天室 + */ +- (EMCursorResult *)fetchChatroomsFromServerWithCursor:(NSString *)cursor + pageSize:(NSInteger)pageSize + andError:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取指定范围的聊天室 + @param cursor 获取聊天室的cursor,首次调用传空即可 + @param pageSize 期望结果的数量, 如果 < 0 则一次返回所有结果 + @param completion 完成回调,回调会在主线程调用 + */ +- (void)asyncFetchChatroomsFromServerWithCursor:(NSString *)cursor + pageSize:(NSInteger)pageSize + andCompletion:(void (^)(EMCursorResult *result, EMError *error))completion; + +#pragma mark - fetch chatroom info + +/*! + @method + @brief 同步方法, 获取聊天室信息 + @param chatroomId 聊天室ID + @param pError 错误信息 + @return 聊天室 + */ +- (EMChatroom *)fetchChatroomInfo:(NSString *)chatroomId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取聊天室信息 + @param chatroomId 群组ID + @param completion 完成后的回调, 回调会在主线程调用 + */ +- (void)asyncFetchChatroomInfo:(NSString *)chatroomId + completion:(void (^)(EMChatroom *chatroom, EMError *error))completion; + +#pragma mark - fetch chatroom occupants + +/*! + @method + @brief 同步方法, 获取聊天室成员 + @param chatroomId 聊天室ID + @param cursor 获取成员的cursor,首次调用传空即可 + @param pageSize 期望结果的数量 + @param pError 错误信息 + @return 获取的成员结果 + */ +- (EMCursorResult *)fetchOccupantsForChatroom:(NSString *)chatroomId + cursor:(NSString *)cursor + pageSize:(NSInteger)pageSize + andError:(EMError **)pError; + +/*! + @method + @brief 同步方法, 获取聊天室成员列表 + @param chatroomId 聊天室ID + @param cursor 获取成员的cursor,首次调用传空即可 + @param pageSize 期望结果的数量 + @param completion 完成后的回调 + */ +- (void)asyncFetchOccupantsForChatroom:(NSString *)chatroomId + cursor:(NSString *)cursor + pageSize:(NSInteger)pageSize + completion:(void (^)(EMCursorResult *result, EMError *error))completion; + +#pragma mark - join/leave chatroom + +/*! + @method + @brief 加入一个聊天室 + @param chatroomId 聊天室的ID + @param pError 错误信息 + @result 所加入的聊天室 + @discussion + 这是一个阻塞方法,用户应当在一个独立线程中执行此方法 + */ +- (EMChatroom *)joinChatroom:(NSString *)chatroomId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 加入一个聊天室 + @param chatroomId 聊天室的ID + @param completion 加入聊天室完成后的回调, 回调会在主线程调用 + */ +- (void)asyncJoinChatroom:(NSString *)chatroomId + completion:(void (^)(EMChatroom *chatroom, EMError *error))completion; + +/*! + @method + @brief 退出聊天室 + @param chatroomId 聊天室ID + @param pError 错误信息 + @result 退出的聊天室, 失败返回nil + @discussion + 这是一个阻塞方法,用户应当在一个独立线程中执行此方法 + */ +- (EMChatroom *)leaveChatroom:(NSString *)chatroomId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 退出聊天室 + @param chatroomId 聊天室ID + @param completion 退出聊天室完成后的回调, 回调会在主线程调用 + */ +- (void)asyncLeaveChatroom:(NSString *)chatroomId + completion:(void (^)(EMChatroom *chatroom, EMError *error))completion; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerConversation.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerConversation.h new file mode 100644 index 0000000..be6b79d --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerConversation.h @@ -0,0 +1,346 @@ +/*! + @header IChatManagerConversation.h + @abstract 为ChatManager提供基础会话操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IChatManagerBase.h" +#import "EMChatManagerDefs.h" + +@class EMConversation; +@class EMMessage; + +/*! + @protocol + @brief 本协议主要用于聊天数据库的操作, 包括获取会话对象、保存会话对象、删除会话对象、获取会话未读记录的条数等 + @discussion + */ +@protocol IChatManagerConversation + +@optional + +#pragma mark - properties + +/*! + @property + @brief 当前登陆用户的会话对象列表 + */ +@property (nonatomic, readonly) NSArray *conversations; + +#pragma mark - database + +/*! + @method + @brief 获取某个用户的会话 + @discussion + 此方法获取会话的顺序如下: + 1. 查找内存会话列表中的会话; + 2. 如果没找到, 试图从数据库中查找此条会话; + 3. 如果仍没找到, 创建一个新的会话, 加到会话列表中, 并触发didUpdateConversationList:回调 + @param chatter 需要获取会话对象的用户名, 对于群组是群组ID,聊天室则是聊天室ID + @result 会话对象 + */ +- (EMConversation *)conversationForChatter:(NSString *)chatter + conversationType:(EMConversationType)type; + +/*! + @method + @brief 获取当前登录用户的会话列表 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @result 会话对象列表 + */ +- (NSArray *)loadAllConversationsFromDatabaseWithAppend2Chat:(BOOL)append2Chat; + +#pragma mark - save + +/*! + @method + @brief 保存单个会话对象到数据库 + @discussion 对数据库中取出的数据修改后, 需要调用该方法 + @param conversation 需要保存的会话对象 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @result 保存成功或失败 + */ +- (BOOL)insertConversationToDB:(EMConversation *)conversation + append2Chat:(BOOL)append2Chat; + +/*! + @method + @brief 保存多个会话对象到数据库 + @discussion + @param conversations 需要保存的会话对象列表 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @result 保存成功的会话对象个数 + */ +- (NSInteger)insertConversationsToDB:(NSArray *)conversations + append2Chat:(BOOL)append2Chat; + +#pragma mark - remove + +/*! + @method + @brief 删除某个会话对象 + @discussion + @param chatter 这个会话对象所对应的用户名 + @param aDeleteMessages 是否删除这个会话对象所关联的聊天记录 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @result 删除成功或失败 + */ +- (BOOL)removeConversationByChatter:(NSString *)chatter + deleteMessages:(BOOL)aDeleteMessages + append2Chat:(BOOL)append2Chat; + +/*! + @method + @brief 删除某几个会话对象 + @discussion + @param chatters 这几个要被删除的会话对象所对应的用户名列表 + @param aDeleteMessages 是否删除这个会话对象所关联的聊天记录 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @result 成功删除的会话对象的个数 + */ +- (NSUInteger)removeConversationsByChatters:(NSArray *)chatters + deleteMessages:(BOOL)aDeleteMessages + append2Chat:(BOOL)append2Chat; + +/*! + @method + @brief 删除所有会话对象 + @discussion + @param aDeleteMessages 是否删除这个会话对象所关联的聊天记录 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @result 是否成功执行 + */ +- (BOOL)removeAllConversationsWithDeleteMessages:(BOOL)aDeleteMessages + append2Chat:(BOOL)append2Chat; + +#pragma mark - message counter + +/*! + @method + @brief 从数据库获取所有未读消息数量 + @discussion + @result 未读消息数量 + */ +- (NSUInteger)loadTotalUnreadMessagesCountFromDatabase; + +/*! + @method + @brief 获取单个会话对象的未读消息数量 + @discussion + @param chatter 此会话对象所对应的用户名 + @result 此绘画对象的未读消息数量 + */ +- (NSUInteger)unreadMessagesCountForConversation:(NSString *)chatter; + +#pragma mark - search message + +/*! + * 从所有的聊天记录中搜索符合条件的记录 + * + * @param criteria 搜索条件 + * + * @return 搜索结果, 由EMMessage对象组成 + */ +- (NSArray *)searchMessagesWithCriteria:(NSString *)criteria; + +/*! + * 从单个chatter聊天记录中搜索符合条件的记录 + * + * @param criteria 搜索条件 + * @param chatter 聊天对象的用户名 + * + * @return 搜索结果, 由EMMessage对象组成 + */ +- (NSArray *)searchMessagesWithCriteria:(NSString *)criteria + withChatter:(NSString *)chatter; + +#pragma mark - save message + +/*! + @method + @brief 保存聊天消息到DB + @param message 待保存的聊天消息 + @return 是否成功保存聊天消息 + @discussion + 消息会直接保存到数据库中,并不会调用相关回调方法; + 若希望调用相关回调方法,请使用insertMessageToDB:append2Chat: + */ +- (BOOL)insertMessageToDB:(EMMessage *)message; + +/*! + @method + @brief 导入聊天消息 + @param message 待导入的聊天消息 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @return 是否成功导入聊天消息 + */ +- (BOOL)insertMessageToDB:(EMMessage *)message + append2Chat:(BOOL)append2Chat; + +/*! + @method + @brief 保存一组聊天消息 + @param messages 待保存的聊天消息列表 + @return 成功保存的聊天消息条数 + @discussion + 请调用者确保传入消息的有效性(conversationChatter和isRead等状态正确赋值); + 消息会直接保存到数据库中,并不会调用相关回调方法,请自行调用[loadAllConversationsFromDatabaseWithAppend2Chat:]更新会话列表 + */ +- (NSInteger)insertMessagesToDB:(NSArray *)messages; + +/*! + @method + @brief 保存一组聊天消息(推荐用法,速度有惊喜哦) + @param messages 待保存的聊天消息列表 + @param chatter 必填选项,message的conversationChatter + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @return 是否成功插入 + */ +- (BOOL)insertMessagesToDB:(NSArray *)messages + forChatter:(NSString *)chatter + append2Chat:(BOOL)append2Chat; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @method + @brief 获取某个用户的会话 + @discussion + 此方法获取会话的顺序如下: + 1. 查找内存会话列表中的会话; + 2. 如果没找到, 试图从数据库中查找此条会话; + 3. 如果仍没找到, 创建一个新的会话, 加到会话列表中, 并触发didUpdateConversationList:回调 + @param chatter 需要获取会话对象的用户名, 对于群组, 则是群组ID + @result 会话对象 + */ +- (EMConversation *)conversationForChatter:(NSString *)chatter + isGroup:(BOOL)isGroup EM_DEPRECATED_IOS(2_0_0, 2_1_6, "Use - conversationForChatter:conversationType"); + +/*! + @method + @brief 获取当前登录用户的会话列表 + @discussion + 直接从数据库中删除,并不会返回相关回调方法; + 若希望返回相关回调方法,请使用loadAllConversationsFromDatabaseWithAppend2Chat: + @result 会话对象列表 + */ +- (NSArray *)loadAllConversations EM_DEPRECATED_IOS(2_0_8, 2_1_1, "Use - loadAllConversationsFromDatabase"); +- (NSArray *)loadAllConversationsFromDatabase EM_DEPRECATED_IOS(2_1_0, 2_1_2, "Use - loadAllConversationsFromDatabaseWithAppend2Chat:"); + +/*! + @method + @brief 保存当前登录用户的会话列表到数据库 + @discussion + @result 成功保存的会话对象列表的项数 + */ +- (NSInteger)saveAllConversations EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Delete"); + +/*! + @method + @brief 删除某个会话对象 + @param chatter 这个会话对象所对应的用户名 + @param aDeleteMessages 是否删除这个会话对象所关联的聊天记录 + @discussion + 直接从数据库中删除,并不会返回相关回调方法; + 若希望返回相关回调方法,请使用removeConversationByChatters:deleteMessages:append2Chat: + @result 删除成功或失败 + */ +- (BOOL)removeConversationByChatter:(NSString *)chatter + deleteMessages:(BOOL)aDeleteMessages EM_DEPRECATED_IOS(2_1_0, 2_1_2, "Use - removeConversationByChatter:deleteMessages:append2Chat:"); + +/*! + @method + @brief 删除某几个会话对象 + @param chatters 这几个要被删除的会话对象所对应的用户名列表 + @param aDeleteMessages 是否删除这个会话对象所关联的聊天记录 + @discussion + 直接从数据库中删除,并不会返回相关回调方法; + 若希望返回相关回调方法,请使用removeConversationsByChatters:deleteMessages:append2Chat: + @result 成功删除的会话对象的个数 + */ +- (NSUInteger)removeConversationsByChatters:(NSArray *)chatters + deleteMessages:(BOOL)aDeleteMessages EM_DEPRECATED_IOS(2_1_0, 2_1_2, "Use - removeConversationsByChatters:deleteMessages:append2Chat:"); + +/*! + @method + @brief 删除所有会话对象 + @param aDeleteMessages 是否删除这个会话对象所关联的聊天记录 + @discussion + 会话会直接从数据库中删除,并不会返回相关回调方法; + 若希望返回相关回调方法,请使用removeAllConversationsWithDeleteMessages:append2Chat: + @result 是否成功执行 + */ +- (BOOL)removeAllConversationsWithDeleteMessages:(BOOL)aDeleteMessages EM_DEPRECATED_IOS(2_1_0, 2_1_2, "Use - removeAllConversationsWithDeleteMessages:append2Chat:"); + +/*! + @method + @brief 获取当前登录用户所有包含未读消息的会话对象的个数 + @discussion + @result 当前登录用户所有包含未读消息的会话对象的个数 + */ +- (NSUInteger)unreadConversationsCount EM_DEPRECATED_IOS(2_0_0, 2_0_8, "不再提供该属性"); + +/*! + @method + @brief 获取所有conversation的未读消息数量 + @discussion + @result 未读消息数量 + */ +- (NSUInteger)totalUnreadMessagesCount EM_DEPRECATED_IOS(2_1_0, 2_1_6, "Use - loadTotalUnreadMessagesCountFromDatabase"); + +/*! + @method + @brief 保存聊天消息到DB + @param message 待保存的聊天消息 + @return 是否成功保存聊天消息 + @discussion + 消息会直接保存到数据库中,并不会调用相关回调方法; + 若希望调用相关回调方法,请使用insertMessageToDB:append2Chat: + */ +- (BOOL)saveMessage:(EMMessage *)message EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Use - insertMessageToDB:"); + +/*! + @method + @brief 导入聊天消息 + @param message 待导入的聊天消息 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @return 是否成功导入聊天消息 + */ +- (BOOL)importMessage:(EMMessage *)message + append2Chat:(BOOL)append2Chat EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Use - insertMessageToDB:append2Chat:"); + +/*! + @method + @brief 保存一组聊天消息 + @param messages 待保存的聊天消息列表 + @return 成功保存的聊天消息条数 + @discussion + 请调用者确保传入消息的有效性(conversationChatter和isRead等状态正确赋值); + 消息会直接保存到数据库中,并不会调用相关回调方法,请自行调用[loadAllConversationsFromDatabaseWithAppend2Chat:]更新会话列表 + */ +- (NSInteger)saveMessages:(NSArray *)messages EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Use - insertMessagesToDB:"); + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerEncryption.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerEncryption.h new file mode 100644 index 0000000..4bea988 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerEncryption.h @@ -0,0 +1,29 @@ +/*! + @header IChatManagerEncryption.h + @abstract 为ChatManager提供基础的加解密操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IChatManagerBase.h" +#import "IEMChatCryptor.h" + +@class EMMessage; + +/*! + @protocol + @brief 本协议主要处理聊天数据的加密和解密操作 + @discussion + */ +@protocol IChatManagerEncryption + +@required + +/*! + @property + @brief 加解密器 + */ +@property (nonatomic, strong) id chatCryptor; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerGroup.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerGroup.h new file mode 100644 index 0000000..2baf0d6 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerGroup.h @@ -0,0 +1,1264 @@ +/*! + @header IChatManagerGroup.h + @abstract 为ChatManager提供群组的基础操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IChatManagerBase.h" +#import "EMGroupManagerDefs.h" + +@class EMGroup; +@class EMError; +@class EMGroupStyleSetting; +@class EMCursorResult; + +/*! + @protocol + @brief 本协议包括:创建, 销毁, 加入, 退出等群组操作 + @discussion 所有不带Block回调的异步方法, 需要监听回调时, 需要先将要接受回调的对象注册到delegate中, 示例代码如下: + [[[EaseMob sharedInstance] chatManager] addDelegate:self delegateQueue:dispatch_get_main_queue()] + */ +@protocol IChatManagerGroup + +@required + +#pragma mark - properties + +/*! + @property + @brief 所加入和创建的群组列表, 群组对象 + */ +@property (nonatomic, strong, readonly) NSArray *groupList; + +#pragma mark - load groups from database + +/*! + @method + @brief 从数据库获取与登陆者相关的群组 + @param append2Chat 是否加到内存中。 + YES为加到内存中。加到内存中之后, 会有相应的回调被触发从而更新UI; + NO为不加到内存中。如果不加到内存中, 则只会直接添加进DB, 不会有SDK的回调函数被触发从而去更新UI。 + @return 错误信息 + */ +- (NSArray *)loadAllMyGroupsFromDatabaseWithAppend2Chat:(BOOL)append2Chat; + +#pragma mark - create group, Founded in 2.0.3 version + +/*! + @method + @brief 创建群组(同步方法) + @param subject 群组名称 + @param description 群组描述 + @param invitees 默认群组成员(usernames,不需要包含创建者username) + @param welcomeMessage 群组欢迎语 + @param styleSetting 群组属性配置 + @param pError 建组的错误。成功为nil + @return 创建好的群组 + @discussion + 创建群组成功 判断条件:*pError == nil && returnGroup != nil + */ +- (EMGroup *)createGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + styleSetting:(EMGroupStyleSetting *)styleSetting + error:(EMError **)pError; + +/*! + @method + @brief 创建群组(异步方法)。 + @param subject 群组名称 + @param description 群组描述 + @param invitees 默认群组成员(usernames,不需要包含创建者username) + @param welcomeMessage 群组欢迎语 + @param styleSetting 群组属性配置 + @discussion + 函数执行完, 回调[group:didCreateWithError:]会被触发 + */ +- (void)asyncCreateGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + styleSetting:(EMGroupStyleSetting *)styleSetting; + +/*! + @method + @brief 创建群组(异步方法)。 + @param subject 群组名称 + @param description 群组描述 + @param invitees 默认群组成员(usernames,不需要包含创建者username) + @param welcomeMessage 群组欢迎语 + @param styleSetting 群组属性配置 + @param completion 创建完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 创建群组成功 判断条件:completion中,error == nil && group != nil + 函数执行完, 会调用参数completion + */ +- (void)asyncCreateGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + styleSetting:(EMGroupStyleSetting *)styleSetting + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + + +#pragma mark - create Anonymous group(匿名群组), Founded in 2.0.9 version + +/*! + @method + @brief 创建匿名群组(同步方法) + @param subject 群组名称 + @param description 群组描述 + @param welcomeMessage 群组欢迎语 + @param nickname 创建群组时群主的昵称(匿名聊天时的昵称) + @param styleSetting 群组属性配置(groupStyle 必须为 eGroupStyle_PublicAnonymous, 目前只可以设置 maxUsersCount) + @param pError 建组的错误。成功为nil + @return 创建好的群组 + @discussion + 创建群组成功 判断条件:*pError == nil && returnGroup != nil + */ +- (EMGroup *)createAnonymousGroupWithSubject:(NSString *)subject + description:(NSString *)description + initialWelcomeMessage:(NSString *)welcomeMessage + nickname:(NSString *)nickname + styleSetting:(EMGroupStyleSetting *)styleSetting + error:(EMError **)pError; + +/*! + @method + @brief 创建匿名群组(异步方法)。函数执行完, 回调[group:didCreateWithError:]会被触发 + @param subject 群组名称 + @param description 群组描述 + @param welcomeMessage 群组欢迎语 + @param nickname 创建群组时群主的昵称(匿名聊天时的昵称) + @param styleSetting 群组属性配置(groupStyle 必须为 eGroupStyle_PublicAnonymous, 目前只可以设置 maxUsersCount) + */ +- (void)asyncCreateAnonymousGroupWithSubject:(NSString *)subject + description:(NSString *)description + initialWelcomeMessage:(NSString *)welcomeMessage + nickname:(NSString *)nickname + styleSetting:(EMGroupStyleSetting *)styleSetting; + +/*! + @method + @brief 创建群组(异步方法)。函数执行完, 会调用参数completion + @param subject 群组名称 + @param description 群组描述 + @param welcomeMessage 群组欢迎语 + @param nickname 创建群组时群主的昵称(匿名聊天时的昵称) + @param styleSetting 群组属性配置(groupStyle 必须为 eGroupStyle_PublicAnonymous, 目前只可以设置 maxUsersCount) + @param completion 创建完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 创建群组成功 判断条件:completion中,error == nil && group != nil + */ +- (void)asyncCreateAnonymousGroupWithSubject:(NSString *)subject + description:(NSString *)description + initialWelcomeMessage:(NSString *)welcomeMessage + nickname:(NSString *)nickname + styleSetting:(EMGroupStyleSetting *)styleSetting + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - join Anonymous public group, Founded in 2.0.9 version + +/*! + @method + @brief 加入一个匿名公开群组 + @param groupId 公开群组的ID + @param nickname 匿名群组中的昵称 + @param pError 错误信息 + @result 所加入的公开群组 + */ +- (EMGroup *)joinAnonymousPublicGroup:(NSString *)groupId + nickname:(NSString *)nickname + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 加入一个匿名公开群组 + @param groupId 公开群组的ID + @param nickname 匿名群组中的昵称 + @discussion + 执行后, 回调didJoinPublicGroup:error:会被触发 + */ +- (void)asyncJoinAnonymousPublicGroup:(NSString *)groupId + nickname:(NSString *)nickname; + +/*! + @method + @brief 异步方法, 加入一个匿名公开群组 + @param groupId 公开群组的ID + @param nickname 匿名群组中的昵称 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncJoinAnonymousPublicGroup:(NSString *)groupId + nickname:(NSString *)nickname + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - leave group + +/*! + @method + @brief 退出群组 (需要非owner的权限) + @param groupId 群组ID + @param pError 错误信息 + @result 退出的群组对象, 失败返回nil + */ +- (EMGroup *)leaveGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 退出群组(需要非owner的权限) + @param groupId 群组ID + @discussion + 函数执行完, 回调group:didLeave:error:会被触发 + */ +- (void)asyncLeaveGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 退出群组(需要非owner的权限) + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncLeaveGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMGroupLeaveReason reason, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - destroy group + +/*! + @method + @brief 同步方法, 解散群组,需要owner权限 + @param groupId 群组ID + @param pError 错误信息 + @result 退出的群组对象, 失败返回nil + */ +- (EMGroup *)destroyGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 解散群组,需要owner权限 + @param groupId 群组ID + @discussion + 函数执行完, 回调group:didLeave:error:会被触发 + */ +- (void)asyncDestroyGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 解散群组,需要owner权限 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncDestroyGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMGroupLeaveReason reason, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - add occupants + +/*! + @method + @brief 邀请用户加入群组 + @param occupants 被邀请的用户名列表 + @param groupId 群组ID + @param welcomeMessage 欢迎信息 + @param pError 错误信息 + @result 返回群组对象, 失败返回空 + */ +- (EMGroup *)addOccupants:(NSArray *)occupants + toGroup:(NSString *)groupId + welcomeMessage:(NSString *)welcomeMessage + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 邀请用户加入群组 + @param occupants 被邀请的用户名列表 + @param groupId 群组ID + @param welcomeMessage 欢迎信息 + @discussion + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncAddOccupants:(NSArray *)occupants + toGroup:(NSString *)groupId + welcomeMessage:(NSString *)welcomeMessage; + +/*! + @method + @brief 异步方法, 邀请用户加入群组 + @param occupants 被邀请的用户名列表 + @param groupId 群组ID + @param welcomeMessage 欢迎信息 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncAddOccupants:(NSArray *)occupants + toGroup:(NSString *)groupId + welcomeMessage:(NSString *)welcomeMessage + completion:(void (^)(NSArray *occupants, + EMGroup *group, + NSString *welcomeMessage, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - remove occupants + +/*! + @method + @brief 将某些人请出群组 + @param occupants 要请出群组的人的用户名列表 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限 + */ +- (EMGroup *)removeOccupants:(NSArray *)occupants + fromGroup:(NSString *)groupId + error:(EMError *__autoreleasing *)pError; + +/*! + @method + @brief 异步方法, 将某些人请出群组 + @param occupants 要请出群组的人的用户名列表 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限. + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncRemoveOccupants:(NSArray *)occupants + fromGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 将某些人请出群组 + @param occupants 要请出群组的人的用户名列表 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限 + */ +- (void)asyncRemoveOccupants:(NSArray *)occupants + fromGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - block occupants + +/*! + @method + @brief 将某些人加入群组黑名单 + @param occupants 要加入黑名单的用户名列表 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限, 被加入黑名单的人, 不会再被允许进入群组 + */ +- (EMGroup *)blockOccupants:(NSArray *)occupants + fromGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 将某些人加入群组黑名单 + @param occupants 要加入黑名单的用户名列表 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限, 被加入黑名单的人, 不会再被允许进入群组 + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncBlockOccupants:(NSArray *)occupants + fromGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 将某些人加入群组黑名单 + @param occupants 要加入黑名单的用户名列表 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限, 被加入黑名单的人, 不会再被允许进入群组 + */ +- (void)asyncBlockOccupants:(NSArray *)occupants + fromGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - unblock occupants + +/*! + @method + @brief 将某些人从群组黑名单中解除 + @param occupants 要从黑名单中移除的用户名列表 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限, 从黑名单中移除后, 可以再次进入群组 + */ +- (EMGroup *)unblockOccupants:(NSArray *)occupants + forGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 将某些人从群组黑名单中解除 + @param occupants 要从黑名单中移除的用户名列表 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限, 从黑名单中移除后, 可以再次进入群组 + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncUnblockOccupants:(NSArray *)occupants + forGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 将某些人从群组黑名单中解除 + @param occupants 要从黑名单中移除的用户名列表 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限, 从黑名单中移除后, 可以再次进入群组 + */ +- (void)asyncUnblockOccupants:(NSArray *)occupants + forGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - change group subject + +/*! + @method + @brief 更改群组主题 + @param subject 主题 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限 + */ +- (EMGroup *)changeGroupSubject:(NSString *)subject + forGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 更改群组主题 + @param subject 主题 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限 + 函数执行完, groupDidUpdateInfo:error:回调会被触发 + */ +- (void)asyncChangeGroupSubject:(NSString *)subject + forGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 更改群组主题 + @param subject 主题 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限 + */ +- (void)asyncChangeGroupSubject:(NSString *)subject + forGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - change group description + +/*! + @method + @brief 更改群组说明信息 + @param newDescription 说明信息 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限 + */ +- (EMGroup *)changeDescription:(NSString *)newDescription + forGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 更改群组说明信息 + @param newDescription 说明信息 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限. + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncChangeDescription:(NSString *)newDescription + forGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 更改群组说明信息 + @param newDescription 说明信息 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限 + */ +- (void)asyncChangeDescription:(NSString *)newDescription + forGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - accept invitation + +/*! + @method + @brief 接受并加入群组 + @param groupId 所接受的群组ID + @param pError 错误信息 + @result 返回所加入的群组对象 + */ +- (EMGroup *)acceptInvitationFromGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 接受并加入群组 + @param groupId 所接受的群组ID + @discussion + 函数执行后, didAcceptInvitationFromGroup:error:回调会被触发 + */ +- (void)asyncAcceptInvitationFromGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 接受并加入群组 + @param groupId 所接受的群组ID + @param completion 消息完成后的回调 + @param aQueue 回调执行时的线程 + */ +- (void)asyncAcceptInvitationFromGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - reject invitation + +/*! + @method + @brief 拒绝一个加入群组的邀请 + @param groupId 被拒绝的群组ID + @param username 被拒绝的人 + @param reason 拒绝理由 + */ +- (void)rejectInvitationForGroup:(NSString *)groupId + toInviter:(NSString *)username + reason:(NSString *)reason; + + +#pragma mark - accept join group apply + +/*! + @method + @brief 同意加入群组的申请 + @param groupId 所申请的群组ID + @param groupname 申请的群组名称 + @param username 申请人的用户名 + @param pError 错误信息 + */ +- (void)acceptApplyJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + applicant:(NSString *)username + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 同意加入群组的申请 + @param groupId 所申请的群组ID + @param groupname 申请的群组名称 + @param username 申请人的用户名 + @discussion + 函数执行后, didAcceptApplyJoinGroup:username:error:回调会被触发 + */ +- (void)asyncAcceptApplyJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + applicant:(NSString *)username; + +/*! + @method + @brief 异步方法, 同意加入群组的申请 + @param groupId 所申请的群组ID + @param groupname 申请的群组名称 + @param username 申请人的用户名 + @param completion 消息完成后的回调 + @param aQueue 回调执行时的线程 + */ +- (void)asyncAcceptApplyJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + applicant:(NSString *)username + completion:(void (^)(EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - reject join group apply + +/*! + @method + @brief 拒绝一个加入群组的申请 + @param groupId 被拒绝的群组ID + @param username 被拒绝的人 + @param reason 拒绝理由 + */ +- (void)rejectApplyJoinGroup:(NSString *)groupId + groupname:(NSString *)groupname + toApplicant:(NSString *)username + reason:(NSString *)reason; + +#pragma mark - fetch group info + +/*! + @method + @brief 获取群组详细信息(id,密码,主题,描述,实际总人数,在线人数,成员列表,属性) + @param groupId 群组ID + @param pError 错误信息 + @result 所获取的群组对象 + */ +- (EMGroup *)fetchGroupInfo:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取群组详细信息(id,密码,主题,描述,实际总人数,在线人数,成员列表,属性) + @param groupId 群组ID + @discussion + 执行后, 回调didFetchGroupInfo:error会被触发 + */ +- (void)asyncFetchGroupInfo:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 获取群组详细信息(id,密码,主题,描述,实际总人数,在线人数,成员列表,属性) + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncFetchGroupInfo:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +/*! + @method + @brief 同步方法, 获取群组成员列表 + @param groupId 群组ID + @param pError 错误信息 + @return 群组的成员列表(包含创建者) + */ +- (NSArray *)fetchOccupantList:(NSString *)groupId error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取群组成员列表 + @param groupId 群组ID + @discussion + 执行完成后,回调[didFetchGroupOccupantsList:error:] + */ +- (void)asyncFetchOccupantList:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 获取群组成员列表 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncFetchOccupantList:(NSString *)groupId + completion:(void (^)(NSArray *occupantsList,EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +/*! + @method + @brief 同步方法, 获取群组信息 + @param groupId 群组ID + @param includesOccupantList 是否获取成员列表 + @param pError 错误信息 + @return 群组 + */ +- (EMGroup *)fetchGroupInfo:(NSString *)groupId + includesOccupantList:(BOOL)includesOccupantList + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取群组成员列表 + @param groupId 群组ID + @param includesOccupantList 是否获取成员列表 + @discussion + 执行完成后,回调[didFetchGroupInfo:error:] + */ +- (void)asyncFetchGroupInfo:(NSString *)groupId + includesOccupantList:(BOOL)includesOccupantList; + +/*! + @method + @brief 异步方法, 获取群组成员列表 + @param groupId 群组ID + @param includesOccupantList 是否获取成员列表 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncFetchGroupInfo:(NSString *)groupId + includesOccupantList:(BOOL)includesOccupantList + completion:(void (^)(EMGroup *group,EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - fetch group bans +/*! + @method + @brief 同步方法, 获取群组黑名单列表 + @param groupId 群组ID + @return 群组黑名单列表 + @discussion + 需要owner权限 + */ +- (NSArray *)fetchGroupBansList:(NSString *)groupId error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取群组黑名单列表 + @param groupId 群组ID + @discussion + 需要owner权限 + 执行完成后,回调[didFetchGroupBans:list:error:] + */ +- (void)asyncFetchGroupBansList:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 获取群组黑名单列表 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 需要owner权限 + */ +- (void)asyncFetchGroupBansList:(NSString *)groupId + completion:(void (^)(NSArray *groupBans,EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - fetch my groups, Founded in 2.0.3 version + +/** + @brief 获取与我相关的群组列表(自己创建的,加入的)(同步方法) + @param pError 获取错误信息 + @return 群组列表 + @discussion + 获取列表成功 判断条件:*pError == nil && returnArray != nil + */ +- (NSArray *)fetchMyGroupsListWithError:(EMError **)pError; + +/*! + @method + @brief 获取与我相关的群组列表(自己创建的,加入的)(异步方法) + @discussion + 执行后, 回调[didUpdateGroupList:error]会被触发 + */ +- (void)asyncFetchMyGroupsList; + +/*! + @method + @brief 获取与我相关的群组列表(自己创建的,加入的)(异步方法) + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 获取列表成功 判断条件:completion中,error == nil && groups != nil + */ +- (void)asyncFetchMyGroupsListWithCompletion:(void (^)(NSArray *groups, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - fetch all public groups + +/*! + @method + @brief 获取所有公开群组 + @param pError 错误信息 + @return 获取的所有群组列表 + */ +- (NSArray *)fetchAllPublicGroupsWithError:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取所有公开群组 + @discussion + 执行后, 回调didFetchAllPublicGroups:error:会被触发 + */ +- (void)asyncFetchAllPublicGroups; + +/*! + @method + @brief 异步方法, 获取所有公开群组 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncFetchAllPublicGroupsWithCompletion:(void (^)(NSArray *groups, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +/*! + @method + @brief 获取指定范围内的公开群 + @param cursor 获取公开群的cursor,首次调用传空即可 + @param pageSize 期望结果的数量, 如果 < 0 则一次返回所有结果 + @param pError 出错信息 + @return 获取的公开群结果 + @discussion + 这是一个阻塞方法,用户应当在一个独立线程中执行此方法,用户可以连续调用此方法以获得所有的公开群 + */ +- (EMCursorResult *)fetchPublicGroupsFromServerWithCursor:(NSString *)cursor + pageSize:(NSInteger)pageSize + andError:(EMError **)pError; + +/*! + @method + @brief 异步方法, 获取指定范围的公开群 + @param cursor 获取公开群的cursor,首次调用传空即可 + @param pageSize 期望结果的数量, 如果 < 0 则一次返回所有结果 + @param completion 完成回调,回调会在主线程调用 + */ +- (void)asyncFetchPublicGroupsFromServerWithCursor:(NSString *)cursor + pageSize:(NSInteger)pageSize + andCompletion:(void (^)(EMCursorResult *result, EMError *error))completion; + +#pragma mark - join public group + +/*! + @method + @brief 加入一个公开群组 + @param groupId 公开群组的ID + @param pError 错误信息 + @result 所加入的公开群组 + @discussion + 成功标志:*pError == nil; + */ +- (EMGroup *)joinPublicGroup:(NSString *)groupId error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 加入一个公开群组 + @param groupId 公开群组的ID + @discussion + 执行后, 回调didJoinPublicGroup:error:会被触发 + 成功标志:error == nil; + */ +- (void)asyncJoinPublicGroup:(NSString *)groupId; + +/*! + @method + @brief 异步方法, 加入一个公开群组 + @param groupId 公开群组的ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 成功标志:error == nil; + */ +- (void)asyncJoinPublicGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - Apply to join public group, Founded in 2.0.3 version + +/*! + @method + @brief 同步方法, 申请加入一个需授权的公开群组 + @param groupId 公开群组的ID + @param groupName 请求加入的群组名称 + @param message 请求加入的信息 + @param pError 错误信息 + @result 所加入的公开群组 + */ +- (EMGroup *)applyJoinPublicGroup:(NSString *)groupId + withGroupname:(NSString *)groupName + message:(NSString *)message + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 申请加入一个需授权的公开群组 + @param groupId 公开群组的ID + @param groupName 请求加入的群组名称 + @param message 请求加入的信息 + @discussion + 执行后, 回调didApplyJoinPublicGroup:error:会被触发 + */ +- (void)asyncApplyJoinPublicGroup:(NSString *)groupId + withGroupname:(NSString *)groupName + message:(NSString *)message; + +/*! + @method + @brief 异步方法, 申请加入一个需授权的公开群组 + @param groupId 公开群组的ID + @param groupName 请求加入的群组名称 + @param message 请求加入的信息 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncApplyJoinPublicGroup:(NSString *)groupId + withGroupname:(NSString *)groupName + message:(NSString *)message + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - search public group, Founded in 2.0.3 version + +/*! + @method + @brief 根据groupId搜索公开群(同步方法) + @param groupId 群组id(完整id) + @param pError 搜索失败的错误 + @return 搜索到的群组 + @discussion + 搜索群组成功 判断条件:*pError == nil && returnGroup != nil + */ +- (EMGroup *)searchPublicGroupWithGroupId:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 根据groupId搜索公开群(异步方法) + @param groupId 公开群组的ID(完整id) + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 搜索群组成功 判断条件:completion中,error == nil && group != nil + */ +- (void)asyncSearchPublicGroupWithGroupId:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - block group + +/*! + @method + @brief 屏蔽群消息,服务器不发送消息(不能屏蔽自己创建的群,EMErrorInvalidUsername) + @param groupId 要屏蔽的群ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 被屏蔽的群,服务器不再发消息 + */ +- (EMGroup *)blockGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 屏蔽群消息,服务器不发送消息(不能屏蔽自己创建的群,EMErrorInvalidUsername) + @param groupId 要取消屏蔽的群ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 被屏蔽的群,服务器不再发消息 + */ +- (void)asyncBlockGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +/*! + @method + @brief 取消屏蔽群消息(不能操作自己创建的群,EMErrorInvalidUsername) + @param groupId 要取消屏蔽的群ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + */ +- (EMGroup *)unblockGroup:(NSString *)groupId + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 取消屏蔽群消息(不能操作自己创建的群,EMErrorInvalidUsername) + @param groupId 要取消屏蔽的群ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + */ +- (void)asyncUnblockGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @method + @brief 从数据库获取与登陆者相关的群组 + @return 错误信息 + @discussion + 直接从数据库中获取,并不会返回相关回调方法; + 若希望返回相关回调方法,请使用loadAllMyGroupsFromDatabaseWithAppend2Chat: + */ +- (NSArray *)loadAllMyGroupsFromDatabase EM_DEPRECATED_IOS(2_1_0, 2_1_2, "Use - loadAllMyGroupsFromDatabaseWithAppend2Chat:"); + +#pragma mark - create private group, will be abolished + +/*! + @method + @brief 创建一个私有群组 + @param subject 主题 + @param description 说明信息 + @param invitees 初始群组成员的用户名列表 + @param welcomeMessage 对初始群组成员的邀请信息 + @param pError 错误信息 + @result 创建的群组对象, 失败返回nil + */ +- (EMGroup *)createPrivateGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -createGroupWithSubject:description:invitees:initialWelcomeMessage:styleSetting:error:"); + +/*! + @method + @brief 异步方法, 创建一个私有群组 + @param subject 主题 + @param description 说明信息 + @param invitees 初始群组成员的用户名列表 + @param welcomeMessage 对初始群组成员的邀请信息 + @discussion + 函数执行完, 回调group:didCreateWithError:会被触发 + */ +- (void)asyncCreatePrivateGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -asyncCreateGroupWithSubject:description:invitees:initialWelcomeMessage:styleSetting:"); + +/*! + @method + @brief 异步方法, 创建一个私有群组 + @param subject 主题 + @param description 说明信息 + @param invitees 初始群组成员的用户名列表 + @param welcomeMessage 对初始群组成员的邀请信息 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncCreatePrivateGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -asyncCreateGroupWithSubject:description:invitees:initialWelcomeMessage:styleSetting:completion:onQueue:"); + +#pragma mark - create public group, will be abolished + +/*! + @method + @brief 创建一个公开群组 + @param subject 主题 + @param description 说明信息 + @param invitees 初始群组成员的用户名列表 + @param welcomeMessage 对初始群组成员的邀请信息 + @param pError 错误信息 + @result 创建的群组对象, 失败返回nil + */ +- (EMGroup *)createPublicGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -createGroupWithSubject:description:invitees:initialWelcomeMessage:styleSetting:error:"); + +/*! + @method + @brief 异步方法, 创建一个公开群组 + @param subject 主题 + @param description 说明信息 + @param invitees 初始群组成员的用户名列表 + @param welcomeMessage 对初始群组成员的邀请信息 + @discussion + 函数执行完, 回调group:didCreateWithError:会被触发 + */ +- (void)asyncCreatePublicGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -asyncCreateGroupWithSubject:description:invitees:initialWelcomeMessage:styleSetting:"); + +/*! + @method + @brief 异步方法, 创建一个公开群组 + @param subject 主题 + @param description 说明信息 + @param invitees 初始群组成员的用户名列表 + @param welcomeMessage 对初始群组成员的邀请信息 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncCreatePublicGroupWithSubject:(NSString *)subject + description:(NSString *)description + invitees:(NSArray *)invitees + initialWelcomeMessage:(NSString *)welcomeMessage + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -asyncCreateGroupWithSubject:description:invitees:initialWelcomeMessage:styleSetting:completion:onQueue:"); + +#pragma mark - change group password, will be abolished + +/*! + @method + @brief 更改群组密码 + @param newPassword 新密码 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限 + */ +- (EMGroup *)changePassword:(NSString *)newPassword + forGroup:(NSString *)groupId + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @method + @brief 异步方法, 更改群组密码 + @param newPassword 新密码 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限. + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncChangePassword:(NSString *)newPassword + forGroup:(NSString *)groupId EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @method + @brief 异步方法, 更改群组密码 + @param newPassword 新密码 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限 + */ +- (void)asyncChangePassword:(NSString *)newPassword + forGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +#pragma mark - change occupants' affiliation, will be abolished + +/*! + @method + @brief 更改成员的权限级别 + @param newAffiliation 新的级别 + @param occupants 被更改成员的用户名列表 + @param groupId 群组ID + @param pError 错误信息 + @result 返回群组对象 + @discussion + 此操作需要admin/owner权限 + */ +- (EMGroup *)changeAffiliation:(EMGroupMemberRole)newAffiliation + forOccupants:(NSArray *)occupants + inGroup:(NSString *)groupId + error:(EMError **)pError EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @method + @brief 异步方法, 更改成员的权限级别 + @param newAffiliation 新的级别 + @param occupants 被更改成员的用户名列表 + @param groupId 群组ID + @discussion + 此操作需要admin/owner权限. + 函数执行完, 回调groupDidUpdateInfo:error:会被触发 + */ +- (void)asyncChangeAffiliation:(EMGroupMemberRole)newAffiliation + forOccupants:(NSArray *)occupants + inGroup:(NSString *)groupId EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @method + @brief 异步方法, 更改成员的权限级别 + @param newAffiliation 新的级别 + @param occupants 被更改成员的用户名列表 + @param groupId 群组ID + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + @discussion + 此操作需要admin/owner权限 + */ +- (void)asyncChangeAffiliation:(EMGroupMemberRole)newAffiliation + forOccupants:(NSArray *)occupants + inGroup:(NSString *)groupId + completion:(void (^)(EMGroup *group, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +#pragma mark - fetch my groups, will be abolished + +/*! + @method + @brief 获取所有私有群组 + @param pError 错误信息 + @return 获取的所有私有群组列表 + */ +- (NSArray *)fetchAllPrivateGroupsWithError:(EMError **)pError EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -fetchMyGroupsListWithError:"); + +/*! + @method + @brief 异步方法, 获取所有私有群组 + @discussion + 执行后, 回调didUpdateGroupList:error会被触发 + */ +- (void)asyncFetchAllPrivateGroups EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -asyncMyGroupsList"); + +/*! + @method + @brief 异步方法, 获取所有私有群组 + @param completion 消息完成后的回调 + @param aQueue 回调block时的线程 + */ +- (void)asyncFetchAllPrivateGroupsWithCompletion:(void (^)(NSArray *groups, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -asyncMyGroupsListWithCompletion:onQueue:"); + + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerLogin.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerLogin.h new file mode 100644 index 0000000..216ffcd --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerLogin.h @@ -0,0 +1,207 @@ +/*! + @header IChatManagerLogin.h + @abstract 为ChatManager提供基础登陆操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IChatManagerBase.h" + +/*! + @protocol + @brief 本协议包括:登录、退出、修改密码等方法 + @discussion 所有不带Block回调的异步方法, 需要监听回调时, 需要先将要接受回调的对象注册到delegate中, 示例代码如下: + [[[EaseMob sharedInstance] chatManager] addDelegate:self delegateQueue:dispatch_get_main_queue()] + */ +@protocol IChatManagerLogin + +#pragma mark - properties + +/*! + @property + @brief 当前登录的用户信息 + */ +@property (nonatomic, strong, readonly) NSDictionary *loginInfo; + +/*! + @property + @brief 当前是否已有登录的用户 + */ +@property (nonatomic, readonly) BOOL isLoggedIn; + +/*! + @property + @brief 是否连上聊天服务器 + */ +@property (nonatomic, readonly) BOOL isConnected; + + +#pragma mark - database +/*! + @method + @brief 将数据库数据导入新的数据库,旧版sdk数据库采用CoreData,从2.1.0版本开始,换成Sqlite + @discussion 同步方法,登录成功之后调用 + @result 错误信息 + */ +- (EMError *)importDataToNewDatabase; + +/*! + @method + @brief 调用sdk登录接口,登陆成功之后,sdk内部会默认调用一次该函数 + 从数据库获取信息,包括自己相关的群组,被屏蔽的群组的id数组,会话,消息 + @discussion 登录成功之后调用 + @result 错误信息 + */ +- (EMError *)loadDataFromDatabase; + +#pragma mark - register + +/*! + @method + @brief 在聊天服务器上创建账号 + @discussion + @param username 用户名 + @param password 密码 + @param pError 错误信息 + @result 是否注册成功 + */ +- (BOOL)registerNewAccount:(NSString *)username + password:(NSString *)password + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 在聊天服务器上创建账号 + @discussion 在注册过程中, EMChatManagerLoginDelegate中的didRegisterNewAccount:password:error:回调会被触发 + @param username 用户名 + @param password 密码 + @result + */ +- (void)asyncRegisterNewAccount:(NSString *)username + password:(NSString *)password; + +/*! + @method + @brief 异步方法, 在聊天服务器上创建账号 + @discussion + @param username 用户名 + @param password 密码 + @param completion 回调 + @param aQueue 回调时的线程 + @result + */ +- (void)asyncRegisterNewAccount:(NSString *)username + password:(NSString *)password + withCompletion:(void (^)(NSString *username, + NSString *password, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - login + +/*! + @method + @brief 使用用户名密码登录聊天服务器 + @discussion 如果登陆失败, 返回nil + @param username 用户名 + @param password 密码 + @param pError 错误信息 + @result 登录后返回的用户信息 + */ +- (NSDictionary *)loginWithUsername:(NSString *)username + password:(NSString *)password + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 使用用户名密码登录聊天服务器 + @discussion 在登陆过程中, EMChatManagerLoginDelegate中的didLoginWithInfo:error:回调会被触发 + @param username 用户名 + @param password 密码 + @result + */ +- (void)asyncLoginWithUsername:(NSString *)username + password:(NSString *)password; + +/*! + @method + @brief 异步方法, 使用用户名密码登录聊天服务器 + @discussion + @param username 用户名 + @param password 密码 + @param completion 回调 + @param aQueue 回调时的线程 + @result + */ +- (void)asyncLoginWithUsername:(NSString *)username + password:(NSString *)password + completion:(void (^)(NSDictionary *loginInfo, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - logoff + +/*! + @method + @brief 注销当前登录用户 + @discussion 当接收到【didLoginFromOtherDevice】和【didRemovedFromServer】的回调时,调用此方法,isUnbind传NO + @param isUnbind 是否解除device token + @param pError 错误信息 + @result 返回注销信息 + */ +- (NSDictionary *)logoffWithUnbindDeviceToken:(BOOL)isUnbind + error:(EMError **)pError; + +/*! + @method + @brief 异步方法, 注销当前登录用户 + @discussion 当接收到【didLoginFromOtherDevice】和【didRemovedFromServer】的回调时,调用此方法,isUnbind传NO + @result 完成后【didLogoffWithError:】回调会被触发. + */ +- (void)asyncLogoffWithUnbindDeviceToken:(BOOL)isUnbind; + +/*! + @method + @brief 异步方法, 注销当前登录用户 + @discussion 当接收到【didLoginFromOtherDevice】和【didRemovedFromServer】的回调时,调用此方法,isUnbind传NO + @param completion 回调 + @param aQueue 回调时的线程 + @result + */ +- (void)asyncLogoffWithUnbindDeviceToken:(BOOL)isUnbind + completion:(void (^)(NSDictionary *info, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @method + @brief 注销当前登录用户 + @param pError 错误信息 + @result 返回注销信息 + */ +- (NSDictionary *)logoffWithError:(EMError **)pError EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Use - logoffWithUnbindDeviceToken:error:"); + +/*! + @method + @brief 异步方法, 注销当前登录用户 + @discussion 在注销过程中, EMChatManagerLoginDelegate中的didLogoffWithError:回调会被触发. + @result + */ +- (void)asyncLogoff EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Use - asyncLogoffWithUnbindDeviceToken:"); + +/*! + @method + @brief 异步方法, 注销当前登录用户 + @discussion + @param completion 回调 + @param aQueue 回调时的线程 + @result + */ +- (void)asyncLogoffWithCompletion:(void (^)(NSDictionary *info, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue EM_DEPRECATED_IOS(2_0_6, 2_1_1, "Use - asyncLogoffWithUnbindDeviceToken:completion:onQueue:"); + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerPushNotification.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerPushNotification.h new file mode 100644 index 0000000..6d8268d --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerPushNotification.h @@ -0,0 +1,121 @@ +/*! + @header IChatManagerPushNotification.h + @abstract 为推送通知提供基础操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IChatManagerBase.h" + +@class EMPushNotificationOptions; + +/*! + @protocol + @brief 本协议包括:消息推送自定义设置 + @discussion + */ +@protocol IChatManagerPushNotification + +@required +#pragma mark - push notification properties + +/*! + @property + @brief 消息推送设置 + */ +@property (nonatomic, strong, readonly) EMPushNotificationOptions *pushNotificationOptions; + +/*! + @property + @brief 已屏蔽接收推送消息的群ID列表 + */ +@property (nonatomic, strong, readonly) NSArray *ignoredGroupIds; + +/*! + @method + @brief 更新消息推送相关属性配置(同步方法) + @param options 属性 + @param pError 更新错误信息 + @result 最新的属性配置 + */ +- (EMPushNotificationOptions *)updatePushOptions:(EMPushNotificationOptions *)options + error:(EMError **)pError; + +/*! + @method + @brief 更新消息推送相关属性配置(异步方法) + @param options 属性 + @discussion + 方法执行完之后,调用[didUpdatePushOptions:error:]; + */ +- (void)asyncUpdatePushOptions:(EMPushNotificationOptions *)options; + +/*! + @method + @brief 更新消息推送相关属性配置(异步方法) + @param options 属性 + @param completion 回调 + @param aQueue 回调时的线程 + @result + */ +- (void)asyncUpdatePushOptions:(EMPushNotificationOptions *)options + completion:(void (^)(EMPushNotificationOptions *options, EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - ignore group push notification + +/*! + @method + @brief 屏蔽接收群的推送消息 + @param groupId 需要屏蔽/取消屏蔽 推送消息的群ID + @param ignore 屏蔽/取消屏蔽 + @param pError 错误信息 + @result 返回已屏蔽接收推送消息的群列表 + @discussion + 全局的屏蔽推送消息属性优先于此设置 + */ +- (NSArray *)ignoreGroupPushNotification:(NSString *)groupId + ignore:(BOOL)ignore + error:(EMError **)pError; + +/*! + @method + @brief 屏蔽接收群的推送消息, 异步方法 + @param groupId 需要屏蔽/取消屏蔽 推送消息的群ID + @param isIgnore 屏蔽/取消屏蔽 + @discussion + 全局的屏蔽推送消息属性优先于此设置; + 方法执行完之后,调用[didIgnoreGroupPushNotification:error:]. + */ +- (void)asyncIgnoreGroupPushNotification:(NSString *)groupId + isIgnore:(BOOL)isIgnore; + +/*! + @method + @brief 屏蔽接收群的推送消息, 异步方法 + @param groupId 需要屏蔽/取消屏蔽 推送消息的群ID + @param isIgnore 屏蔽/取消屏蔽 + @param completion 回调 + @param aQueue 回调时的线程 + @discussion + 全局的屏蔽推送消息属性优先于此设置; + */ +- (void)asyncIgnoreGroupPushNotification:(NSString *)groupId + isIgnore:(BOOL)isIgnore + completion:(void (^)(NSArray *ignoreGroupsList, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @property + @brief 已屏蔽接收推送消息的群ID列表 + */ +@property (nonatomic, strong, readonly) NSArray *ignoredGroupList EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use - ignoredGroupIds"); + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerSettingOptions.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerSettingOptions.h new file mode 100644 index 0000000..6a673dc --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerSettingOptions.h @@ -0,0 +1,153 @@ +/*! + @header IChatManagerSettingOptions.h + @abstract 为ChatManager提供昵称、是否自动登录等配置信息 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IChatManagerBase.h" + +/*! + @protocol + @brief 推送昵称、是否自动登录等配置信息 + */ +@protocol IChatManagerSettingOptions + +@optional + +/*! + @property + @brief 当前登陆用户的昵称, 默认为用户名。 + 因为环信只有用户ID, 并没有用户信息, 所以在后台发送推送的时候, 并不能知道用户昵称, 导致在推送过来的消息里, 用户名字为用户ID. 为解决此类问题, 环信多添加了一个可以由用户设置的推送昵称的属性,此方法是同步方法,会阻塞调用线程. + */ +@property (strong, nonatomic) NSString *apnsNickname; + +/*! + @property + @brief 是否已经开启自动登录 + @discussion + */ +@property (nonatomic) BOOL isAutoLoginEnabled; + +/*! + @property + @brief 开启自动登录功能 + @discussion + 设置后,当再次app启动时,会自动登录上次登录的账号,本设置需要在登录成功后设置才起作用。 + */ +- (void)enableAutoLogin; + +/*! + @property + @brief 关闭自动登录功能 + @discussion + */ +- (void)disableAutoLogin; + +/*! + @property + @brief 自动获取好友列表(包括好友黑名单,Default is NO) + @discussion + 设置为YES时, 登录成功后会自动调用 asyncFetchBuddyList 方法 + */ +@property (nonatomic) BOOL isAutoFetchBuddyList; + +/*! + @property + @brief 开启自动获取好友列表 + @discussion + 登录成功后会自动调用 asyncFetchBuddyList 方法 + */ +- (void)enableAutoFetchBuddyList; + +/*! + @property + @brief 关闭自动获取好友列表 + @discussion + */ +- (void)disableAutoFetchBuddyList; + +/*! + @property + @brief 是否使用ip,该接口的设置不会进行存储,需要开发者每次启动sdk之前都要设置一下 + @discussion + 2.1.4版本缺省关闭,2.1.5及以后版本缺省打开 + */ +@property (nonatomic) BOOL isUseIp; + +/*! + @property + @brief 使用ip,该接口的设置不会进行存储,需要开发者每次启动sdk之前都要设置一下 + @discussion + 2.1.4版本缺省关闭,2.1.5及以后版本缺省打开 + */ +- (void)enableUseIp; + +/*! + @property + @brief 关闭ip,该接口的设置不会进行存储,需要开发者每次启动sdk之前都要设置一下 + @discussion + 2.1.4版本缺省关闭,2.1.5及以后版本缺省打开 + */ +- (void)disableUseIp; + +/*! + @property + @brief 开启消息送达通知(默认是不开启的) + @discussion + */ +- (void)enableDeliveryNotification; + +/*! + @property + @brief 关闭消息送达通知 (默认是不开启的) + @discussion + */ +- (void)disableDeliveryNotification; + +/*! + @property + @brief 离开群时是否自动删除群会话(Default is YES),该接口的设置不会进行存储,需要开发者每次启动sdk之前都要设置一下 + @discussion + 设置为YES时, 当离开该群时会自动删除该群对应的会话 + */ +@property (nonatomic) BOOL isAutoDeleteConversationWhenLeaveGroup; + +/*! + @property + @brief 开启离开群组后自动删除对应会话 + @discussion + 当开启后, 当离开该群时会自动删除该群对应的会话 + */ +- (void)enableAutoDeleteConversatonWhenLeaveGroup; + +/*! + @property + @brief 关闭离开群组后自动删除对应会话 + @discussion + 当关闭后, 当离开该群时不会自动删除该群对应的会话 + */ +- (void)disableAutoDeleteConversatonWhenLeaveGroup; + +@optional + +#pragma mark - EM_DEPRECATED_IOS + +/*! + @property + @brief 当前登陆用户的昵称, 默认为用户名。 + 因为环信只有用户ID, 并没有用户信息, 所以在后台发送推送的时候, 并不能知道用户昵称, 导致在推送过来的消息里, 用户名字为用户ID. 为解决此类问题, 环信多添加了一个可以由用户设置的推送昵称的属性. + */ +@property (strong, nonatomic) NSString *nickname EM_DEPRECATED_IOS(2_0_6, 2_1_1, "apnsNickname"); + +/*! + @property + @brief 自动获取好友列表(包括好友黑名单,Default is NO), + @discussion + 设置为YES时, 登录成功后会自动调用 asyncFetchBuddyList 方法 + */ +@property (nonatomic) BOOL autoFetchBuddyList EM_DEPRECATED_IOS(2_0_9, 2_1_1, "isAutoFetchBuddyList"); + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerUtil.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerUtil.h new file mode 100644 index 0000000..d57f7ca --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/internal/IChatManagerUtil.h @@ -0,0 +1,103 @@ +/*! + @header IChatManagerUtil.h + @abstract 为ChatManager提供工具类 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + + +#import +#import "IChatManagerBase.h" + +@protocol IEMChatProgressDelegate; +@class EMError; +@class EMMessage; + +/*! + @protocol + @brief 本协议主要用于为ChatManager提供一些实用工具 + @discussion + */ +@protocol IChatManagerUtil + +@required + +#pragma mark - fetch message + +/*! + @method + @brief 获取聊天对象对应的远程服务器上的文件, 同步方法 + @discussion 如果此对象所在的消息对象是被加密的,下载下来的对象会被自动解密 + @param aMessage 聊天对象 + @param progress 进度条 + @param pError 错误信息 + */ +- (EMMessage *)fetchMessage:(EMMessage *)aMessage + progress:(id)progress + error:(EMError **)pError; + +/*! + @method + @brief 获取聊天对象对应的远程服务器上的文件, 异步方法 + @discussion 如果此对象所在的消息对象是被加密的,下载下来的对象会被自动解密.下载完成后,didFetchMessage:error:回调会被触发 + @param aMessage 聊天对象 + @param progress 进度条 + */ +- (void)asyncFetchMessage:(EMMessage *)aMessage + progress:(id)progress; + +/*! + @method + @brief 获取聊天对象对应的远程服务器上的文件, 异步方法 + @discussion 如果此对象所在的消息对象是被加密的,下载下来的对象会被自动解密 + @param aMessage 聊天对象 + @param progress 进度条 + @param completion 函数执行完成后的回调 + @param aQueue 回调函数所在的线程 + */ +- (void)asyncFetchMessage:(EMMessage *)aMessage + progress:(id)progress + completion:(void (^)(EMMessage *aMessage, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +#pragma mark - fetch message thumbnail + +/*! + @method + @brief 获取聊天对象的缩略图(当收到的消息有缩略图时, SDK会自动下载缩略图, 缩略图下载失败时, 可以使用此方法去重新获取) + @discussion 如果此对象所在的消息对象是被加密的,下载下来的对象会被自动解密 + @param aMessage 聊天对象 + @param progress 进度条 + @param pError 错误信息 + */ +- (EMMessage *)fetchMessageThumbnail:(EMMessage *)aMessage + progress:(id)progress + error:(EMError **)pError; + +/*! + @method + @brief 获取聊天对象的缩略图(当收到的消息有缩略图时, SDK会自动下载缩略图, 缩略图下载失败时, 可以使用此方法去重新获取), 异步方法 + @discussion 如果此对象所在的消息对象是被加密的,下载下来的对象会被自动解密.下载完成后, didFetchMessageThumbnail:error:回调会被触发 + @param aMessage 聊天对象 + @param progress 进度条 + */ +- (void)asyncFetchMessageThumbnail:(EMMessage *)aMessage + progress:(id)progress; + +/*! + @method + @brief 获取聊天对象的缩略图(当收到的消息有缩略图时, SDK会自动下载缩略图, 缩略图下载失败时, 可以使用此方法去重新获取), 异步方法 + @discussion 如果此对象所在的消息对象是被加密的,下载下来的对象会被自动解密 + @param aMessage 聊天对象 + @param progress 进度条 + @param completion 函数执行完成后的回调 + @param aQueue 回调函数所在的线程 + */ +- (void)asyncFetchMessageThumbnail:(EMMessage *)aMessage + progress:(id)progress + completion:(void (^)(EMMessage * aMessage, + EMError *error))completion + onQueue:(dispatch_queue_t)aQueue; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMBuddy.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMBuddy.h new file mode 100644 index 0000000..c790018 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMBuddy.h @@ -0,0 +1,58 @@ +/*! + @header EMBuddy.h + @abstract 好友的信息描述类 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ +#import + +/*! + @enum + @brief 好友关系 + @constant eEMBuddyFollowState_NotFollowed 双方不是好友 + @constant eEMBuddyFollowState_Followed 对方已接受好友请求 + @constant eEMBuddyFollowState_BeFollowed 登录用户已接受了该用户的好友请求 + @constant eEMBuddyFollowState_FollowedBoth 登录用户和小伙伴都互相在好友列表中 + */ +typedef NS_ENUM(NSInteger, EMBuddyFollowState) { + eEMBuddyFollowState_NotFollowed = 0, //双方不是好友 + eEMBuddyFollowState_Followed, //对方已接受好友请求. + eEMBuddyFollowState_BeFollowed, //登录用户已接受了该用户的好友请求 + eEMBuddyFollowState_FollowedBoth //"登录用户"和"小伙伴"都互相在好友列表中 +}; + +/*! + @class + @brief 好友的信息描述类 + */ +@interface EMBuddy : NSObject + +/*! + @method + @brief 通过username初始化一个EMBuddy对象 + @param username 好友的username + @discussion + @result EMBuddy实例对象 + */ ++ (instancetype)buddyWithUsername:(NSString *)username; + +/*! + @property + @brief 好友的username + */ +@property (copy, nonatomic, readonly)NSString *username; + +/*! + @property + @brief 好友状态 + */ +@property (nonatomic) EMBuddyFollowState followState; + +/*! + @property + @brief 是否等待对方接受好友请求() + @discussion A向B发送好友请求,会自动将B添加到A的好友列表中,但isPendingApproval为NO,表示等待B接受A的好友请求,如果在好友列表中,不需要显示isPendingApproval为NO的用户,屏蔽它即可 + */ +@property (nonatomic) BOOL isPendingApproval; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatCommand.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatCommand.h new file mode 100644 index 0000000..03f490f --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatCommand.h @@ -0,0 +1,42 @@ +/*! + @header EMChatCommand.h + @abstract 聊天的命令对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMChatObject.h" +#import "EMChatManagerDefs.h" + +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的命令对象类型 + */ +@interface EMChatCommand : NSObject + +/*! + @property + @brief 命令 + */ +@property (nonatomic, strong) NSString *cmd; + +/*! + @property + @brief 命令参数 + */ +@property (nonatomic, strong) NSArray *params EM_DEPRECATED_IOS(2_0_0, 2_0_9, @"不推荐使用, 请使用 EMMessage 的 ext 属性来携带额外的参数"); + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatFile.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatFile.h new file mode 100644 index 0000000..b9e88fb --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatFile.h @@ -0,0 +1,66 @@ +/*! + @header EMChatFile.h + @abstract 聊天的文件对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMChatFile.h" + +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的文件对象类型 + */ +@interface EMChatFile : NSObject + +/*! + @property + @brief 文件对象的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件对象本地磁盘位置的全路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件对象所对应的文件的大小, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +/*! + @method + @brief 以NSData构造文件对象 + @discussion + @param aData 文件内容 + @param aDisplayName 文件对象的显示名 + @result 文件对象 + */ +- (id)initWithData:(NSData *)aData displayName:(NSString *)aDisplayName; + +/*! + @method + @brief 以文件路径构造文件对象 + @discussion + @param filePath 磁盘文件全路径 + @param aDisplayName 文件对象的显示名 + @result 文件对象 + */ +- (id)initWithFile:(NSString *)filePath displayName:(NSString *)aDisplayName; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatImage.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatImage.h new file mode 100644 index 0000000..8306420 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatImage.h @@ -0,0 +1,92 @@ +/*! + @header EMChatImage.h + @abstract 聊天的图片对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import +#import "IEMChatFile.h" +#import "IChatImageOptions.h" + +@class UIImage; +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的图片对象类型 + */ +@interface EMChatImage : NSObject + +/*! + @property + @brief 文件对象的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件对象本地磁盘位置的全路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件对象所对应的文件的大小, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 图片对象尺寸 + */ +@property (nonatomic) CGSize size; + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +/*! + @property + @brief 对上传的图片压缩设置 + @discussion 目前只支持对图片的压缩比率的设置 + */ +@property (strong, nonatomic) id imageOptions; + +/*! + @method + @brief 以UIImage构造图片对象 + @discussion + @param aImage UIImage实例 + @param aDisplayName 图片对象的显示名 + @result 图片对象 + */ +- (id)initWithUIImage:(UIImage *)aImage displayName:(NSString *)aDisplayName; + +/*! + @method + @brief 以NSData构造图片对象 + @discussion + @param aData 图片内容 + @param aDisplayName 图片对象的显示名 + @result 图片对象 + */ +- (id)initWithData:(NSData *)aData displayName:(NSString *)aDisplayName; + +/*! + @method + @brief 以文件路径构造图片对象 + @discussion + @param filePath 磁盘文件全路径 + @param aDisplayName 图片对象的显示名 + @result 图片对象 + */ +- (id)initWithFile:(NSString *)filePath displayName:(NSString *)aDisplayName; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatLocation.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatLocation.h new file mode 100644 index 0000000..a760d5b --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatLocation.h @@ -0,0 +1,75 @@ +/*! + @header EMChatLocation.h + @abstract 聊天的位置对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMChatObject.h" + +@class CLLocation; +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的位置对象类型 + */ +@interface EMChatLocation : NSObject + +/*! + @property + @brief 纬度 + */ +@property (nonatomic) double latitude; + +/*! + @property + @brief 经度 + */ +@property (nonatomic) double longitude; + +/*! + @property + @brief 地址信息 + */ +@property (nonatomic, strong) NSString *address; + +/*! + @property + @brief CLLocation位置信息 + */ +@property (nonatomic, strong) CLLocation *location; + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +/*! + @method + @brief 以位置信息构造位置对象 + @discussion + @param latitude 纬度 + @param longitude 经度 + @param address 地址信息 + @result 位置对象 + */ +- (id)initWithLatitude:(double)latitude + longitude:(double)longitude + address:(NSString *)address; + +/*! + @method + @brief 以CLLocation构造位置对象 + @discussion + @param location CLLocation实例 + @result 位置对象 + */ +- (id)initWithCLLocation:(CLLocation *)location; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatText.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatText.h new file mode 100644 index 0000000..bced30f --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatText.h @@ -0,0 +1,43 @@ +/*! + @header EMChatText.h + @abstract 聊天的文本对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMChatObject.h" + +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的文本对象类型 + */ +@interface EMChatText : NSObject + +/*! + @property + @brief 文本对象的文本内容 + */ +@property (nonatomic, strong) NSString *text; + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +/*! + @method + @brief 以字符串构造文本对象 + @discussion + @param text 文本内容 + @result 文本对象 + */ +- (id)initWithText:(NSString *)text; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatVideo.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatVideo.h new file mode 100644 index 0000000..307bf0b --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatVideo.h @@ -0,0 +1,90 @@ +/*! + @header EMChatVideo.h + @abstract 聊天的视频对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMChatFile.h" + +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的视频对象类型 + */ +@interface EMChatVideo : NSObject + +/*! + @property + @brief 文件对象的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 是否需要生成缩略图, 默认为YES, SDK内部从DB中读取时, 为NO + */ +@property (nonatomic, assign) BOOL shouldGenerateThumbnail; + +/*! + @property + @brief 文件对象本地磁盘位置的全路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件第一帧图片的本地路径 + */ +@property (nonatomic, copy) NSString *thumbnailPath; + +/*! + @property + @brief 文件对象所对应的文件的大小, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 视频对象的时长, 秒为单位 + */ +@property (nonatomic) NSInteger duration; + +/*! + @property + @brief 视频对象的大小 + */ +@property (nonatomic) CGSize size; + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +/*! + @method + @brief 以NSData构造视频对象 + @discussion + @param aData 视频内容 + @param aDisplayName 视频对象的显示名 + @result 视频对象 + */ +- (id)initWithData:(NSData *)aData displayName:(NSString *)aDisplayName; + +/*! + @method + @brief 以文件路径构造视频对象 + @discussion + @param filePath 磁盘文件全路径 + @param aDisplayName 视频对象的显示名 + @result 视频对象 + */ +- (id)initWithFile:(NSString *)filePath displayName:(NSString *)aDisplayName; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatVoice.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatVoice.h new file mode 100644 index 0000000..551da92 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatVoice.h @@ -0,0 +1,72 @@ +/*! + @header EMChatVoice.h + @abstract 聊天的语音对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMChatFile.h" + +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天的语音对象类型 + */ +@interface EMChatVoice : NSObject + +/*! + @property + @brief 文件对象的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件对象本地磁盘位置的全路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件对象所对应的文件的大小, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 语音的时长, 单位是秒 + */ +@property (nonatomic) NSInteger duration; + +/*! + @property + @brief + 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +/*! + @method + @brief 以NSData构造语音对象 + @discussion + @param aData 语音内容 + @param aDisplayName 语音对象的显示名 + @result 语音对象 + */ +- (id)initWithData:(NSData *)aData displayName:(NSString *)aDisplayName; + +/*! + @method + @brief 以文件路径构造文件对象 + @discussion + @param filePath 磁盘文件全路径 + @param aDisplayName 文件对象的显示名 + @result 文件对象 + */ +- (id)initWithFile:(NSString *)filePath displayName:(NSString *)aDisplayName; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatroom.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatroom.h new file mode 100644 index 0000000..bfa799e --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMChatroom.h @@ -0,0 +1,36 @@ +/*! + @header EMChatroom.h + @abstract 聊天室对象类型 + @author EaseMob Inc. + @version 1.00 2015/04/08 Creation (1.00) + */ + +#import + +@interface EMChatroom : NSObject +/*! + @property + @brief 聊天室ID + */ +@property (nonatomic, strong, readonly) NSString *chatroomId; + +/*! + @property + @brief 聊天室的主题 + */ +@property (nonatomic, strong, readonly) NSString *chatroomSubject; + +/*! + @property + @brief 聊天室的描述 + */ +@property (nonatomic, strong, readonly) NSString *chatroomDescription; + +/*! + @property + @brief 聊天室的最大人数 + */ +@property (nonatomic, readonly) NSInteger chatroomMaxOccupantsCount; + ++ (instancetype)chatroomWithId:(NSString *)chatroomId; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMCommandMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMCommandMessageBody.h new file mode 100644 index 0000000..97f9e12 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMCommandMessageBody.h @@ -0,0 +1,63 @@ +/*! + @header EMCommandMessageBody.h + @abstract 聊天的命令消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMMessageBody.h" +#import "EMChatManagerDefs.h" + +@class EMChatCommand; + +/*! + @class + @abstract 聊天的命令消息体对象 + */ +@interface EMCommandMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + @discussion 实现IEMMessageBody接口 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + @discussion 实现IEMMessageBody接口 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 具体命令 + */ +@property (nonatomic, strong, readonly) NSString *action; + +/*! + @property + @brief 命令参数 + */ +@property (nonatomic, strong, readonly) NSArray *params; + +/*! + @property + @brief 消息体所在的消息对象 + @discussion 实现IEMMessageBody接口 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @method + @abstract 以命令对象创建文件消息体实例 + @discussion + @param aChatCommand 命令对象 + @result 命令消息体 + */ +- (id)initWithChatObject:(EMChatCommand *)aChatCommand; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMConversation.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMConversation.h new file mode 100644 index 0000000..38c9441 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMConversation.h @@ -0,0 +1,198 @@ +/*! + @header EMConversation.h + @abstract 聊天的会话对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMChatManagerDefs.h" + +@class EMMessage; + +/*! + @class + @brief 聊天的会话对象 + */ +@interface EMConversation : NSObject + +/*! + @property + @brief 会话对方的用户名. 如果是群聊, 则是群组的id + */ +@property (nonatomic, strong, readonly) NSString *chatter; + +/*! + @property + @brief 是否是群聊 + */ +@property (nonatomic, readonly) BOOL isGroup EM_DEPRECATED_IOS(2_0_0, 2_1_6, "Use - conversationType"); + +/*! + @property + @brief 是否接收关于此会话的未读消息变更通知 + */ +@property (nonatomic, readwrite) BOOL enableUnreadMessagesCountEvent; + +/*! + @property + @brief 会话扩展 + */ +@property (nonatomic, strong) NSDictionary *ext; + +/*! + @property + @brief 此会话中的消息列表 + */ +@property (nonatomic, strong, readonly) NSArray *messages EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Delete"); + +/*! + @property + @brief 是否接收关于此会话的消息 + */ +@property (nonatomic, readwrite) BOOL enableReceiveMessage EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Delete"); + +/*! + @property + @brief 会话类型 + */ +@property (nonatomic, readonly) EMConversationType conversationType; + +#pragma mark - message + +/*! + @method + @brief 删除会话对象和数据库中相关联的某一条消息 + @discussion 如果此消息不属于或不存在于此会话, 则不会进行删除 + @param aMessageId 将要删除的消息ID + @result 是否成功删除此消息 + */ +//- (BOOL)removeMessage:(NSString *)aMessageId EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Delete"); +- (BOOL)removeMessageWithId:(NSString *)aMessageId; + +/*! + @method + @brief 删除会话对象中的指定消息 + @discussion + @result 删除是否成功 + */ +- (BOOL)removeMessage:(EMMessage *)aMessage; + +/*! + @method + @brief 删除会话对象和数据库中相关联的某几条消息 + @discussion 如果消息不属于或不存在于此会话, 则不会进行删除相应的消息 + @param aMessageIds 将要删除的消息ID列表 + @result 成功删除的消息条数 + */ +- (NSUInteger)removeMessages:(NSArray *)aMessageIds EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use - removeMessagesWithIds:"); +- (NSUInteger)removeMessagesWithIds:(NSArray *)aMessageIds; + +/*! + @method + @brief 删除会话对象中相关联所有消息 + @discussion + @result 删除是否成功 + */ +- (BOOL)removeAllMessages; + +/*! + @method + @brief 从数据库中加载消息 + @discussion + @result 加载的消息列表 + */ +- (NSArray *)loadAllMessages; + +/*! + @method + @brief 根据消息ID从数据库中加载消息 + @discussion 如果数据库中没有这条消息, 方法返回nil + @param aMessageId 消息ID + @result 加载的消息 + */ +- (EMMessage *)loadMessage:(NSString *)aMessageId EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use - loadMessageWithId:"); +- (EMMessage *)loadMessageWithId:(NSString *)aMessageId; + +/*! + @method + @brief 根据消息ID列表从数据库中加载消息 + @discussion 如果数据库中没有某条消息对应的ID, 则不加载这条消息 + @param aMessageIds 消息ID列表 + @result 加载的消息列表 + */ +- (NSArray *)loadMessages:(NSArray *)aMessageIds EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use - loadMessagesWithIds:"); +- (NSArray *)loadMessagesWithIds:(NSArray *)aMessageIds; + +/*! + @method + @brief 根据时间加载指定条数的消息 + @param aCount 要加载的消息条数 + @param timestamp 时间点, UTC时间, 以毫秒为单位 + @discussion + 1. 加载后的消息按照升序排列; + 2. NSDate返回的timeInterval是以秒为单位的, 如果使用NSDate, 比如 timeIntervalSince1970 方法,需要将 timeInterval 乘以1000 + @result 加载的消息列表 + */ +- (NSArray *)loadNumbersOfMessages:(NSUInteger)aCount before:(long long)timestamp; + + +/*! + @method + @brief 根据消息id加载它之前的指定条数消息 + @param aCount 要加载的消息条数 + @param messageId 消息id,如果传nil就是取最后一条消息 + @discussion + 加载后的消息按照升序排列(不包含传入的messageId对应的消息); + @result 加载的消息列表 + */ +- (NSArray *)loadNumbersOfMessages:(NSUInteger)aCount withMessageId:(NSString *)messageId; + +/*! + @method + @brief 获取conversation最新一条消息 + @result EMMessage最新一条消息 + */ +- (EMMessage *)latestMessage; + +/*! + @method + @brief 获取conversation从对方发过来的最新一条消息 + @result EMMessage最新一条消息 + */ +- (EMMessage *)latestMessageFromOthers; + +#pragma mark - mark conversation + +/*! + @method + @brief 把本对话里的所有消息标记为已读/未读(此方法调用后,需要从数据库重新获取数据) + @param isRead 已读或未读 + @result 成功标记的消息条数 + */ +- (NSUInteger)markMessagesAsRead:(BOOL)isRead EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use - markAllMessagesAsRead:"); +- (BOOL)markAllMessagesAsRead:(BOOL)isRead; + +/*! + @method + @brief 把本条消息标记为已读/未读 + @discussion 非此conversation的消息不会被标记 + @param aMessageId 需要被标记的消息ID + @param isRead 已读或未读 + @result 是否成功标记此条消息 + */ +- (BOOL)markMessage:(NSString *)aMessageId asRead:(BOOL)isRead EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use - markMessageWithId:asRead"); +- (BOOL)markMessageWithId:(NSString *)aMessageId asRead:(BOOL)isRead; + +#pragma mark - statistics + +/*! + @method + @brief 获取此对话中所有未读消息的条数 + @discussion + @result 此对话中所有未读消息的条数 + */ +- (NSUInteger)unreadMessagesCount; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMCursorResult.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMCursorResult.h new file mode 100644 index 0000000..b0befa1 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMCursorResult.h @@ -0,0 +1,25 @@ +/*! + @header EMCursorResult.h + @abstract 分批获取的结果 + @author EaseMob Inc. + @version 1.00 2015/05/26 Creation (1.00) + */ + +#import + +@interface EMCursorResult : NSObject + +/*! + @property + @brief 结果 + */ +@property (nonatomic, strong) NSArray *list; + +/*! + @property + @brief 获取更多结果的cursor + */ +@property (nonatomic, copy) NSString *cursor; + ++ (instancetype)cursorResultWithList:(NSArray *)list andCursor:(NSString *)cusror; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMFileMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMFileMessageBody.h new file mode 100644 index 0000000..2fec1cb --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMFileMessageBody.h @@ -0,0 +1,95 @@ +/*! + @header EMFileMessageBody.h + @abstract 聊天的文件消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMFileMessageBody.h" +#import "EMChatManagerDefs.h" + +@protocol IEMChatObject; +@class EMMessage; +@class EMChatFile; + +/*! + @class + @brief 聊天的文件消息体对象 + */ +@interface EMFileMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @property + @brief 文件消息体的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件消息体的本地文件路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件消息体的服务器远程文件路径 + */ +@property (nonatomic, strong) NSString *remotePath; + +/*! + @property + @brief 远端文件的密钥, 下载时需要文件密钥和用户安全信息配合以下载远程文件 + */ +@property (nonatomic, strong) NSString *secretKey; + +/*! + @property + @brief 文件消息体的文件长度, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 附件是否下载完成 + */ +@property (nonatomic)EMAttachmentDownloadStatus attachmentDownloadStatus; + +/*! + @method + @brief 以文件对象创建文件消息体实例 + @discussion + @param aChatFile 文件对象 + @result 文件消息体 + */ +- (id)initWithChatObject:(EMChatFile *)aChatFile; + +/*! + @method + @brief 以文件属性创建文件消息体 + @discussion 如果传入的参数有误会返回nil + @param bodyDict 文件属性 + @param chatter 所属消息的chatter + @result 文件消息体 + */ ++ (instancetype)fileMessageBodyFromBodyDict:(NSDictionary *)bodyDict forChatter:(NSString *)chatter; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMGroup.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMGroup.h new file mode 100644 index 0000000..5e70248 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMGroup.h @@ -0,0 +1,132 @@ +/*! + @header EMGroup.h + @abstract 群组对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "commonDefs.h" +#import "EMGroupStyleSetting.h" + +@class EMError; +@class EMGroupOccupant; + +/*! + @class + @brief 聊天消息类 + */ +@interface EMGroup : NSObject + +/*! + @property + @brief 群组ID + */ +@property (nonatomic, strong, readonly) NSString *groupId; + +/*! + @property + @brief 群组的主题 + */ +@property (nonatomic, strong, readonly) NSString *groupSubject; + +/*! + @property + @brief 群组的描述 + */ +@property (nonatomic, strong, readonly) NSString *groupDescription; + +/*! + @property + @brief 群组的实际总人数 + */ +@property (nonatomic, readonly) NSInteger groupOccupantsCount; + +/*! + @property + @brief 群组的在线人数 + */ +@property (nonatomic, readonly) NSInteger groupOnlineOccupantsCount; + +/*! + @property + @brief 此群组的密码 + */ +@property (nonatomic, strong, readonly) NSString *password EM_DEPRECATED_IOS(2_0_3, 2_1_3, "Delete"); + +/*! + @property + @brief 此群是否为公开群组 + */ +@property (nonatomic, readonly) BOOL isPublic; + +/*! + @property + @brief 群组属性配置 + */ +@property (nonatomic, strong, readonly) EMGroupStyleSetting *groupSetting; + +/*! + @property + @brief 此群组是否接收推送通知 + */ +@property (nonatomic, readonly) BOOL isPushNotificationEnabled; + +/*! + @property + @brief 此群组是否被屏蔽 + */ +@property (nonatomic, readonly) BOOL isBlocked; + +/*! + @property + @brief 群组的创建者 + @discussion + 群组的所有者只有一人 + */ +@property (nonatomic, strong, readonly) NSString *owner; + +/*! + @property + @brief 群组的管理员列表 + @discussion + 群组的管理员不止一人,可以通过动态更改群组成员的角色而成为群组的管理员 + */ +@property (nonatomic, strong, readonly) NSArray *admins EM_DEPRECATED_IOS(2_0_3, 2_0_9, "Delete"); + +/*! + @property + @brief 群组的普通成员列表 + */ +@property (nonatomic, strong, readonly) NSArray *members; + +/*! + @property + @brief 此群组中的所有成员列表(owner, members) + */ +@property (nonatomic, strong, readonly) NSArray *occupants; + +/*! + @property + @brief 此群组黑名单中的成员列表 + @discussion 需要owner权限才能查看,非owner返回nil + */ +@property (nonatomic, strong, readonly) NSArray *bans; + +/*! + @method + @brief 通过username获取它的属性(一般只有匿名群中会用到) + @param username 需要获取的occupant信息的username + @result 返回username在群组中的属性 + */ +- (EMGroupOccupant *)occupantWithUsername:(NSString *)username; + +/*! + @method + @brief 如果不存在则创建一个群组实例 + @param groupId 群组ID + @result 返回群组实例 + */ ++ (instancetype)groupWithId:(NSString *)groupId; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMGroupStyleSetting.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMGroupStyleSetting.h new file mode 100644 index 0000000..6e746c0 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMGroupStyleSetting.h @@ -0,0 +1,54 @@ +/*! + @header EMGroupStyleSetting.h + @abstract 群组参数设置(用于创建群组) + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +/*! + @enum + @brief 群组类型 + @constant eGroupStyle_PrivateOnlyOwnerInvite 私有群组,只能owner权限的人邀请人加入 + @constant eGroupStyle_PrivateMemberCanInvite 私有群组,owner和member权限的人可以邀请人加入 + @constant eGroupStyle_PublicJoinNeedApproval 公开群组,允许非群组成员申请加入,需要管理员同意才能真正加入该群组 + @constant eGroupStyle_PublicOpenJoin 公开群组,允许非群组成员加入,不需要管理员同意 + @constant eGroupStyle_PublicAnonymous 公开匿名群组,允许非群组成员加入,不需要管理员同意 + @constant eGroupStyle_Default 默认群组类型 + @discussion + eGroupStyle_Private:私有群组,只允许群组成员邀请人进入 + eGroupStyle_Public: 公有群组,允许非群组成员加入 + */ +typedef NS_ENUM(NSInteger, EMGroupStyle){ + eGroupStyle_PrivateOnlyOwnerInvite = 0, + eGroupStyle_PrivateMemberCanInvite, + eGroupStyle_PublicJoinNeedApproval, + eGroupStyle_PublicOpenJoin, + eGroupStyle_PublicAnonymous, + eGroupStyle_Default = eGroupStyle_PrivateOnlyOwnerInvite, +}; + +#define KSDK_GROUP_MINUSERSCOUNT 3 +#define KSDK_GROUP_MAXUSERSCOUNT 500 +#define KSDK_GROUP_USERSCOUNTDEFAULT 200 + +/*! + @class + @brief 群组参数设置类 + */ +@interface EMGroupStyleSetting : NSObject + +/*! + @property + @brief 群组的类型 + */ +@property (nonatomic) EMGroupStyle groupStyle; + +/*! + @property + @brief 群组的最大成员数(3 - 2000,ios默认是200) + */ +@property (nonatomic) NSInteger groupMaxUsersCount; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMImageMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMImageMessageBody.h new file mode 100644 index 0000000..0857b75 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMImageMessageBody.h @@ -0,0 +1,172 @@ +/*! + @header EMImageMessageBody.h + @abstract 聊天的图片消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import + +#import "IEMFileMessageBody.h" +#import "EMChatManagerDefs.h" + +@class EMChatImage; +@class EMMessage; +@protocol IEMChatObject; + +/*! + @class + @brief 聊天的图片消息体对象 + */ +@interface EMImageMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @property + @brief 图片消息体中的预览图文件的服务器uuid + */ +@property (nonatomic, strong) NSString *thumbnailUuid; + +/*! + @property + @brief 图片消息体中的预览图的显示名 + */ +@property (nonatomic, strong) NSString *thumbnailDisplayName; + +/*! + @property + @brief 图片消息体中的预览图文件的本地路径 + */ +@property (nonatomic, strong) NSString *thumbnailLocalPath; + +/*! + @property + @brief 图片消息体中的预览图文件的服务器远程路径 + */ +@property (nonatomic, strong) NSString *thumbnailRemotePath; + +/*! + @property + @brief 远端图片预览文件的密钥, 下载时需要图片预览文件密钥和用户安全信息配合以下载远程图片预览文件 + */ +@property (nonatomic, strong) NSString *thumbnailSecretKey; + +/*! + @property + @brief 图片消息体中的预览图的尺寸 + */ +@property (nonatomic) CGSize thumbnailSize; + +/*! + @property + @brief 图片消息体中的预览图文件的大小, 以字节为单位 + */ +@property (nonatomic) long long thumbnailFileLength; + +/*! + @property + @brief 图片消息体中的大图的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 图片消息体中的大图文件的本地路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 图片消息体中图片文件的服务器远程路径 + */ +@property (nonatomic, strong) NSString *remotePath; + +/*! + @property + @brief 远端图片文件的密钥, 下载时需要图片文件密钥和用户安全信息配合以下载远程图片文件 + */ +@property (nonatomic, strong) NSString *secretKey; + +/*! + @property + @brief 图片消息体中的大图的尺寸 + */ +@property (nonatomic) CGSize size; + +/*! + @property + @brief 图片消息体中的大图文件的大小, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 图片消息体中的大图对象 + */ +@property (nonatomic, readonly, strong) EMChatImage *image; + +/*! + @property + @brief 图片消息体中的预览图对象 + */ +@property (nonatomic, readonly, strong) EMChatImage *thumbnailImage; + +/*! + @property + @brief 大图下载状态 + */ +@property (nonatomic)EMAttachmentDownloadStatus attachmentDownloadStatus; + +/*! + @property + @brief 缩略图下载状态 + */ +@property (nonatomic)EMAttachmentDownloadStatus thumbnailDownloadStatus; + +/*! + @method + @brief 以图片对象创建图片消息体 + @discussion 如果预览图对象为空或与大图为同一实例, 则会自动创建预览图对象 + @param aImage 大图对应的图片对象 + @param aThumbnialImage 预览图图对应的图片对象 + @result 图片消息体 + */ +- (id)initWithImage:(EMChatImage *)aImage thumbnailImage:(EMChatImage *)aThumbnialImage; + +/*! + @method + @brief 以图片对象创建图片消息体 + @discussion 会自动创建预览图对象 + @param aChatObject 大图对应的图片对象 + @result 图片消息体 + */ +- (id)initWithChatObject:(EMChatImage *)aChatObject; + +/*! + @method + @brief 以图片属性创建图片消息体 + @discussion 会自动创建预览图对象,如果传入的参数有误会返回nil + @param bodyDict 图片属性 + @param chatter 所属消息的chatter + @result 图片消息体 + */ ++ (instancetype)imageMessageBodyFromBodyDict:(NSDictionary *)bodyDict forChatter:(NSString *)chatter; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMLocationMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMLocationMessageBody.h new file mode 100644 index 0000000..2843c56 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMLocationMessageBody.h @@ -0,0 +1,68 @@ +/*! + @header EMLocationMessageBody.h + @abstract 聊天的位置消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMChatManagerDefs.h" +#import "IEMMessageBody.h" + +@class EMChatLocation; +@class EMMessage; +@protocol IEMChatObject; + +/*! + @class + @brief 聊天的位置消息体对象 + */ +@interface EMLocationMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @property + @brief 纬度 + */ +@property (nonatomic) double latitude; + +/*! + @property + @brief 经度 + */ +@property (nonatomic) double longitude; + +/*! + @property + @brief 地理位置信息 + */ +@property (nonatomic, strong) NSString *address; + +/*! + @method + @brief 以位置对象创建位置消息体实例 + @discussion + @param aChatLocation 位置对象 + @result 位置消息体 + */ +- (id)initWithChatObject:(EMChatLocation *)aChatLocation; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMMessage.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMMessage.h new file mode 100644 index 0000000..47f63e1 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMMessage.h @@ -0,0 +1,216 @@ +/*! + @header EMMessage.h + @abstract 聊天消息对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMChatManagerDefs.h" + +@protocol IEMMessageBody; +@class EMConversation; + +/*! + @class + @brief 聊天消息类 + */ +@interface EMMessage : NSObject +{ + BOOL _isOfflineMessage; +} + +/*! + @property + @brief 消息来源用户名 + */ +@property (nonatomic, copy) NSString *from; // should be username for now + +/*! + @property + @brief 消息目的地用户名 + */ +@property (nonatomic, copy) NSString *to; // should be username for now + +/*! + @property + @brief 消息ID + */ +@property (nonatomic, copy) NSString *messageId; + +/*! + @property + @brief 消息在发送前是否需要加密 + */ +@property (nonatomic) BOOL requireEncryption; + +/*! + @property + @brief 消息在服务器端是否已被加密 + */ +@property (nonatomic) BOOL isEncryptedOnServer; + +/*! + @property + @brief 消息发送或接收的时间 + */ +@property (nonatomic) long long timestamp; + +/*! + @property + @brief 消息是否已读 + */ +@property (nonatomic) BOOL isRead; + +/*! + @property + @brief 是否接收到了接收方的阅读回执, 或是否已发送了阅读回执给对方 + @discussion 针对发送的消息, 当接收方读了消息后, 会发回已读回执, 接收到了已读回执, 此标记位会被置为YES; + 针对接收的消息, 发送了阅读回执后, 此标记会被置为YES + */ +@property (nonatomic) BOOL isAcked EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use -isReadAcked"); +@property (nonatomic) BOOL isReadAcked; + +/*! + @property + @brief 对于发送方来说, 该值表示:接收方是否已收到了消息, 对于接收方来说, 表示:接收方是否已发送了"已接收回执" 给对方 + @discussion 针对发送的消息, 当接收方读了消息后, 会发回已读回执, 接收到了已读回执, 此标记位会被置为YES; + 针对接收的消息, 发送了阅读回执后, 此标记会被置为YES + */ +@property (nonatomic) BOOL isDelivered EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Use -isDeliveredAcked"); +@property (nonatomic) BOOL isDeliveredAcked; + +/*! + @property + @brief 消息体列表 + */ +@property (nonatomic, strong) NSArray *messageBodies; + +/*! + @property + @brief 消息所属的对话对象的chatter + */ +@property (nonatomic, strong) NSString *conversationChatter; + +/*! + @property + @brief 消息所属的对话对象 + */ +@property (nonatomic, weak) EMConversation *conversation EM_DEPRECATED_IOS(2_0_0, 2_1_1, "Delete"); + +/*! + @property + @brief 此消息是否是群聊消息 + */ +@property (nonatomic) BOOL isGroup EM_DEPRECATED_IOS(2_0_0, 2_1_6, "Use - messageType"); + +/*! + @property + @brief 群聊消息里的发送者用户名 + */ +@property (nonatomic, copy) NSString *groupSenderName; + +/*! + @property + @brief 是否是离线消息 + */ +@property (nonatomic, readonly) BOOL isOfflineMessage; + +/*! + @property + @brief 消息扩展 + */ +@property (nonatomic, strong) NSDictionary *ext; + +/*! + @property + @brief 消息发送状态 + */ +@property (nonatomic) MessageDeliveryState deliveryState; + +/*! + @property + @brief 是否是匿名消息 + */ +@property (nonatomic) BOOL isAnonymous; + +/*! + @property + @brief 消息类型 + */ +@property (nonatomic) EMMessageType messageType; + +/*! + @method + @brief 创建消息实例(用于:创建一个新的消息) + @discussion 消息实例会在发送过程中内部状态发生更改,比如deliveryState + @param receiver 消息接收方 + @param bodies 消息体列表 + @result 消息实例 + */ +- (id)initWithReceiver:(NSString *)receiver + bodies:(NSArray *)bodies; + +/*! + @method + @brief 创建消息实例(用于:已存在于数据库的消息,实例化为消息实例) + @discussion 消息实例会在发送过程中内部状态发生更改,比如deliveryState + @param messageId 消息id + @param sender 消息发送方 + @param receiver 消息接收方 + @param bodies 消息体列表 + @result 消息实例 + */ +- (id)initMessageWithID:(NSString *)messageId + sender:(NSString *)sender + receiver:(NSString *)receiver + bodies:(NSArray *)bodies; + +/*! + @method + @brief 将消息体加入消息实例 + @discussion 消息实例可以对消息体进行动态的添加删除 + @param body 消息体 + @result 此消息的消息体列表 + */ +- (NSArray *)addMessageBody:(id)body; + +/*! + @method + @brief 将消息体从消息实例中移除 + @discussion 消息实例可以对消息体进行动态的添加删除 + @param body 消息体 + @result 此消息的消息体列表 + */ +- (NSArray *)removeMessageBody:(id)body; + +/*! + @method + @brief 更新消息发送状态 + @result 是否更新成功 + */ +- (BOOL)updateMessageDeliveryStateToDB; + +/*! + @method + @brief 更新消息扩展属性 + @result 是否更新成功 + */ +- (BOOL)updateMessageExtToDB; + +/*! + @method + @brief 更新消息的消息体 + @result 是否更新成功 + */ +- (BOOL)updateMessageBodiesToDB; + +/*! + @method + @brief 修改当前 message 的发送状态, 下载状态为 failed (crash 时或者 terminate) + @return 是否更新成功 + */ +- (BOOL)updateMessageStatusFailedToDB; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMPushNotificationOptions.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMPushNotificationOptions.h new file mode 100644 index 0000000..843762e --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMPushNotificationOptions.h @@ -0,0 +1,83 @@ +/*! + @header EMPushNotificationOptions.h + @abstract 消息推送参数设置 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EMChatManagerDefs.h" + +/*! + @class + @brief 消息推送参数设置 + */ +@interface EMPushNotificationOptions : NSObject + +/*! + @property + @brief 推送消息显示的昵称 + */ +@property (nonatomic, strong) NSString *nickname; + +/*! + @property + @brief 推送消息显示的类型 + */ +@property (nonatomic) EMPushNotificationDisplayStyle displayStyle; + +/*! + @property + @brief 推送消息是否开启了免打扰模式,YES:开启免打扰;NO:未开启免打扰 + */ +@property (nonatomic) BOOL noDisturbing EM_DEPRECATED_IOS(2_0_6, 2_1_4, "Use - noDisturbStatus"); + +/*! + @property + @brief 推送消息的免打扰设置,YES:开启免打扰;NO:未开启免打扰 + */ +@property (nonatomic) EMPushNotificationNoDisturbStatus noDisturbStatus; + +/*! + @property + @brief 推送消息免打扰模式开始时间,小时,暂时只支持整点(小时) + */ +@property (nonatomic) NSUInteger noDisturbingStartH; + +/*! + @property + @brief 推送消息免打扰模式开始时间,分钟,暂时不支持 + */ +@property (nonatomic) NSUInteger noDisturbingStartM; + +/*! + @property + @brief 推送消息免打扰模式结束时间,小时,暂时只支持整点(小时) + */ +@property (nonatomic) NSUInteger noDisturbingEndH; + +/*! + @property + @brief 推送消息免打扰模式结束时间,分钟,暂时不支持 + */ +@property (nonatomic) NSUInteger noDisturbingEndM; + +/*! + @property + @brief 备份消息的大小 bytes + */ +@property (nonatomic) NSUInteger backupDataSize; + +/*! + @property + @brief 备份消息的时间戳 + */ +@property (nonatomic) NSTimeInterval backupTimeInterval; + +/*! + @property + @brief 备份消息的下载地址,以“,”组合成字符串 + */ +@property (strong, nonatomic) NSString *backupPaths; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMReceipt.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMReceipt.h new file mode 100644 index 0000000..4a0db82 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMReceipt.h @@ -0,0 +1,40 @@ +/*! + @header EMReceipt.h + @abstract 聊天回执 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import "EMReceiptBase.h" + +@class EMMessage; + +/*! + @class + @brief 聊天回执请求 + */ +@interface EMReceipt : EMReceiptBase + +/*! + @property + @brief 回执所属的对话对象的chatter + */ +@property (strong, nonatomic) NSString *conversationChatter; + +/*! + @property + @brief 是否是匿名消息回执 + */ +@property (assign, nonatomic) BOOL isAnonymous; + +/*! + @method + @brief 由消息创建回执请求 + @discussion + @param message 消息对象 + @param type 回执类型 + @result 聊天回执请求实例 + */ ++ (EMReceipt *)createFromMessage:(EMMessage *)message type:(EMReceiptType)type; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMReceiptBase.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMReceiptBase.h new file mode 100644 index 0000000..2f98864 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMReceiptBase.h @@ -0,0 +1,55 @@ +/*! + @header EMReceiptBase.h + @abstract 聊天回执请求与响应基类 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMChatManagerDefs.h" + +#pragma mark - EMReceipt Base +/*! + @class + @brief 聊天回执基类 + */ +@interface EMReceiptBase : NSObject + +/*! + @property + @brief 发送方 + */ +@property (nonatomic, copy) NSString *from; + +/*! + @property + @brief 接收方 + */ +@property (nonatomic, copy) NSString *to; + +/*! + @property + @brief 此回执关联的聊天ID + */ +@property (nonatomic, copy) NSString *chatId; + +/*! + @property + @brief 此回执是否用于群聊 + */ +@property (nonatomic) BOOL isGroup; + +/*! + @property + @brief 回执类型 + */ +@property (nonatomic) EMReceiptType type; + +/*! + @property + @brief 时间戳, UTC时间, 单位为毫秒 + */ +@property (nonatomic) long long timestamp; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMTextMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMTextMessageBody.h new file mode 100644 index 0000000..98524b2 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMTextMessageBody.h @@ -0,0 +1,56 @@ +/*! + @header EMTextMessageBody.h + @abstract 聊天的文本消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMMessageBody.h" +#import "EMChatManagerDefs.h" + +@class EMChatText; +@protocol IEMChatObject; +@class EMMessage; + +/*! + @class + @brief 聊天的文本消息体对象 + */ +@interface EMTextMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @property + @brief 文本消息体的内部文本对象的文本 + */ +@property (nonatomic, strong) NSString *text; + +/*! + @method + @brief 以文本对象创建文本消息体实例 + @discussion + @param aChatText 文本对象 + @result 文本消息体 + */ +- (id)initWithChatObject:(EMChatText *)aChatText; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMVideoMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMVideoMessageBody.h new file mode 100644 index 0000000..eab9288 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMVideoMessageBody.h @@ -0,0 +1,137 @@ +/*! + @header EMVideoMessageBody.h + @abstract 聊天的视频消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMFileMessageBody.h" +#import "EMChatManagerDefs.h" + +@class EMChatVideo; +@protocol IEMChatObject; +@class EMMessage; + +/*! + @class + @brief 聊天的视频消息体对象 + */ +@interface EMVideoMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @property + @brief 文件消息体的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件消息体的本地文件路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件消息体的服务器远程文件路径 + */ +@property (nonatomic, strong) NSString *remotePath; + +/*! + @property + @brief 远端视频文件的密钥, 下载时需要视频文件密钥和用户安全信息配合以下载远程视频文件 + */ +@property (nonatomic, strong) NSString *secretKey; + +/*! + @property + @brief 文件消息体的本地第一帧图片uuid + */ +@property (nonatomic, strong) NSString *thumbnailUuid; + +/*! + @property + @brief 文件消息体的本地第一帧图片路径 + */ +@property (nonatomic, strong) NSString *thumbnailLocalPath; + +/*! + @property + @brief 文件消息体的服务器视频第一帧图片路径 + */ +@property (nonatomic, strong) NSString *thumbnailRemotePath; + +/*! + @property + @brief 远端视频文件第一帧图片的密钥, 下载时需要视频文件密钥和用户安全信息配合以下载远程图片文件 + */ +@property (nonatomic, strong) NSString *thumbnailSecretKey; + +/*! + @property + @brief 文件消息体的文件长度, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 视频时长, 秒为单位 + */ +@property (nonatomic) NSInteger duration; + +/*! + @property + @brief 视频大小 + */ +@property (nonatomic) CGSize size; + +/*! + @property + @brief 视频附件是否下载完成 + */ +@property (nonatomic)EMAttachmentDownloadStatus attachmentDownloadStatus; + +/*! + @property + @brief 缩略图是否下载完成 + */ +@property (nonatomic)EMAttachmentDownloadStatus thumbnailDownloadStatus; + +/*! + @method + @brief 以视频对象创建视频消息体实例 + @discussion 视频部分目前不支持 + @param aChatVideo 视频对象 + @result 视频消息体 + */ +- (id)initWithChatObject:(EMChatVideo *)aChatVideo; + +/*! + @method + @brief 以视频属性创建视频消息体 + @discussion 如果传入的参数有误会返回nil + @param bodyDict 视频属性 + @param chatter 所属消息的chatter + @result 视频消息体 + */ ++ (instancetype)videoMessageBodyFromBodyDict:(NSDictionary *)bodyDict forChatter:(NSString *)chatter; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMVoiceMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMVoiceMessageBody.h new file mode 100644 index 0000000..204693c --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/EMVoiceMessageBody.h @@ -0,0 +1,101 @@ +/*! + @header EMVoiceMessageBody.h + @abstract 聊天的语音消息体对象类型 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMFileMessageBody.h" +#import "EMChatManagerDefs.h" + +@class EMMessage; +@class EMChatVoice; +@protocol IEMChatObject; + +/*! + @class + @brief 聊天的语音消息体对象 + */ +@interface EMVoiceMessageBody : NSObject + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @property + @brief 文件消息体的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件消息体的本地文件路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件消息体的服务器远程文件路径 + */ +@property (nonatomic, strong) NSString *remotePath; + +/*! + @property + @brief 远端语音文件的密钥, 下载时需要语音文件密钥和用户安全信息配合以下载远程语音文件 + */ +@property (nonatomic, strong) NSString *secretKey; + +/*! + @property + @brief 文件消息体的文件长度, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @property + @brief 语音时长, 秒为单位 + */ +@property (nonatomic) NSInteger duration; + +/*! + @property + @brief 语音附件是否下载完成 + */ +@property (nonatomic)EMAttachmentDownloadStatus attachmentDownloadStatus; + +/*! + @method + @brief 以语音对象创建语音消息体实例 + @discussion + @param aChatVoice 语音对象 + @result 语音消息体 + */ +- (id)initWithChatObject:(EMChatVoice *)aChatVoice; + +/*! + @method + @brief 以语音属性创建语音消息体 + @discussion 如果传入的参数有误会返回nil + @param bodyDict 语音属性 + @param chatter 所属消息的chatter + @result 语音消息体 + */ ++ (instancetype)voiceMessageBodyFromBodyDict:(NSDictionary *)bodyDict forChatter:(NSString *)chatter; +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IChatImageOptions.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IChatImageOptions.h new file mode 100644 index 0000000..d28c3f2 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IChatImageOptions.h @@ -0,0 +1,26 @@ +/*! + @header IChatImageOptions.h + @abstract 发送图片消息时的压缩设置协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +/*! + @protocol + @brief 本协议主要用于发送图片消息时的压缩设置, 目前只支持压缩比率的设置 + @discussion + */ +@protocol IChatImageOptions + +@required + +/*! + @property + @brief 发送图片信息时的压缩比率 + @discussion 为1.0的时候, 不压缩, 越小图片质量就越小. 如果设置为0, 则使用默认值(0.6)进行压缩 + */ +@property (assign, nonatomic) CGFloat compressionQuality; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatCryptor.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatCryptor.h new file mode 100644 index 0000000..e5bca75 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatCryptor.h @@ -0,0 +1,39 @@ +/*! + @header IEMChatCryptor.h + @abstract 为消息提供基础加解密服务的协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +/*! + @protocol + @brief 本协议主要用于对聊天提供基础的加密, 解密服务 + @discussion + */ +@protocol IEMChatCryptor + +@required + +/*! + @method + @brief 对NSData进行加密 + @discussion + @param data 要加密的数据 + @param aArgs 附加参数 + @result 加密后的数据 + */ +- (NSData *)encryptData:(NSData *)data args:(id)aArgs; + +/*! + @method + @brief 对NSData进行解密 + @discussion + @param data 要解密的数据 + @param aArgs 附加参数 + @result 解密后的数据 + */ +- (NSData *)decryptData:(NSData *)data args:(id)aArgs; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatFile.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatFile.h new file mode 100644 index 0000000..0211bb2 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatFile.h @@ -0,0 +1,57 @@ +/*! + @header IEMChatFile.h + @abstract 基于文件类的聊天对象接口 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMChatObject.h" + +/*! + @class + @brief 基于文件类的聊天对象协议 + */ +@protocol IEMChatFile + +@required + +/*! + @property + @brief 文件对象的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件对象本地磁盘位置的全路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件对象所对应的文件的大小, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +/*! + @method + @brief 以NSData构造文件对象 + @discussion + @param aData 文件内容 + @param aDisplayName 文件对象的显示名 + @result 文件对象 + */ +- (id)initWithData:(NSData *)aData displayName:(NSString *)aDisplayName; + +/*! + @method + @brief 以文件路径构造文件对象 + @discussion + @param filePath 磁盘文件全路径 + @param aDisplayName 文件对象的显示名 + @result 文件对象 + */ +- (id)initWithFile:(NSString *)filePath displayName:(NSString *)aDisplayName; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatObject.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatObject.h new file mode 100644 index 0000000..acd008a --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatObject.h @@ -0,0 +1,28 @@ +/*! + @header IEMChatObject.h + @abstract 聊天对象基类接口 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +@protocol IEMMessageBody; + +/*! + @class + @brief 聊天对象基类对象协议 + */ +@protocol IEMChatObject + +@required + +/*! + @property + @brief 聊天对象所在的消息体对象 + @discussion + 当消息体通过聊天对象创建完成后, messageBody为非nil, 当聊天对象并不属于任何消息体对象的时候, messageBody为nil + */ +@property (nonatomic, weak) id messageBody; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatProgressDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatProgressDelegate.h new file mode 100644 index 0000000..838baf1 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMChatProgressDelegate.h @@ -0,0 +1,56 @@ +/*! + @header IEMChatProgressDelegate.h + @abstract 聊天消息发送接收进度条协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "IEMMessageBody.h" + +/*! + @protocol + @brief 聊天消息发送接收进度条 + @discussion 当发送带有附件的消息时, 可以使用进度条在界面上提示用户当前进度 + */ +@protocol IEMChatProgressDelegate + +@optional + +/*! + @method + @brief 设置进度 + @discussion 用户需实现此接口用以支持进度显示 + @param progress 值域为0到1.0的浮点数 + @param message 某一条消息的progress + @result + */ +- (void)setProgress:(float)progress + forMessage:(EMMessage *)message EM_DEPRECATED_IOS(2_0_6, 2_1_2, "Use - setProgress:forMessage:forMessageBody:"); + +/*! + @method + @brief 设置进度 + @discussion 用户需实现此接口用以支持进度显示 + @param progress 值域为0到1.0的浮点数 + @result + */ +- (void)setProgress:(float)progress; + +@required + +/*! + @method + @brief 设置进度 + @discussion 用户需实现此接口用以支持进度显示 + @param progress 值域为0到1.0的浮点数 + @param message 某一条消息的progress + @param messageBody 某一条消息某个body的progress + @result + */ +- (void)setProgress:(float)progress + forMessage:(EMMessage *)message + forMessageBody:(id)messageBody; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMFileMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMFileMessageBody.h new file mode 100644 index 0000000..398ae69 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMFileMessageBody.h @@ -0,0 +1,107 @@ +/*! + @header IEMFileMessageBody.h + @abstract 基于文件类的消息体接口 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IEMMessageBody.h" + +//消息体类型键 +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyType; + +//附件属性键 +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyUrl; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeySecret; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyFileName; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyFileLength; + +//图片大小属性键 +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeySize; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeySizeWidth; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeySizeHeight; + +//缩略图属性键 +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyThumb; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyThumbSecret; + +//音视频时长 +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrKeyDuration; + +//消息体类型 +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeTxt; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeImag; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeAudio; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeLoc; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeVideo; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeFile; +FOUNDATION_EXTERN NSString * const EMMessageBodyAttrTypeCmd; + +/*! + @enum + @brief 附件下载的状态 + @constant EMAttachmentDownloading 正在下载 + @constant EMAttachmentDownloadSuccessed 下载成功 + @constant EMAttachmentDownloadFailure 下载失败 + @constant EMAttachmentNotStarted 未下载 + */ +typedef NS_ENUM(NSUInteger, EMAttachmentDownloadStatus) { + EMAttachmentDownloading, + EMAttachmentDownloadSuccessed, + EMAttachmentDownloadFailure, + EMAttachmentNotStarted, +} ; + + +/*! + @protocol + @brief 基于文件类型的消息体接口协议 + */ +@protocol IEMFileMessageBody + +@required + +/*! + @property + @brief 文件uuid + */ +@property (nonatomic, strong) NSString *uuid; + +/*! + @property + @brief 文件消息体的显示名 + */ +@property (nonatomic, strong) NSString *displayName; + +/*! + @property + @brief 文件消息体的本地文件路径 + */ +@property (nonatomic, strong) NSString *localPath; + +/*! + @property + @brief 文件消息体的服务器远程文件路径 + */ +@property (nonatomic, strong) NSString *remotePath; + +/*! + @property + @brief 远端文件的密钥, 下载时需要文件密钥和用户安全信息配合以下载远程文件 + */ +@property (nonatomic, strong) NSString *secretKey; + +/*! + @property + @brief 附件是否下载完成 + */ +@property (nonatomic)EMAttachmentDownloadStatus attachmentDownloadStatus; + +/*! + @property + @brief 文件消息体的文件长度, 以字节为单位 + */ +@property (nonatomic) long long fileLength; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMMessageBody.h b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMMessageBody.h new file mode 100644 index 0000000..603d483 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/ChatService/EMChatManager/types/IEMMessageBody.h @@ -0,0 +1,50 @@ +/*! + @header IEMMessageBody.h + @abstract 聊天消息体对象基类协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMChatManagerDefs.h" + +@protocol IEMChatObject; +@class EMMessage; + +/*! + @class + @brief 聊天的消息体基类对象协议 + */ +@protocol IEMMessageBody + +@required + +/*! + @property + @brief 消息体的类型 + */ +@property (nonatomic, readonly) MessageBodyType messageBodyType; + +/*! + @property + @brief 消息体的底层聊天对象 + */ +@property (nonatomic, strong, readonly) id chatObject; + +/*! + @property + @brief 消息体所在的消息对象 + */ +@property (nonatomic, weak) EMMessage *message; + +/*! + @method + @brief 由聊天对象构造消息体对象 + @discussion 派生类需要改写此方法 + @param aChatObject 聊天对象 + @result 消息体对象 + */ +- (id)initWithChatObject:(id)aChatObject; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EMSDKFull.h b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EMSDKFull.h new file mode 100644 index 0000000..1facfbb --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EMSDKFull.h @@ -0,0 +1,37 @@ +/*! + @header EMSDKFull.h + @abstract 客户端基本类 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "EaseMob.h" + +#warning 请使用EaseMob单实例引用callManager. 在下个版本将不会提供EMSDKFull及其头文件. EMSDKFull的功能将整合进EaseMob中. + +@protocol ICallManager; + +/*! + @class + @brief 该类包含了EaseMob和EMCallManager + @discussion SDK集成进工程后, 最先使用的类, 所有的类对象, 均是通过这个单实例来获取, 示例代码如下: + [EMSDKFull sharedInstance] + */ +@interface EMSDKFull : NSObject + +/*! + @method + @brief 获取单实例 + @discussion + @result EMSDKFull实例对象 + */ ++ (EMSDKFull *)sharedInstance; + +/*! + @property + @brief 实时通信管理器, 实时语音、实时视频等操作 + */ +@property (nonatomic, readonly, strong) id callManager; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EMSDKFullHeaders.h b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EMSDKFullHeaders.h new file mode 100644 index 0000000..e460783 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EMSDKFullHeaders.h @@ -0,0 +1,11 @@ +/*! + @header EaseMobHeaders.h + @abstract 引入SDK的所有需要的头文件 + @author EaseMob Inc. + @version 1.0 + */ + +#ifndef EaseMobClientSDK_EMSDKFullHeaders_h +#define EaseMobClientSDK_EMSDKFullHeaders_h + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EaseMob.h b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EaseMob.h new file mode 100644 index 0000000..0352181 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EaseMob.h @@ -0,0 +1,96 @@ +/*! + @header EaseMob.h + @abstract 客户端基本类 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import + +#import "EaseMobHeaders.h" + +/*! + @class + @brief 该类声明了EMChatManager和EMDeviceManager + @discussion SDK集成进工程后, 最先使用的类, 所有的类对象, 均是通过这个单实例来获取, 示例代码如下: + [EaseMob sharedInstance] + */ +@interface EaseMob : NSObject + +/*! + @property + @brief 聊天管理器, 获取该对象后, 可以做登录、聊天、加好友等操作 + */ +@property (nonatomic, readonly, strong) id chatManager; + +/*! + @property + @brief 设备管理器, 获取该对象后, 可以操作硬件相关的接口(照片、音频、地理位置信息等) + */ +@property (nonatomic, readonly, strong) id deviceManager; + +/*! + @property + @brief EaseMob SDK版本号 + */ +@property (nonatomic, readonly, strong) NSString *sdkVersion; + +/*! + @method + @brief 获取单实例 + @discussion + @result EaseMob实例对象 +*/ ++ (EaseMob *)sharedInstance; + +/*! + @method + @brief 初始化SDK + @discussion 失败返回EMError,成功返回nil + @result 初始化是否成功 + */ +- (EMError *)registerSDKWithAppKey:(NSString *)anAppKey EM_DEPRECATED_IOS(2_0_0, 2_0_2, "Use -registerSDKWithAppKey:apnsCertName:"); // Deprecated; + +/*! + @method + @brief 初始化SDK + @discussion 失败返回EMError,成功返回nil + @param anAppKey 申请应用时的appkey + @param anAPNSCertName 需要使用的APNS证书名字(需要与后台上传时的APNS证书名字相同, 客户端打包时的证书, 需要与服务器后台的证书一一对应) + @result 初始化是否成功 + */ +- (EMError *)registerSDKWithAppKey:(NSString *)anAppKey + apnsCertName:(NSString *)anAPNSCertName; + +/*! + @method + @brief 初始化SDK + @discussion 失败返回EMError,成功返回nil + @param anAppKey 申请应用时的appkey + @param anAPNSCertName 需要使用的APNS证书名字(需要与后台上传时的APNS证书名字相同, 客户端打包时的证书, 需要与服务器后台的证书一一对应) + @param anOtherConfig 其他初始化配置。目前支持自定义 1、是否打印Console Log(对应key为kSDKConfigEnableConsoleLogger) + @result 初始化是否成功 + */ +- (EMError *)registerSDKWithAppKey:(NSString *)anAppKey + apnsCertName:(NSString *)anAPNSCertName + otherConfig:(NSDictionary *)anOtherConfig; + +/*! + @method + @brief App切换到后台时, 开启后台运行模式, 在后台时, 仍可接收消息 + @discussion 要使SDK在后台仍然能正常运行, 有两种方式可以实现: + 1. 在工程的Capabilities中, 设置Background Modes, 勾选 Voice Over IP, 无需调用此方法, 也可保持App在后台运行(但开启此项时, 如果应用未使用到VOIP, 上传到App Store会有被拒绝的风险) + 2. 在工程的Capabilities中, 设置Background Modes, 勾选 Audio And Airplay, 然后调用此方法, 即可保持App在后台一直运行. + */ +- (void)enableBackgroundReceiveMessage EM_DEPRECATED_IOS(2_0_0, 2_0_7, "目前已不使用该方法, 请在 applicationDidEnterBackground 和 applicationWillEnterForeground 方法中通知添加 SDK 的回调即可"); + +//开启 exception监听,并将exception写入到日志 +//(跟友盟有冲突,如果使用了友盟,调用了该方法,有可能会导致 umeng的 crashReport不能正常工作) +//建议只在 Debug 状态时,打开该开关 +- (void)enableUncaughtExceptionHandler; + +@end + +#import "EaseMob+CallService.h" + diff --git a/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EaseMobHeaders.h b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EaseMobHeaders.h new file mode 100644 index 0000000..7904cd2 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDK/EaseMobHeaders.h @@ -0,0 +1,82 @@ +/*! + @header EaseMobHeaders.h + @abstract 引入SDK的所有需要的头文件 + @author EaseMob Inc. + @version 1.0 + */ + +#ifndef demoApp_EaseMobHeaders_h +#define demoApp_EaseMobHeaders_h + +//defs +#define kSDKAppKey @"EASEMOB_APPKEY" +#define kSDKApnsCertName @"EASEMOB_APNSCERTNAME" +#define kSDKConfigEnableConsoleLogger @"EASEMOB_CONFIG_ENABLECONSOLELOGGER" + +//private server +#define kSDKServerApi @"EASEMOB_API_ADDRESS" +#define kSDKServerChat @"EASEMOB_IM_ADDRESS" +#define kSDKServerChatPort @"EASEMOB_IM_PORT" +#define kSDKServerGroupDomain @"EASEMOB_GROUP_DOMAIN" +#define kSDKServerChatDomain @"EASEMOB_CHAT_DOMAIN" +#define kSDKConfigUseHttps @"EASEMOB_CONFIG_USEHTTPS" +#define kSDKConfigEnableIPAccess @"EASEMOB_ENABLE_IP_ACCESS" +#define kSDKConfigPingIntervalWifi @"EASEMOB_PING_INTERVAL_WIFI" +#define kSDKConfigPingIntervalWwan @"EASEMOB_PING_INTERVAL_WWAN" + +//defs headers +#import "EMChatManagerDefs.h" +#import "EMDeviceManagerDefs.h" +#import "EMErrorDefs.h" + +//managers & delegates +#import "IChatManager.h" +#import "IDeviceManager.h" +#import "IChatManagerDelegate.h" +#import "IDeviceManagerDelegate.h" + +//messages +#import "EMMessage.h" + +//message bodies +#import "IEMMessageBody.h" +#import "EMVideoMessageBody.h" +#import "EMVoiceMessageBody.h" +#import "EMTextMessageBody.h" +#import "EMLocationMessageBody.h" +#import "EMImageMessageBody.h" +#import "EMCommandMessageBody.h" +#import "EMFileMessageBody.h" + +//chat types +#import "EMChatVideo.h" +#import "EMChatVoice.h" +#import "EMChatText.h" +#import "EMChatLocation.h" +#import "EMChatImage.h" +#import "EMChatFile.h" +#import "EMChatCommand.h" + +//user types +#import "EMBuddy.h" + +//chat sessions +#import "EMGroup.h" +#import "EMGroupStyleSetting.h" +#import "IChatImageOptions.h" +#import "EMConversation.h" +#import "EMReceipt.h" + +//error +#import "EMError.h" + +//push +#import "EMPushNotificationOptions.h" + +//chat progress +#import "IEMChatProgressDelegate.h" + +//cryptor +#import "IEMChatCryptor.h" + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDKLite/EaseMob.h b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDKLite/EaseMob.h new file mode 120000 index 0000000..eb2fb13 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDKLite/EaseMob.h @@ -0,0 +1 @@ +/Users/dhc/Desktop/easemobProject/emclient-ios/EaseMobClientSDK/export/include/EaseMobClientSDK/EaseMob.h \ No newline at end of file diff --git a/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDKLite/EaseMobHeaders.h b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDKLite/EaseMobHeaders.h new file mode 120000 index 0000000..49719ad --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/EaseMobClientSDKLite/EaseMobHeaders.h @@ -0,0 +1 @@ +/Users/dhc/Desktop/easemobProject/emclient-ios/EaseMobClientSDK/export/include/EaseMobClientSDK/EaseMobHeaders.h \ No newline at end of file diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/EMDeviceManagerDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/EMDeviceManagerDefs.h new file mode 100644 index 0000000..6e82dff --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/EMDeviceManagerDefs.h @@ -0,0 +1,35 @@ +/*! + @header EMDeviceManagerDefs + @abstract 硬件管理的一些enum定义信息 + @author EaseMob Inc. + @version 1.0 + */ +#ifndef EaseMobClientSDK_DeviceManagerDefs_h +#define EaseMobClientSDK_DeviceManagerDefs_h + +typedef NS_ENUM(NSInteger, EMAudioOutputDevice) { + // output to earphone + eAudioOutputDevice_earphone = 0, + + // output to speaker + eAudioOutputDevice_speaker +}; + +typedef NS_ENUM(NSInteger, EMAudioPlaybackMode) { + // play sound, stop in background&screen lock, mixed with others + eAudioPlayMode_Simple = 0, + + // play sound, stop in background&screen lock, play sound exclusively + eAudioPlayMode_SimpleExclusive, + + // play sound, persist in backgound&screen lock + eAudioPlayMode_PersistPlay, + + // record sound only + eAudioPlayMode_RecordOnly, + + // play & record + eAudioPlayMode_PlayAndRecord +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/IDeviceManager.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/IDeviceManager.h new file mode 100644 index 0000000..75eac60 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/IDeviceManager.h @@ -0,0 +1,18 @@ +/*! + @header IDeviceManager.h + @abstract DeviceManager各类协议的合集 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ +#import + +/*! + @protocol + @brief DeviceManager各类协议的合集 + @discussion + */ +@protocol IDeviceManager + +@required + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/IDeviceManagerDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/IDeviceManagerDelegate.h new file mode 100644 index 0000000..9cae761 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/IDeviceManagerDelegate.h @@ -0,0 +1,19 @@ +/*! + @header IDeviceManagerDelegate.h + @abstract DeviceManager异步方法操作完成后的回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ +#import +#import "EMDeviceManagerDelegate.h" + +/*! + @protocol + @brief DeviceManager异步方法操作完成后的回调协议 + @discussion + */ +@protocol IDeviceManagerDelegate + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerDelegate.h new file mode 100644 index 0000000..3bfe8b2 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerDelegate.h @@ -0,0 +1,19 @@ +/*! + @header IDeviceManagerDelegate.h + @abstract DeviceManager异步方法操作完成后的回调协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ +#import +#import "EMDeviceManagerNetworkDelegate.h" + +/*! + @protocol + @brief DeviceManager异步方法操作完成后的回调协议 + @discussion + */ +@protocol EMDeviceManagerDelegate + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerDelegateBase.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerDelegateBase.h new file mode 100644 index 0000000..736cecf --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerDelegateBase.h @@ -0,0 +1,18 @@ +/*! + @header DeviceManager 回调协议的基础协议 + @abstract DeviceManager 回调协议的基础协议 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ +#import + +/*! + @protocol + @brief DeviceManager 回调协议的基础协议 + @discussion + */ +@protocol EMDeviceManagerDelegateBase + +@optional + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerNetworkDelegate.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerNetworkDelegate.h new file mode 100644 index 0000000..33d8e2b --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/delegates/internal/EMDeviceManagerNetworkDelegate.h @@ -0,0 +1,32 @@ +/*! + @header EMDeviceManagerNetworkDelegate.h + @abstract DeviceManager网络相关的事件通知 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#import "EMNetworkMonitorDefs.h" + +/*! + @protocol + @brief DeviceManagerDeviceManager网络相关的事件通知 + @discussion + */ +@protocol EMDeviceManagerNetworkDelegate + +@optional + +/*! + @method + @brief 网络状况发生变化的通知 + @param connectionType 新的网络状态 + @param fromConnectionType 上一次的网络状态 + @discussion + @result + */ +- (void)didConnectionChanged:(EMConnectionType)connectionType + fromConnectionType:(EMConnectionType)fromConnectionType; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/internal/IDeviceManagerBase.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/internal/IDeviceManagerBase.h new file mode 100644 index 0000000..c44e845 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMDeviceManager/internal/IDeviceManagerBase.h @@ -0,0 +1,39 @@ +/*! + @header IDeviceManagerBase.h + @abstract 为DeviceManager提供基础操作 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import +#import "IDeviceManagerDelegate.h" + +/*! + @protocol + @brief 设备管理器基础协议, 用于注册对象到监听列表和从监听列表中移除对象 + @discussion + */ +@protocol IDeviceManagerBase + +@required + +/*! + @method + @brief 注册一个监听对象到监听列表中 + @discussion 把监听对象添加到监听列表中准备接收相应的事件 + @param delegate 需要注册的监听对象 + @param aQueue 通知监听对象时的线程 + @result + */ +- (void)addDelegate:(id)delegate onQueue:(dispatch_queue_t)aQueue; + +/*! + @method + @brief 从监听列表中移除一个监听对象 + @discussion 把监听对象从监听列表中移除,取消接收相应的事件 + @param delegate 需要移除的监听对象 + @result + */ +- (void)removeDelegate:(id)delegate; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMNetworkMonitorDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMNetworkMonitorDefs.h new file mode 100644 index 0000000..0cacb80 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/EMNetworkMonitorDefs.h @@ -0,0 +1,48 @@ +/*! + @header EMNetworkMonitorDefs.h + @abstract 网络状况定义 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#ifndef EMNetworkMonitorDefs_h +#define EMNetworkMonitorDefs_h + +typedef NS_ENUM(NSUInteger, EMConnectionState) { + eEMConnectionConnected, //连接成功 + eEMConnectionDisconnected,//未连接 +}; + +/*! + @enum + @brief 网络状态 + @constant eConnectionType_None 没有网络连接 + @constant eConnectionType_WWAN 使用蜂窝网络 + @constant eConnectionType_WIFI 使用WIFI网络 + @constant eConnectionType_2G 使用2G网络 + @constant eConnectionType_3G 使用3G网络 + @constant eConnectionType_4G 使用4G网络 + */ +typedef NS_ENUM(NSInteger, EMConnectionType) { + eConnectionType_None = 0, + eConnectionType_WWAN, + eConnectionType_WIFI, + eConnectionType_2G, + eConnectionType_3G, + eConnectionType_4G, +}; + +/*! + @enum + @brief 网络类型 + @constant eConnectionName_Internet 网络连接 + @constant eConnectionName_LocalWIFI 本地wifi + @constant eConnectionName_Default 网络连接 + */ +typedef NS_ENUM(NSInteger, EMConnectionName) { + eConnectionName_Internet = 0, + eConnectionName_LocalWIFI, + eConnectionName_Default = eConnectionName_Internet +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/ErrorManager/EMError.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/ErrorManager/EMError.h new file mode 100644 index 0000000..d6d19cc --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/ErrorManager/EMError.h @@ -0,0 +1,49 @@ +/*! + @header EMError.h + @abstract SDK错误信息定义文件 + @author EaseMob Inc. + @version 1.0 + */ +#import +#import "EMErrorDefs.h" + +/*! + @class + @brief SDK错误信息定义类 + @discussion + */ +@interface EMError : NSObject + +/*! + @property + @brief 错误代码 + */ +@property (nonatomic) EMErrorType errorCode; + +/*! + @property + @brief 错误信息描述 + */ +@property (nonatomic, copy) NSString *description; + +/*! + @method + @brief 创建一个EMError实例对象 + @param errCode 错误代码 + @param description 错误描述信息 + @discussion + @result 错误信息描述实例对象 + */ ++ (EMError *)errorWithCode:(EMErrorType)errCode + andDescription:(NSString *)description; + +/*! + @method + @brief 通过NSError对象, 生成一个EMError对象 + @param error NSError对象 + @discussion + @result 错误信息描述实例对象 + */ ++ (EMError *)errorWithNSError:(NSError *)error; + +@end diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/ErrorManager/EMErrorDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/ErrorManager/EMErrorDefs.h new file mode 100644 index 0000000..2672854 --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/ErrorManager/EMErrorDefs.h @@ -0,0 +1,149 @@ +/*! + @header EMErrorDefs.h + @abstract EaseMob SDK 错误定义 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#ifndef EaseMobClientSDK_EMErrorDefs_h +#define EaseMobClientSDK_EMErrorDefs_h + +/*! + @enum + @brief EaseMob SDK 错误定义 + @discussion + SDK系统支持的errorCode 是从1000开始, 但是还是会返回HTTP Response Code, + 如果遇到404, 501等ErrorType时, 需要和HTTP的网络请求返回的responseCode进行对比 + @constant EMErrorNotFound 不存在 + @constant EMErrorServerMaxCountExceeded 数量达到上限(每人最多100条离线消息,群组成员达到上线) + @constant EMErrorConfigInvalidAppKey 无效的appKey + @constant EMErrorServerNotLogin 未登录 + @constant EMErrorServerNotReachable 连接服务器失败(Ex. 手机客户端无网的时候, 会返回的error) + @constant EMErrorServerTimeout 连接超时(Ex. 服务器连接超时会返回的error) + @constant EMErrorServerAuthenticationFailure 获取token失败(Ex. 登录时用户名密码错误,或者服务器无法返回token) + @constant EMErrorServerAPNSRegistrationFailure APNS注册失败 (Ex. 登录时, APNS注册失败会返回的error) + @constant EMErrorServerDuplicatedAccount 注册失败(Ex. 注册时, 如果用户存在, 会返回的error) + @constant EMErrorServerInsufficientPrivilege 所执行操作的权限不够(Ex. 非管理员删除群成员时, 会返回的error) + @constant EMErrorServerOccupantNotExist 操作群组时, 人员不在此群组(Ex. remove群组成员时, 会返回的error) + @constant EMErrorServerTooManyOperations 短时间内多次发起同一异步请求(Ex. 频繁刷新群组列表, 会返回的error) + @constant EMErrorAttachmentNotFound 未找着附件 + @constant EMErrorAttachmentDamaged 文件被损坏或被修改了 + @constant EMErrorAttachmentUploadFailure 文件上传失败 + @constant EMErrorFileTypeConvertionFailure 文件格式转换失败 + @constant EMErrorFileTypeNotSupported 不支持的文件格式 + @constant EMErrorIllegalURI URL非法(内部使用) + @constant EMErrorMessageInvalid_NULL 无效的消息(为空) + @constant EMErrorGroupInvalidID_NULL 无效的群组ID(为空) + @constant EMErrorGroupJoined 已加入群组 + @constant EMErrorGroupJoinNeedRequired 加入群组需要申请 + @constant EMErrorGroupFetchInfoFailure 获取群组失败 + @constant EMErrorGroupInvalidRequired 无效的群组申请 + @constant EMErrorGroupInvalidSubject_NULL 无效的群主题(为空) + @constant EMErrorGroupAddOccupantFailure 添加群成员失败 + @constant EMErrorInvalidUsername 无效的username + @constant EMErrorInvalidUsername_NULL 无效的username(用户名为空) + @constant EMErrorInvalidUsername_Chinese 无效的用户名(用户名不能是中文) + @constant EMErrorAudioRecordStoping 调用开始录音方法时,上一个录音正在stoping + @constant EMErrorAudioRecordDurationTooShort 录音时间过短 + @constant EMErrorAudioRecordNotStarted 录音没有开始 + @constant EMErrorPushNotificationInvalidOption 无效的消息推送设置 + @constant EMErrorRemoveBuddyFromRosterFailure 删除好友失败 + @constant EMErrorAddBuddyToRosterFailure 添加好友失败 + @constant EMErrorHasFetchedBuddyList 获取好友列表成功后, 再次发起好友列表 + @constant EMErrorCallChatterOffline, 对方不在线 + @constant EMErrorCallInvalidSessionId, 无效的通话Id + @constant EMErrorExisted, 已存在 + @constant EMErrorInitFailure 初始化失败 + @constant EMErrorNetworkNotConnected, 网络未连接 + @constant EMErrorFailure 失败 + @constant EMErrorFeatureNotImplemented 还未实现的功能 + @constant EMErrorRequestRefused 申请失效 + @constant EMErrorChatroomInvalidID_NULL 无效的聊天室ID(为空) + @constant EMErrorChatroomJoined 已加入聊天室 + @constant EMErrorChatroomNotJoined 没有加入聊天室 + */ +typedef NS_ENUM(NSInteger, EMErrorType) { + //general error + EMErrorNotFound = 404, //不存在 + EMErrorServerMaxCountExceeded = 500, //数量达到上限(每人最多100条离线消息,群组成员达到上线) + + //configuration error + EMErrorConfigInvalidAppKey = 1000, //无效的appKey + + //server error + EMErrorServerNotLogin = 1002, //未登录 + EMErrorServerNotReachable, //连接服务器失败(Ex. 手机客户端无网的时候, 会返回的error) + EMErrorServerTimeout, //连接超时(Ex. 服务器连接超时会返回的error) + EMErrorServerAuthenticationFailure, //获取token失败(Ex. 登录时用户名密码错误,或者服务器无法返回token) + EMErrorServerAPNSRegistrationFailure, //APNS注册失败 (Ex. 登录时, APNS注册失败会返回的error) + EMErrorServerDuplicatedAccount, //注册失败(Ex. 注册时, 如果用户存在, 会返回的error) + EMErrorServerInsufficientPrivilege, //所执行操作的权限不够(Ex. 非管理员删除群成员时, 会返回的error) + EMErrorServerOccupantNotExist, //操作群组时, 人员不在此群组(Ex. remove群组成员时, 会返回的error) + EMErrorServerTooManyOperations, //短时间内多次发起同一操作(Ex. 频繁刷新群组列表, 会返回的error) + + //file error + EMErrorAttachmentNotFound, //未找着附件 + EMErrorAttachmentDamaged, //文件被损坏或被修改了 + EMErrorAttachmentUploadFailure, //文件上传失败 + EMErrorFileTypeConvertionFailure, //文件格式转换失败 + EMErrorFileTypeNotSupported, //不支持的文件格式 + + EMErrorIllegalURI, //URL非法(内部使用) + + //message error + EMErrorMessageInvalid_NULL, //无效的消息(为空) + + //group error + EMErrorGroupInvalidID_NULL, //无效的群组ID(为空) + EMErrorGroupJoined, //已加入群组 + EMErrorGroupJoinNeedRequired, //加入群组需要申请 + EMErrorGroupFetchInfoFailure, //获取群组失败 + EMErrorGroupInvalidRequired, //无效的群组申请 + EMErrorGroupInvalidSubject_NULL, //无效的群主题(为空) + EMErrorGroupAddOccupantFailure, //添加群成员失败 + + //username error + EMErrorInvalidUsername, // 无效的username + EMErrorInvalidUsername_NULL, // 无效的用户名(用户名为空) + EMErrorInvalidUsername_Chinese, // 无效的用户名(用户名是中文) + + //play or record audio error + EMErrorAudioRecordStoping, //调用开始录音方法时,上一个录音正在stoping + EMErrorAudioRecordDurationTooShort, //录音时间过短 + EMErrorAudioRecordNotStarted, //录音没有开始 + + //push error + EMErrorPushNotificationInvalidOption, //无效的消息推送设置 + + EMErrorRemoveBuddyFromRosterFailure, //删除好友失败 + EMErrorAddBuddyToRosterFailure, //添加好友失败 + EMErrorHasFetchedBuddyList, //获取好友列表成功后, 再次发起好友列表请求时返回的errorType + + //call error + EMErrorCallChatterOffline, //对方不在线 + EMErrorCallInvalidSessionId, //无效的通话Id + + EMErrorExisted, //已存在 + EMErrorInitFailure, //初始化失败 + EMErrorNetworkNotConnected, //网络未连接 + EMErrorFailure, //失败 + EMErrorFeatureNotImplemented, //还未实现的功能 + + EMErrorRequestRefused, //申请失效 + + //chatroom error + EMErrorChatroomInvalidID_NULL, //无效的聊天室ID(为空) + EMErrorChatroomJoined, //已加入聊天室 + EMErrorChatroomNotJoined, //没有加入聊天室 + + EMErrorReachLimit = EMErrorServerMaxCountExceeded, + EMErrorOutOfRateLimited = EMErrorServerMaxCountExceeded, + EMErrorGroupOccupantsReachLimit = EMErrorServerMaxCountExceeded, + EMErrorTooManyLoginRequest = EMErrorServerTooManyOperations, + EMErrorTooManyLogoffRequest = EMErrorServerTooManyOperations, + EMErrorPermissionFailure = EMErrorServerInsufficientPrivilege, + EMErrorIsExist = EMErrorExisted, + +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/include/Utility/commonDefs.h b/Ash_AWord/Vender/EaseMobSDK/include/Utility/commonDefs.h new file mode 100644 index 0000000..b202bbd --- /dev/null +++ b/Ash_AWord/Vender/EaseMobSDK/include/Utility/commonDefs.h @@ -0,0 +1,41 @@ +/*! + @header commonDefs.h + @abstract 用户在线状态及聊天状态定义 + @author EaseMob Inc. + @version 1.0 + */ +#ifndef EaseMobClientSDK_commonDefs_h +#define EaseMobClientSDK_commonDefs_h + +//login info +#define kSDKPassword @"password" +#define kSDKUsername @"username" +#define kSDKToken @"token" + +//chat setting +#define kSDKConfigKeyPushNickname @"PushNickname" +#define kSDKConfigKeyAutoLogin @"AutoLogin" +#define kSDKConfigKeyAutoAcceptGroupInvitation @"AutoAcceptGroupInvitation" +#define kSDKConfigKeyAutoFetchBuddyList @"AutoFetchBuddyList" + + +#define EM_DEPRECATED_IOS(_easemobIntro, _easemobDep, ...) __attribute__((deprecated(""))) + +#pragma mark - buddy chatting state +typedef NS_ENUM(NSInteger, EMChatState) { + eChatState_Stopped = 0, + eChatState_Composing, + eChatState_Paused, +}; + +#pragma mark - buddy online state +typedef NS_ENUM(NSInteger, EMOnlineStatus) { + eOnlineStatus_OffLine = 0, + eOnlineStatus_Online, + eOnlineStatus_Away, + eOnlineStatus_Busy, + eOnlineStatus_Invisible, + eOnlineStatus_Do_Not_Disturb +}; + +#endif diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/SDKConfig.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/SDKConfig.plist new file mode 100644 index 0000000..1d10dfe Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/SDKConfig.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/VersionInfo.plist new file mode 100644 index 0000000..fb23cfe Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities 2.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities 2.mom new file mode 100644 index 0000000..6f07e98 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities 2.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities 2.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities 2.omo new file mode 100644 index 0000000..377fe29 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities 2.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities.mom new file mode 100644 index 0000000..6f07e98 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPCapabilities.momd/XMPPCapabilities.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/VersionInfo.plist new file mode 100644 index 0000000..fd58a7a Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/XMPPMessageArchiving.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/XMPPMessageArchiving.mom new file mode 100644 index 0000000..6e29691 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/XMPPMessageArchiving.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/XMPPMessageArchiving.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/XMPPMessageArchiving.omo new file mode 100644 index 0000000..11f8abd Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPMessageArchiving.momd/XMPPMessageArchiving.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/VersionInfo.plist new file mode 100644 index 0000000..544a691 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/XMPPRoom.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/XMPPRoom.mom new file mode 100644 index 0000000..b767d5a Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/XMPPRoom.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/XMPPRoom.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/XMPPRoom.omo new file mode 100644 index 0000000..88c7c16 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoom.momd/XMPPRoom.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/VersionInfo.plist new file mode 100644 index 0000000..3c6f9e1 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/XMPPRoomHybrid.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/XMPPRoomHybrid.mom new file mode 100644 index 0000000..f3f150a Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/XMPPRoomHybrid.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/XMPPRoomHybrid.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/XMPPRoomHybrid.omo new file mode 100644 index 0000000..f278435 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoomHybrid.momd/XMPPRoomHybrid.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/VersionInfo.plist new file mode 100644 index 0000000..fcef934 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster 2.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster 2.mom new file mode 100644 index 0000000..8356d56 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster 2.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster 2.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster 2.omo new file mode 100644 index 0000000..a346d76 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster 2.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster.mom new file mode 100644 index 0000000..8356d56 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPRoster.momd/XMPPRoster.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/VersionInfo.plist new file mode 100644 index 0000000..efbcdaf Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/XMPPvCard.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/XMPPvCard.mom new file mode 100644 index 0000000..849b82e Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/XMPPvCard.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/XMPPvCard.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/XMPPvCard.omo new file mode 100644 index 0000000..982605a Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/XMPPvCard.momd/XMPPvCard.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/com.easemob.config.xml b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/com.easemob.config.xml new file mode 100644 index 0000000..52298f1 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/com.easemob.config.xml differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/com.vip1.config.xml b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/com.vip1.config.xml new file mode 100644 index 0000000..7d7f214 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/com.vip1.config.xml differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/VersionInfo.plist b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/VersionInfo.plist new file mode 100644 index 0000000..8ee4306 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/VersionInfo.plist differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob.mom new file mode 100644 index 0000000..3ff8d7b Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_3.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_3.mom new file mode 100644 index 0000000..a26fa17 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_3.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_5.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_5.mom new file mode 100644 index 0000000..f0a17fa Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_5.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_6.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_6.mom new file mode 100644 index 0000000..1441233 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_6.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_7.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_7.mom new file mode 100644 index 0000000..f874205 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_7.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_7plus.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_7plus.mom new file mode 100644 index 0000000..67956c6 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_7plus.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_8.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_8.mom new file mode 100644 index 0000000..a64ed87 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_8.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_9.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_9.mom new file mode 100644 index 0000000..299ecd7 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_0_9.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_1_1.mom b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_1_1.mom new file mode 100644 index 0000000..75e6ba9 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_1_1.mom differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_1_1.omo b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_1_1.omo new file mode 100644 index 0000000..210812a Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/easemob.momd/easemob2_1_1.omo differ diff --git a/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/in.caf b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/in.caf new file mode 100644 index 0000000..685aef7 Binary files /dev/null and b/Ash_AWord/Vender/EaseMobSDK/resources/EaseMob.bundle/in.caf differ diff --git a/Ash_AWord/ViewControllers/Chat/Call/CallViewController.h b/Ash_AWord/ViewControllers/Chat/Call/CallViewController.h new file mode 100644 index 0000000..1e47af5 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/Call/CallViewController.h @@ -0,0 +1,62 @@ +// +// CallViewController.h +// ChatDemo-UI2.0 +// +// Created by dhc on 15/4/13. +// Copyright (c) 2015年 dhc. All rights reserved. +// + +#import +#import +#import +#import "EMCallManagerDelegate.h" +#import "OpenGLView20.h" +static CTCallCenter *g_callCenter; + +@interface CallViewController : UIViewController +{ + NSTimer *_timeTimer; + AVAudioPlayer *_ringPlayer; + + UIView *_topView; + UILabel *_statusLabel; + UILabel *_timeLabel; + UILabel *_nameLabel; + UIImageView *_headerImageView; + + UIView *_smallView; + OpenGLView20 *_openGLView; + AVCaptureVideoPreviewLayer *_smallCaptureLayer; + AVCaptureSession *_session; + AVCaptureVideoDataOutput *_captureOutput; + AVCaptureDeviceInput *_captureInput; + + UIView *_actionView; + UIButton *_silenceButton; + UILabel *_silenceLabel; + UIButton *_speakerOutButton; + UILabel *_speakerOutLabel; + + UIButton *_rejectButton; + UIButton *_answerButton; + + UIButton *_hangupButton; + + BOOL _isIncoming; + int _timeLength; + EMCallSession *_callSession; + UITapGestureRecognizer *_tapRecognizer; + + UInt8 *_imageDataBuffer; +} + +@property (strong, nonatomic) NSString *chatter; +@property (strong, nonatomic) UILabel *statusLabel; +@property (strong, nonatomic) UITapGestureRecognizer *tapRecognizer; + +- (instancetype)initWithSession:(EMCallSession *)session + isIncoming:(BOOL)isIncoming; + ++ (BOOL)canVideo; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/Call/CallViewController.m b/Ash_AWord/ViewControllers/Chat/Call/CallViewController.m new file mode 100644 index 0000000..fc8bb06 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/Call/CallViewController.m @@ -0,0 +1,614 @@ +// +// CallViewController.m +// ChatDemo-UI2.0 +// +// Created by dhc on 15/4/13. +// Copyright (c) 2015年 dhc. All rights reserved. +// + +#import +#import +#import "CallViewController.h" +#import "EMCallSession.h" +#import "EaseMob.h" +#define kAlertViewTag_Close 100 + +@interface CallViewController (){ + NSString * _audioCategory; +} + +@end + +@implementation CallViewController + +- (instancetype)initWithSession:(EMCallSession *)session + isIncoming:(BOOL)isIncoming +{ + self = [super initWithNibName:nil bundle:nil]; + if (self) { + _callSession = session; + _isIncoming = isIncoming; + _timeLabel.text = @""; + _timeLength = 0; + _chatter = session.sessionChatter; + +// [[EaseMob sharedInstance].callManager removeDelegate:self]; + [[EaseMob sharedInstance].callManager addDelegate:self delegateQueue:nil]; + + g_callCenter = [[CTCallCenter alloc] init]; + g_callCenter.callEventHandler=^(CTCall* call) + { + if(call.callState == CTCallStateIncoming) + { + NSLog(@"Call is incoming"); + [_timeTimer invalidate]; + [self _stopRing]; + + [[EaseMob sharedInstance].callManager asyncEndCall:_callSession.sessionId reason:eCallReason_Hangup]; + [self _close]; + } + }; + + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + [self _setupSubviews]; + + _nameLabel.text = _chatter; + if (_callSession.type == eCallSessionTypeVideo) { + [self _initializeCamera]; + [_session startRunning]; + [self.view addGestureRecognizer:self.tapRecognizer]; + [self.view bringSubviewToFront:_topView]; + [self.view bringSubviewToFront:_actionView]; + +#warning 要提前设置视频通话对方图像的显示区域 + _callSession.displayView = _openGLView; + } + + if (_isIncoming) { + _statusLabel.text = @"等待接听..."; + [_actionView addSubview:_answerButton]; + [_actionView addSubview:_rejectButton]; + } + else{ + _statusLabel.text = @"正在建立连接..."; + [_actionView addSubview:_hangupButton]; + } +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)dealloc +{ + if (_session) { + [_session stopRunning]; + [_session removeInput:_captureInput]; + [_session removeOutput:_captureOutput]; + _session = nil; + } + + if (_ringPlayer) { + [_ringPlayer stop]; + _ringPlayer = nil; + } + + if (_timeTimer) { + [_timeTimer invalidate]; + _timeTimer = nil; + } + + if (_smallView) { + [_smallCaptureLayer removeFromSuperlayer]; + _smallCaptureLayer = nil; + _smallView = nil; + } + + if (_openGLView) { + _openGLView = nil; + } + + if (_imageDataBuffer) { + free(_imageDataBuffer); + _imageDataBuffer = nil; + } +} + +#pragma makr - property + +- (UITapGestureRecognizer *)tapRecognizer +{ + if (_tapRecognizer == nil) { + _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapAction:)]; + } + + return _tapRecognizer; +} + +#pragma mark - subviews + +- (void)_setupSubviews +{ + if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) + { + [self setEdgesForExtendedLayout:UIRectEdgeNone]; + } + self.navigationController.navigationBarHidden = YES; + self.view.backgroundColor = [UIColor whiteColor]; + + UIImageView *bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; + bgImageView.contentMode = UIViewContentModeScaleToFill; + bgImageView.image = [UIImage imageNamed:@"callBg.png"]; + [self.view addSubview:bgImageView]; + + _topView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150)]; + _topView.backgroundColor = [UIColor clearColor]; + [self.view addSubview:_topView]; + + _statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 20, _topView.frame.size.width - 20, 20)]; + _statusLabel.font = [UIFont systemFontOfSize:15.0]; + _statusLabel.backgroundColor = [UIColor clearColor]; + _statusLabel.textColor = [UIColor whiteColor]; + _statusLabel.textAlignment = NSTextAlignmentCenter; + [_topView addSubview:self.statusLabel]; + + _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_statusLabel.frame), _topView.frame.size.width, 15)]; + _timeLabel.font = [UIFont systemFontOfSize:12.0]; + _timeLabel.backgroundColor = [UIColor clearColor]; + _timeLabel.textColor = [UIColor whiteColor]; + _timeLabel.textAlignment = NSTextAlignmentCenter; + [_topView addSubview:_timeLabel]; + + _headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake((_topView.frame.size.width - 50) / 2, CGRectGetMaxY(_statusLabel.frame) + 20, 50, 50)]; + _headerImageView.image = DefaultUserIcon; + [_topView addSubview:_headerImageView]; + + _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_headerImageView.frame) + 5, _topView.frame.size.width, 20)]; + _nameLabel.font = [UIFont systemFontOfSize:14.0]; + _nameLabel.backgroundColor = [UIColor clearColor]; + _nameLabel.textColor = [UIColor whiteColor]; + _nameLabel.textAlignment = NSTextAlignmentCenter; + _nameLabel.text = _chatter; + [_topView addSubview:_nameLabel]; + + _actionView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 180, self.view.frame.size.width, 180)]; + _actionView.backgroundColor = [UIColor clearColor]; + [self.view addSubview:_actionView]; + + CGFloat tmpWidth = _actionView.frame.size.width / 2; + _silenceButton = [[UIButton alloc] initWithFrame:CGRectMake((tmpWidth - 40) / 2, 20, 40, 40)]; + [_silenceButton setImage:[UIImage imageNamed:@"call_silence"] forState:UIControlStateNormal]; + [_silenceButton setImage:[UIImage imageNamed:@"call_silence_h"] forState:UIControlStateSelected]; + [_silenceButton addTarget:self action:@selector(silenceAction) forControlEvents:UIControlEventTouchUpInside]; + + _silenceLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(_silenceButton.frame), CGRectGetMaxY(_silenceButton.frame) + 5, 40, 20)]; + _silenceLabel.backgroundColor = [UIColor clearColor]; + _silenceLabel.textColor = [UIColor whiteColor]; + _silenceLabel.font = [UIFont systemFontOfSize:13.0]; + _silenceLabel.textAlignment = NSTextAlignmentCenter; + _silenceLabel.text = @"静音"; + + _speakerOutButton = [[UIButton alloc] initWithFrame:CGRectMake(tmpWidth + (tmpWidth - 40) / 2, _silenceButton.frame.origin.y, 40, 40)]; + [_speakerOutButton setImage:[UIImage imageNamed:@"call_out"] forState:UIControlStateNormal]; + [_speakerOutButton setImage:[UIImage imageNamed:@"call_out_h"] forState:UIControlStateSelected]; + [_speakerOutButton addTarget:self action:@selector(speakerOutAction) forControlEvents:UIControlEventTouchUpInside]; + + _speakerOutLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(_speakerOutButton.frame), CGRectGetMaxY(_speakerOutButton.frame) + 5, 40, 20)]; + _speakerOutLabel.backgroundColor = [UIColor clearColor]; + _speakerOutLabel.textColor = [UIColor whiteColor]; + _speakerOutLabel.font = [UIFont systemFontOfSize:13.0]; + _speakerOutLabel.textAlignment = NSTextAlignmentCenter; + _speakerOutLabel.text = @"免提"; + + _rejectButton = [[UIButton alloc] initWithFrame:CGRectMake((tmpWidth - 100) / 2, CGRectGetMaxY(_speakerOutLabel.frame) + 30, 100, 40)]; + [_rejectButton setTitle:@"拒接" forState:UIControlStateNormal]; + [_rejectButton setBackgroundColor:[UIColor colorWithRed:191 / 255.0 green:48 / 255.0 blue:49 / 255.0 alpha:1.0]];; + [_rejectButton addTarget:self action:@selector(rejectAction) forControlEvents:UIControlEventTouchUpInside]; + + _answerButton = [[UIButton alloc] initWithFrame:CGRectMake(tmpWidth + (tmpWidth - 100) / 2, _rejectButton.frame.origin.y, 100, 40)]; + [_answerButton setTitle:@"接听" forState:UIControlStateNormal]; + [_answerButton setBackgroundColor:[UIColor colorWithRed:191 / 255.0 green:48 / 255.0 blue:49 / 255.0 alpha:1.0]];; + [_answerButton addTarget:self action:@selector(answerAction) forControlEvents:UIControlEventTouchUpInside]; + + _hangupButton = [[UIButton alloc] initWithFrame:CGRectMake((self.view.frame.size.width - 200) / 2, _rejectButton.frame.origin.y, 200, 40)]; + [_hangupButton setTitle:@"挂断" forState:UIControlStateNormal]; + [_hangupButton setBackgroundColor:[UIColor colorWithRed:191 / 255.0 green:48 / 255.0 blue:49 / 255.0 alpha:1.0]];; + [_hangupButton addTarget:self action:@selector(hangupAction) forControlEvents:UIControlEventTouchUpInside]; +} + +- (void)_initializeCamera +{ + //1.大窗口显示层 + _openGLView = [[OpenGLView20 alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; + _openGLView.backgroundColor = [UIColor clearColor]; + _openGLView.sessionPreset = AVCaptureSessionPreset352x288; + [self.view addSubview:_openGLView]; + + //2.小窗口视图 + CGFloat width = 80; + CGFloat height = _openGLView.frame.size.height / _openGLView.frame.size.width * width; + _smallView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 90, CGRectGetMaxY(_statusLabel.frame), width, height)]; + _smallView.backgroundColor = [UIColor clearColor]; + [self.view addSubview:_smallView]; + + //3.创建会话层 + _session = [[AVCaptureSession alloc] init]; + [_session setSessionPreset:_openGLView.sessionPreset]; + + //4.创建、配置输入设备 + AVCaptureDevice *device; + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + for (AVCaptureDevice *tmp in devices) + { + if (tmp.position == AVCaptureDevicePositionFront) + { + device = tmp; + break; + } + } + + NSError *error = nil; + _captureInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error]; + [_session beginConfiguration]; + if(!error){ + [_session addInput:_captureInput]; + } + else{ + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"错误" message:error.localizedFailureReason delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; + [alertView show]; + } + + //5.创建、配置输出 + _captureOutput = [[AVCaptureVideoDataOutput alloc] init]; + _captureOutput.videoSettings = _openGLView.outputSettings; +// [[_captureOutput connectionWithMediaType:AVMediaTypeVideo] setVideoMinFrameDuration:CMTimeMake(1, 15)]; + _captureOutput.minFrameDuration = CMTimeMake(1, 15); +// _captureOutput.minFrameDuration = _openGLView.videoMinFrameDuration; + _captureOutput.alwaysDiscardsLateVideoFrames = YES; + dispatch_queue_t outQueue = dispatch_queue_create("com.gh.cecall", NULL); + [_captureOutput setSampleBufferDelegate:self queue:outQueue]; + [_session addOutput:_captureOutput]; + [_session commitConfiguration]; + + //6.小窗口显示层 + _smallCaptureLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session]; + _smallCaptureLayer.frame = CGRectMake(0, 0, width, height); + _smallCaptureLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; + [_smallView.layer addSublayer:_smallCaptureLayer]; +} + +#pragma mark - ring + +- (void)_beginRing +{ + [_ringPlayer stop]; + + NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"callRing" ofType:@"mp3"]; + NSURL *url = [[NSURL alloc] initFileURLWithPath:musicPath]; + + _ringPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; + [_ringPlayer setVolume:1]; + _ringPlayer.numberOfLoops = -1; //设置音乐播放次数 -1为一直循环 + if([_ringPlayer prepareToPlay]) + { + [_ringPlayer play]; //播放 + } +} + +- (void)_stopRing +{ + [_ringPlayer stop]; +} + +- (void)timeTimerAction:(id)sender +{ + _timeLength += 1; + int hour = _timeLength / 3600; + int m = (_timeLength - hour * 3600) / 60; + int s = _timeLength - hour * 3600 - m * 60; + + if (hour > 0) { + _timeLabel.text = [NSString stringWithFormat:@"%i:%i:%i", hour, m, s]; + } + else if(m > 0){ + _timeLabel.text = [NSString stringWithFormat:@"%i:%i", m, s]; + } + else{ + _timeLabel.text = [NSString stringWithFormat:@"00:%i", s]; + } +} + +#pragma mark - private + +- (void)_insertMessageWithStr:(NSString *)str +{ + EMChatText *chatText = [[EMChatText alloc] initWithText:str]; + EMTextMessageBody *textBody = [[EMTextMessageBody alloc] initWithChatObject:chatText]; + EMMessage *message = [[EMMessage alloc] initWithReceiver:_callSession.sessionChatter bodies:@[textBody]]; + message.isRead = YES; + message.deliveryState = eMessageDeliveryState_Delivered; + [[EaseMob sharedInstance].chatManager insertMessageToDB:message append2Chat:YES]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"insertCallMessage" object:message]; +} + +- (void)_close +{ + _callSession = nil; + _openGLView.hidden = YES; + [MBProgressHUD hideHUDForView:self.view animated:YES]; + + [_timeTimer invalidate]; + _timeTimer = nil; + + [_session stopRunning]; + [_session removeInput:_captureInput]; + [_session removeOutput:_captureOutput]; + _session = nil; + + [_smallCaptureLayer removeFromSuperlayer]; + _smallCaptureLayer = nil; + _smallView = nil; + + [_openGLView removeFromSuperview]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[AVAudioSession sharedInstance] setActive:NO error:nil]; + [[EaseMob sharedInstance].callManager removeDelegate:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"callControllerClose" object:nil]; + [self dismissViewControllerAnimated:YES completion:nil]; + }); +} + +#pragma mark - UIAlertViewDelegate + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (alertView.tag == kAlertViewTag_Close) + { + [[EaseMob sharedInstance].callManager asyncEndCall:_callSession.sessionId reason:eCallReason_Null]; + _callSession = nil; + [self _close]; + } +} + +#pragma mark AVCaptureVideoDataOutputSampleBufferDelegate + +void YUV420spRotate90(UInt8 * dst, UInt8* src, size_t srcWidth, size_t srcHeight) +{ + size_t wh = srcWidth * srcHeight; + size_t uvHeight = srcHeight >> 1;//uvHeight = height / 2 + size_t uvWidth = srcWidth>>1; + size_t uvwh = wh>>2; + //旋转Y + int k = 0; + for(int i = 0; i < srcWidth; i++) { + int nPos = wh-srcWidth; + for(int j = 0; j < srcHeight; j++) { + dst[k] = src[nPos + i]; + k++; + nPos -= srcWidth; + } + } + for(int i = 0; i < uvWidth; i++) { + int nPos = wh+uvwh-uvWidth; + for(int j = 0; j < uvHeight; j++) { + dst[k] = src[nPos + i]; + dst[k+uvwh] = src[nPos + i+uvwh]; + k++; + nPos -= uvWidth; + } + } +} + +- (void)captureOutput:(AVCaptureOutput *)captureOutput +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection +{ + if (_callSession.status != eCallSessionStatusAccepted) { + return; + } + +#warning 捕捉数据输出,根据自己需求可随意更改 + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + if(CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess) + { +// UInt8 *bufferbasePtr = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer); + UInt8 *bufferPtr = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); + UInt8 *bufferPtr1 = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 1); +// printf("addr diff1:%d,diff2:%d\n",bufferPtr-bufferbasePtr,bufferPtr1-bufferPtr); + +// size_t buffeSize = CVPixelBufferGetDataSize(imageBuffer); + size_t width = CVPixelBufferGetWidth(imageBuffer); + size_t height = CVPixelBufferGetHeight(imageBuffer); +// size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); + size_t bytesrow0 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0); + size_t bytesrow1 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 1); +// size_t bytesrow2 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 2); +// printf("buffeSize:%d,width:%d,height:%d,bytesPerRow:%d,bytesrow0 :%d,bytesrow1 :%d,bytesrow2 :%d\n",buffeSize,width,height,bytesPerRow,bytesrow0,bytesrow1,bytesrow2); + + if (_imageDataBuffer == nil) { + _imageDataBuffer = (UInt8 *)malloc(width * height * 3 / 2); + } + UInt8 *pY = bufferPtr; + UInt8 *pUV = bufferPtr1; + UInt8 *pU = _imageDataBuffer + width * height; + UInt8 *pV = pU + width * height / 4; + for(int i =0; i < height; i++) + { + memcpy(_imageDataBuffer + i * width, pY + i * bytesrow0, width); + } + + for(int j = 0; j < height / 2; j++) + { + for(int i = 0; i < width / 2; i++) + { + *(pU++) = pUV[i<<1]; + *(pV++) = pUV[(i<<1) + 1]; + } + pUV += bytesrow1; + } + + YUV420spRotate90(bufferPtr, _imageDataBuffer, width, height); + [[EaseMob sharedInstance].callManager processPreviewData:(char *)bufferPtr width:width height:height]; + + /*We unlock the buffer*/ + CVPixelBufferUnlockBaseAddress(imageBuffer, 0); + } +} + + +#pragma mark - ICallManagerDelegate + +- (void)callSessionStatusChanged:(EMCallSession *)callSession + changeReason:(EMCallStatusChangedReason)reason + error:(EMError *)error +{ + if(![_callSession.sessionId isEqualToString:callSession.sessionId]){ + return; + } + +// [self hideHud]; + [MBProgressHUD hideAllHUDsForView:self.view animated:YES]; + [self _stopRing]; + if(error){ + _statusLabel.text = @"连接失败"; + [self _insertMessageWithStr:@"通话失败"]; + + UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"error", @"Error") message:error.description delegate:self cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil]; + errorAlert.tag = kAlertViewTag_Close; + [errorAlert show]; + + return; + } + + if (callSession.status == eCallSessionStatusDisconnected) { + NSLog(@"callSession.status == eCallSessionStatusDisconnected"); + _statusLabel.text = @"通话已挂断"; + NSString *str = @"通话结束"; + if(_timeLength == 0) + { + if (reason == eCallReason_Hangup) { + str = @"取消通话"; + } + else if (reason == eCallReason_Reject){ + str = @"拒接通话"; + } + else if (reason == eCallReason_Busy){ + str = @"正在通话中"; + } + } + [self _insertMessageWithStr:str]; + [self _close]; + } + else if (callSession.status == eCallSessionStatusAccepted) + { + _statusLabel.text = @"可以通话了..."; + _timeLength = 0; + _timeTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timeTimerAction:) userInfo:nil repeats:YES]; + + if(_isIncoming) + { + [_answerButton removeFromSuperview]; + [_rejectButton removeFromSuperview]; + [_actionView addSubview:_hangupButton]; + } + [_actionView addSubview:_silenceButton]; + [_actionView addSubview:_silenceLabel]; + [_actionView addSubview:_speakerOutButton]; + [_actionView addSubview:_speakerOutLabel]; + } +} + +#pragma mark - UITapGestureRecognizer + +- (void)viewTapAction:(UITapGestureRecognizer *)tap +{ + _topView.hidden = !_topView.hidden; + _actionView.hidden = !_actionView.hidden; +} + +#pragma mark - action + +- (void)silenceAction +{ + _silenceButton.selected = !_silenceButton.selected; + [[EaseMob sharedInstance].callManager markCallSession:_callSession.sessionId asSilence:_silenceButton.selected]; +} + +- (void)speakerOutAction +{ + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + if (_speakerOutButton.selected) { + [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil]; + }else { + [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil]; + } + [audioSession setActive:YES error:nil]; + _speakerOutButton.selected = !_speakerOutButton.selected; +} + +- (void)rejectAction +{ + [_timeTimer invalidate]; + [self _stopRing]; +// [self showHint:@"拒接通话..."]; + [MBProgressHUD hudWithView:self.view label:@"拒接通话..."]; + + + [[EaseMob sharedInstance].callManager asyncEndCall:_callSession.sessionId reason:eCallReason_Reject]; +} + +- (void)answerAction +{ +// [self showHint:@"正在初始化通话..."]; + [MBProgressHUD hudWithView:self.view label:@"正在初始化通话..."]; + + [self _stopRing]; + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + _audioCategory = audioSession.category; + if(![_audioCategory isEqualToString:AVAudioSessionCategoryPlayAndRecord]){ + [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; + [audioSession setActive:YES error:nil]; + NSLog(@"xieyajie===========2"); + } + + [[EaseMob sharedInstance].callManager asyncAnswerCall:_callSession.sessionId]; +} + +- (void)hangupAction +{ + _openGLView.hidden = YES; + [_timeTimer invalidate]; + [self _stopRing]; +// [self showHint:@"正在结束通话..."]; + [MBProgressHUD hudWithView:self.view label:@"正在结束通话..."]; + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + [audioSession setCategory:_audioCategory error:nil]; + [audioSession setActive:YES error:nil]; + + [[EaseMob sharedInstance].callManager asyncEndCall:_callSession.sessionId reason:eCallReason_Hangup]; +} + ++ (BOOL)canVideo +{ + if([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending){ + if(!([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusAuthorized)){\ + UIAlertView * alt = [[UIAlertView alloc] initWithTitle:@"未获得授权使用摄像头" message:@"请在iOS\"设置中\"-\"隐私\"-\"相机\"中打开" delegate:self cancelButtonTitle:nil otherButtonTitles:@"知道了", nil]; + [alt show]; + return NO; + } + } + + return YES; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/Call/callRing.mp3 b/Ash_AWord/ViewControllers/Chat/Call/callRing.mp3 new file mode 100644 index 0000000..9499dae Binary files /dev/null and b/Ash_AWord/ViewControllers/Chat/Call/callRing.mp3 differ diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatAudioBubbleView.h b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatAudioBubbleView.h new file mode 100644 index 0000000..91977b0 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatAudioBubbleView.h @@ -0,0 +1,54 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "EMChatBaseBubbleView.h" + +#define ANIMATION_IMAGEVIEW_SIZE 25 // 小喇叭图片尺寸 +#define ANIMATION_IMAGEVIEW_SPEED 1 // 小喇叭动画播放速度 + + +#define ANIMATION_TIME_IMAGEVIEW_PADDING 5 // 时间与动画间距 + + +#define ANIMATION_TIME_LABEL_WIDHT 30 // 时间宽度 +#define ANIMATION_TIME_LABEL_HEIGHT 15 // 时间高度 +#define ANIMATION_TIME_LABEL_FONT_SIZE 14 // 时间字体 + +// 发送 +#define SENDER_ANIMATION_IMAGEVIEW_IMAGE_DEFAULT @"chat_sender_audio_playing_full" // 小喇叭默认图片 +#define SENDER_ANIMATION_IMAGEVIEW_IMAGE_01 @"chat_sender_audio_playing_000" // 小喇叭动画第一帧 +#define SENDER_ANIMATION_IMAGEVIEW_IMAGE_02 @"chat_sender_audio_playing_001" // 小喇叭动画第二帧 +#define SENDER_ANIMATION_IMAGEVIEW_IMAGE_03 @"chat_sender_audio_playing_002" // 小喇叭动画第三帧 +#define SENDER_ANIMATION_IMAGEVIEW_IMAGE_04 @"chat_sender_audio_playing_003" // 小喇叭动画第四帧 + + +// 接收 +#define RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_DEFAULT @"chat_receiver_audio_playing_full" // 小喇叭默认图片 +#define RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_01 @"chat_receiver_audio_playing000" // 小喇叭动画第一帧 +#define RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_02 @"chat_receiver_audio_playing001" // 小喇叭动画第二帧 +#define RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_03 @"chat_receiver_audio_playing002" // 小喇叭动画第三帧 +#define RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_04 @"chat_receiver_audio_playing003" // 小喇叭动画第四帧 + +extern NSString *const kRouterEventAudioBubbleTapEventName; + +@interface EMChatAudioBubbleView : EMChatBaseBubbleView +{ + UIImageView *_animationImageView; // 动画的ImageView + UILabel *_timeLabel; // 时间label +} + +-(void)startAudioAnimation; +-(void)stopAudioAnimation; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatAudioBubbleView.m b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatAudioBubbleView.m new file mode 100644 index 0000000..e63a268 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatAudioBubbleView.m @@ -0,0 +1,152 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatAudioBubbleView.h" + +NSString *const kRouterEventAudioBubbleTapEventName = @"kRouterEventAudioBubbleTapEventName"; + +@interface EMChatAudioBubbleView () +{ + NSMutableArray *_senderAnimationImages; + NSMutableArray *_recevierAnimationImages; + UIImageView *_isReadView; +} + +@end + +@implementation EMChatAudioBubbleView + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + _animationImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, ANIMATION_IMAGEVIEW_SIZE, ANIMATION_IMAGEVIEW_SIZE)]; + _animationImageView.animationDuration = ANIMATION_IMAGEVIEW_SPEED; + [self addSubview:_animationImageView]; + + _timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, ANIMATION_TIME_LABEL_WIDHT, ANIMATION_TIME_LABEL_HEIGHT)]; + _timeLabel.font = [UIFont boldSystemFontOfSize:ANIMATION_TIME_LABEL_FONT_SIZE]; + _timeLabel.textAlignment = NSTextAlignmentCenter; + _timeLabel.textColor = [UIColor grayColor]; + _timeLabel.backgroundColor = [UIColor clearColor]; + [self addSubview:_timeLabel]; + + _isReadView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; + _isReadView.layer.cornerRadius = 5; + [_isReadView setClipsToBounds:YES]; + [_isReadView setBackgroundColor:[UIColor redColor]]; + [self addSubview:_isReadView]; + + _senderAnimationImages = [[NSMutableArray alloc] initWithObjects: [UIImage imageNamed:SENDER_ANIMATION_IMAGEVIEW_IMAGE_01], [UIImage imageNamed:SENDER_ANIMATION_IMAGEVIEW_IMAGE_02], [UIImage imageNamed:SENDER_ANIMATION_IMAGEVIEW_IMAGE_03], [UIImage imageNamed:SENDER_ANIMATION_IMAGEVIEW_IMAGE_04], nil]; + _recevierAnimationImages = [[NSMutableArray alloc] initWithObjects: [UIImage imageNamed:RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_01], [UIImage imageNamed:RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_02], [UIImage imageNamed:RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_03], [UIImage imageNamed:RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_04], nil]; + } + return self; +} + +-(CGSize)sizeThatFits:(CGSize)size +{ + CGFloat width = BUBBLE_VIEW_PADDING*2 + BUBBLE_ARROW_WIDTH + ANIMATION_TIME_LABEL_WIDHT +ANIMATION_TIME_IMAGEVIEW_PADDING + ANIMATION_IMAGEVIEW_SIZE; + + CGFloat maxHeight = MAX(ANIMATION_IMAGEVIEW_SIZE, ANIMATION_TIME_LABEL_HEIGHT); + CGFloat height = BUBBLE_VIEW_PADDING*2 + maxHeight; + return CGSizeMake(width, height); +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect frame = _animationImageView.frame; + if (self.model.isSender) { + frame.origin.x = self.frame.size.width - BUBBLE_ARROW_WIDTH - frame.size.width - BUBBLE_VIEW_PADDING; + frame.origin.y = self.frame.size.height / 2 - frame.size.height / 2; + _animationImageView.frame = frame; + + frame = _timeLabel.frame; + frame.origin.x = _animationImageView.frame.origin.x - ANIMATION_TIME_IMAGEVIEW_PADDING - ANIMATION_TIME_LABEL_WIDHT; + frame.origin.y = _animationImageView.center.y - frame.size.height / 2; + _timeLabel.frame = frame; + + } + else { + _animationImageView.image = [UIImage imageNamed:RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_DEFAULT]; + + frame.origin.x = BUBBLE_ARROW_WIDTH + BUBBLE_VIEW_PADDING; + frame.origin.y = self.frame.size.height / 2 - frame.size.height / 2; + _animationImageView.frame = frame; + + frame = _timeLabel.frame; + frame.origin.x = ANIMATION_TIME_IMAGEVIEW_PADDING + BUBBLE_ARROW_WIDTH + _animationImageView.frame.size.width + _animationImageView.frame.origin.x; + frame.origin.y = _animationImageView.center.y - frame.size.height / 2; + _timeLabel.frame = frame; + frame.origin.x += frame.size.width - _isReadView.frame.size.width / 2; + frame.origin.y = - _isReadView.frame.size.height / 2; + frame.size = _isReadView.frame.size; + _isReadView.frame = frame; + } +} + +#pragma mark - setter + +- (void)setModel:(MessageModel *)model +{ + [super setModel:model]; + + _timeLabel.text = [NSString stringWithFormat:@"%d'",(int)self.model.time]; + + if (self.model.isSender) { + [_isReadView setHidden:YES]; + _animationImageView.image = [UIImage imageNamed:SENDER_ANIMATION_IMAGEVIEW_IMAGE_DEFAULT]; + _animationImageView.animationImages = _senderAnimationImages; + } + else{ + if (model.isPlayed) { + [_isReadView setHidden:YES]; + }else{ + [_isReadView setHidden:NO]; + } + + _animationImageView.image = [UIImage imageNamed:RECEIVER_ANIMATION_IMAGEVIEW_IMAGE_DEFAULT]; + _animationImageView.animationImages = _recevierAnimationImages; + } + + if (self.model.isPlaying) + { + [self startAudioAnimation]; + }else { + [self stopAudioAnimation]; + } +} + +#pragma mark - public + +-(void)bubbleViewPressed:(id)sender +{ + [self routerEventWithName:kRouterEventAudioBubbleTapEventName userInfo:@{KMESSAGEKEY:self.model}]; +} + + ++(CGFloat)heightForBubbleWithObject:(MessageModel *)object +{ + return 2 * BUBBLE_VIEW_PADDING + ANIMATION_IMAGEVIEW_SIZE; +} + +-(void)startAudioAnimation +{ + [_animationImageView startAnimating]; +} + +-(void)stopAudioAnimation +{ + [_animationImageView stopAnimating]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatBaseBubbleView.h b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatBaseBubbleView.h new file mode 100644 index 0000000..5817d1f --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatBaseBubbleView.h @@ -0,0 +1,51 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "MessageModel.h" +#import "THProgressView.h" +#import "UIResponder+Router.h" + +extern NSString *const kRouterEventChatCellBubbleTapEventName; + +#define BUBBLE_LEFT_IMAGE_NAME @"chat_receiver_bg" // bubbleView 的背景图片 +#define BUBBLE_RIGHT_IMAGE_NAME @"chat_sender_bg" +#define BUBBLE_ARROW_WIDTH 5 // bubbleView中,箭头的宽度 +#define BUBBLE_VIEW_PADDING 8 // bubbleView 与 在其中的控件内边距 + +#define BUBBLE_RIGHT_LEFT_CAP_WIDTH 5 // 文字在右侧时,bubble用于拉伸点的X坐标 +#define BUBBLE_RIGHT_TOP_CAP_HEIGHT 35 // 文字在右侧时,bubble用于拉伸点的Y坐标 + +#define BUBBLE_LEFT_LEFT_CAP_WIDTH 35 // 文字在左侧时,bubble用于拉伸点的X坐标 +#define BUBBLE_LEFT_TOP_CAP_HEIGHT 35 // 文字在左侧时,bubble用于拉伸点的Y坐标 + +#define BUBBLE_PROGRESSVIEW_HEIGHT 10 // progressView 高度 + +#define KMESSAGEKEY @"message" + +@interface EMChatBaseBubbleView : UIView +{ + THProgressView *_progressView; + MessageModel *_model; +} + +@property (nonatomic, strong) MessageModel *model; + +@property (nonatomic, strong) UIImageView *backImageView; +@property (nonatomic, strong) THProgressView *progressView; + +- (void)bubbleViewPressed:(id)sender; + ++ (CGFloat)heightForBubbleWithObject:(MessageModel *)object; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatBaseBubbleView.m b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatBaseBubbleView.m new file mode 100644 index 0000000..39430a6 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatBaseBubbleView.m @@ -0,0 +1,76 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatBaseBubbleView.h" + +NSString *const kRouterEventChatCellBubbleTapEventName = @"kRouterEventChatCellBubbleTapEventName"; + +@interface EMChatBaseBubbleView () + +@end + +@implementation EMChatBaseBubbleView + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) + { + _backImageView = [[UIImageView alloc] init]; + _backImageView.userInteractionEnabled = YES; + _backImageView.multipleTouchEnabled = YES; + _backImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + [self addSubview:_backImageView]; + + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bubbleViewPressed:)]; + [self addGestureRecognizer:tap]; + self.backgroundColor = [UIColor clearColor]; + } + + return self; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; +} + +#pragma mark - setter + +- (void)setModel:(MessageModel *)model +{ + _model = model; + + BOOL isReceiver = !_model.isSender; + NSString *imageName = isReceiver ? BUBBLE_LEFT_IMAGE_NAME : BUBBLE_RIGHT_IMAGE_NAME; + NSInteger leftCapWidth = isReceiver?BUBBLE_LEFT_LEFT_CAP_WIDTH:BUBBLE_RIGHT_LEFT_CAP_WIDTH; + NSInteger topCapHeight = isReceiver?BUBBLE_LEFT_TOP_CAP_HEIGHT:BUBBLE_RIGHT_TOP_CAP_HEIGHT; + self.backImageView.image = [[UIImage imageNamed:imageName] stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:topCapHeight]; +} + +#pragma mark - public + ++ (CGFloat)heightForBubbleWithObject:(MessageModel *)object +{ + return 30; +} + +- (void)bubbleViewPressed:(id)sender +{ + [self routerEventWithName:kRouterEventChatCellBubbleTapEventName userInfo:@{KMESSAGEKEY:self.model}]; +} + +- (void)progress:(CGFloat)progress +{ + [_progressView setProgress:progress animated:YES]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatImageBubbleView.h b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatImageBubbleView.h new file mode 100644 index 0000000..c1c5e97 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatImageBubbleView.h @@ -0,0 +1,25 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "EMChatBaseBubbleView.h" + +#define MAX_SIZE 120 // 图片最大显示大小 + +extern NSString *const kRouterEventImageBubbleTapEventName; + +@interface EMChatImageBubbleView : EMChatBaseBubbleView + +@property (nonatomic, strong) UIImageView *imageView; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatImageBubbleView.m b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatImageBubbleView.m new file mode 100644 index 0000000..306b06c --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatImageBubbleView.m @@ -0,0 +1,114 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +//#import "UIImageView+EMWebCache.h" +#import "EMChatImageBubbleView.h" + +NSString *const kRouterEventImageBubbleTapEventName = @"kRouterEventImageBubbleTapEventName"; + +@interface EMChatImageBubbleView () + +@end + +@implementation EMChatImageBubbleView + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + _imageView = [[UIImageView alloc] init]; + [self addSubview:_imageView]; + } + + return self; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + CGSize retSize = self.model.size; + if (retSize.width == 0 || retSize.height == 0) { + retSize.width = MAX_SIZE; + retSize.height = MAX_SIZE; + } + if (retSize.width > retSize.height) { + CGFloat height = MAX_SIZE / retSize.width * retSize.height; + retSize.height = height; + retSize.width = MAX_SIZE; + }else { + CGFloat width = MAX_SIZE / retSize.height * retSize.width; + retSize.width = width; + retSize.height = MAX_SIZE; + } + + return CGSizeMake(retSize.width + BUBBLE_VIEW_PADDING * 2 + BUBBLE_ARROW_WIDTH, 2 * BUBBLE_VIEW_PADDING + retSize.height); +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect frame = self.bounds; + frame.size.width -= BUBBLE_ARROW_WIDTH; + frame = CGRectInset(frame, BUBBLE_VIEW_PADDING, BUBBLE_VIEW_PADDING); + if (self.model.isSender) { + frame.origin.x = BUBBLE_VIEW_PADDING; + }else{ + frame.origin.x = BUBBLE_VIEW_PADDING + BUBBLE_ARROW_WIDTH; + } + + frame.origin.y = BUBBLE_VIEW_PADDING; + [self.imageView setFrame:frame]; +} + +#pragma mark - setter + +- (void)setModel:(MessageModel *)model +{ + [super setModel:model]; + + UIImage *image = _model.isSender ? _model.image : _model.thumbnailImage; + if (!image) { + image = _model.image; + if (!image) { + image = [UIImage imageNamed:@"imageDownloadFail.png"]; + } + } + self.imageView.image = image; +} + +#pragma mark - public + +-(void)bubbleViewPressed:(id)sender +{ + [self routerEventWithName:kRouterEventImageBubbleTapEventName + userInfo:@{KMESSAGEKEY:self.model}]; +} + + ++(CGFloat)heightForBubbleWithObject:(MessageModel *)object +{ + CGSize retSize = object.size; + if (retSize.width == 0 || retSize.height == 0) { + retSize.width = MAX_SIZE; + retSize.height = MAX_SIZE; + }else if (retSize.width > retSize.height) { + CGFloat height = MAX_SIZE / retSize.width * retSize.height; + retSize.height = height; + retSize.width = MAX_SIZE; + }else { + CGFloat width = MAX_SIZE / retSize.height * retSize.width; + retSize.width = width; + retSize.height = MAX_SIZE; + } + return 2 * BUBBLE_VIEW_PADDING + retSize.height; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatLocationBubbleView.h b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatLocationBubbleView.h new file mode 100644 index 0000000..1571141 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatLocationBubbleView.h @@ -0,0 +1,27 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import "EMChatBaseBubbleView.h" + +#define LOCATION_IMAGE @"chat_location_preview" // 显示的地图图片 +#define LOCATION_IMAGEVIEW_SIZE 95 // 地图图片大小 + +#define LOCATION_ADDRESS_LABEL_FONT_SIZE 10 // 位置字体大小 +#define LOCATION_ADDRESS_LABEL_PADDING 2 // 位置文字与外边间距 +#define LOCATION_ADDRESS_LABEL_BGVIEW_HEIGHT 25 // 位置文字显示外框的高度 + +extern NSString *const kRouterEventLocationBubbleTapEventName; + +@interface EMChatLocationBubbleView : EMChatBaseBubbleView + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatLocationBubbleView.m b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatLocationBubbleView.m new file mode 100644 index 0000000..99bef67 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatLocationBubbleView.m @@ -0,0 +1,91 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatLocationBubbleView.h" + +NSString *const kRouterEventLocationBubbleTapEventName = @"kRouterEventLocationBubbleTapEventName"; + +@interface EMChatLocationBubbleView () + +@property (nonatomic, strong) UIImageView *locationImageView; +@property (nonatomic, strong) UILabel *addressLabel; + +@end + +@implementation EMChatLocationBubbleView + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + + _locationImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, LOCATION_IMAGEVIEW_SIZE, LOCATION_IMAGEVIEW_SIZE)]; + [self addSubview:_locationImageView]; + + _addressLabel = [[UILabel alloc] init]; + _addressLabel.font = [UIFont systemFontOfSize:LOCATION_ADDRESS_LABEL_FONT_SIZE]; + _addressLabel.textColor = [UIColor whiteColor]; + _addressLabel.numberOfLines = 0; + _addressLabel.backgroundColor = [UIColor clearColor]; + [_locationImageView addSubview:_addressLabel]; + } + return self; +} + +-(CGSize)sizeThatFits:(CGSize)size +{ + CGSize textBlockMinSize = {130, 25}; + CGSize addressSize = [self.model.address sizeWithFont:_addressLabel.font constrainedToSize:textBlockMinSize lineBreakMode:NSLineBreakByCharWrapping]; + CGFloat width = addressSize.width < LOCATION_IMAGEVIEW_SIZE ? LOCATION_IMAGEVIEW_SIZE : addressSize.width; + + return CGSizeMake(width + BUBBLE_VIEW_PADDING * 2 + BUBBLE_ARROW_WIDTH, 2 * BUBBLE_VIEW_PADDING + LOCATION_IMAGEVIEW_SIZE); +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect frame = self.bounds; + frame.size.width -= BUBBLE_ARROW_WIDTH; + frame = CGRectInset(frame, BUBBLE_VIEW_PADDING, BUBBLE_VIEW_PADDING); + if (self.model.isSender) { + frame.origin.x = BUBBLE_VIEW_PADDING; + }else{ + frame.origin.x = BUBBLE_VIEW_PADDING + BUBBLE_ARROW_WIDTH; + } + + frame.origin.y = BUBBLE_VIEW_PADDING; + [self.locationImageView setFrame:frame]; + _addressLabel.frame = CGRectMake(5, self.locationImageView.frame.size.height - 30, self.locationImageView.frame.size.width - 10, 25); +} + +#pragma mark - setter + +- (void)setModel:(MessageModel *)model +{ + [super setModel:model]; + + _locationImageView.image = [[UIImage imageNamed:LOCATION_IMAGE] stretchableImageWithLeftCapWidth:10 topCapHeight:10]; // 设置地图图片 + _addressLabel.text = model.address; +} + +#pragma mark - public + +-(void)bubbleViewPressed:(id)sender +{ + [self routerEventWithName:kRouterEventLocationBubbleTapEventName userInfo:@{KMESSAGEKEY:self.model}]; +} + ++(CGFloat)heightForBubbleWithObject:(MessageModel *)object +{ + return 2 * BUBBLE_VIEW_PADDING + LOCATION_IMAGEVIEW_SIZE; +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatTextBubbleView.h b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatTextBubbleView.h new file mode 100644 index 0000000..f31b1f1 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatTextBubbleView.h @@ -0,0 +1,30 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import "EMChatBaseBubbleView.h" + + +#define TEXTLABEL_MAX_WIDTH 200 // textLaebl 最大宽度 +#define LABEL_FONT_SIZE 14 // 文字大小 +#define LABEL_LINESPACE 0 // 行间距 + +extern NSString *const kRouterEventTextURLTapEventName; + +@interface EMChatTextBubbleView : EMChatBaseBubbleView + +@property (nonatomic, strong) UILabel *textLabel; ++ (CGFloat)lineSpacing; ++ (UIFont *)textLabelFont; ++ (NSLineBreakMode)textLabelLineBreakModel; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatTextBubbleView.m b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatTextBubbleView.m new file mode 100644 index 0000000..343a941 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatTextBubbleView.m @@ -0,0 +1,317 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import "EMChatTextBubbleView.h" + +NSString *const kRouterEventTextURLTapEventName = @"kRouterEventTextURLTapEventName"; + +@interface EMChatTextBubbleView () +{ + NSDataDetector *_detector; + NSArray *_urlMatches; +} + +@end + +@implementation EMChatTextBubbleView + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + _textLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _textLabel.numberOfLines = 0; + _textLabel.lineBreakMode = NSLineBreakByCharWrapping; + _textLabel.font = [UIFont systemFontOfSize:LABEL_FONT_SIZE]; + _textLabel.backgroundColor = [UIColor clearColor]; + _textLabel.userInteractionEnabled = NO; + _textLabel.multipleTouchEnabled = NO; + [self addSubview:_textLabel]; + + _detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil]; + } + + return self; +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect frame = self.bounds; + frame.size.width -= BUBBLE_ARROW_WIDTH; + frame = CGRectInset(frame, BUBBLE_VIEW_PADDING, BUBBLE_VIEW_PADDING); + if (self.model.isSender) { + frame.origin.x = BUBBLE_VIEW_PADDING; + }else{ + frame.origin.x = BUBBLE_VIEW_PADDING + BUBBLE_ARROW_WIDTH; + } + + frame.origin.y = BUBBLE_VIEW_PADDING; + [self.textLabel setFrame:frame]; +} + +- (CGSize)sizeThatFits:(CGSize)size +{ + CGSize textBlockMinSize = {TEXTLABEL_MAX_WIDTH, CGFLOAT_MAX}; + CGSize retSize; + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + [paragraphStyle setLineSpacing:[[self class] lineSpacing]];//调整行间距 + + retSize = [self.model.content boundingRectWithSize:textBlockMinSize options:NSStringDrawingUsesLineFragmentOrigin + attributes:@{ + NSFontAttributeName:[[self class] textLabelFont], + NSParagraphStyleAttributeName:paragraphStyle + } + context:nil].size; + }else{ + retSize = [self.model.content sizeWithFont:[[self class] textLabelFont] constrainedToSize:textBlockMinSize lineBreakMode:[[self class] textLabelLineBreakModel]]; + } + + CGFloat height = 40; + if (2*BUBBLE_VIEW_PADDING + retSize.height > height) { + height = 2*BUBBLE_VIEW_PADDING + retSize.height; + } + + return CGSizeMake(retSize.width + BUBBLE_VIEW_PADDING*2 + BUBBLE_VIEW_PADDING, height); +} + +#pragma mark - setter + +- (void)setModel:(MessageModel *)model +{ + [super setModel:model]; + + _urlMatches = [_detector matchesInString:self.model.content options:0 range:NSMakeRange(0, self.model.content.length)]; + NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] + initWithString:self.model.content]; + NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + [paragraphStyle setLineSpacing:[[self class] lineSpacing]]; + [attributedString addAttribute:NSParagraphStyleAttributeName + value:paragraphStyle + range:NSMakeRange(0, [self.model.content length])]; + [_textLabel setAttributedText:attributedString]; + [self highlightLinksWithIndex:NSNotFound]; +} + +- (BOOL)isIndex:(CFIndex)index inRange:(NSRange)range +{ + return index > range.location && index < range.location+range.length; +} + +- (void)highlightLinksWithIndex:(CFIndex)index { + + NSMutableAttributedString* attributedString = [_textLabel.attributedText mutableCopy]; + + for (NSTextCheckingResult *match in _urlMatches) { + + if ([match resultType] == NSTextCheckingTypeLink) { + + NSRange matchRange = [match range]; + + if ([self isIndex:index inRange:matchRange]) { + [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:matchRange]; + } + else { + [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:matchRange]; + } + + [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:matchRange]; + } + } + + _textLabel.attributedText = attributedString; +} + +- (CFIndex)characterIndexAtPoint:(CGPoint)point +{ + NSMutableAttributedString* optimizedAttributedText = [self.textLabel.attributedText mutableCopy]; + + // use label's font and lineBreakMode properties in case the attributedText does not contain such attributes + [self.textLabel.attributedText enumerateAttributesInRange:NSMakeRange(0, [self.textLabel.attributedText length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) { + + if (!attrs[(NSString*)kCTFontAttributeName]) + { + [optimizedAttributedText addAttribute:(NSString*)kCTFontAttributeName value:self.textLabel.font range:NSMakeRange(0, [self.textLabel.attributedText length])]; + } + + if (!attrs[(NSString*)kCTParagraphStyleAttributeName]) + { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + [paragraphStyle setLineBreakMode:self.textLabel.lineBreakMode]; + + [optimizedAttributedText addAttribute:(NSString*)kCTParagraphStyleAttributeName value:paragraphStyle range:range]; + } + }]; + + // modify kCTLineBreakByTruncatingTail lineBreakMode to kCTLineBreakByWordWrapping + [optimizedAttributedText enumerateAttribute:(NSString*)kCTParagraphStyleAttributeName inRange:NSMakeRange(0, [optimizedAttributedText length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) + { + NSMutableParagraphStyle* paragraphStyle = [value mutableCopy]; + + if ([paragraphStyle lineBreakMode] == NSLineBreakByTruncatingTail) { + [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping]; + } + + [optimizedAttributedText removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range]; + [optimizedAttributedText addAttribute:(NSString*)kCTParagraphStyleAttributeName value:paragraphStyle range:range]; + }]; + + if (!CGRectContainsPoint(self.bounds, point)) { + return NSNotFound; + } + + CGRect textRect = self.textLabel.frame; + + if (!CGRectContainsPoint(textRect, point)) { + return NSNotFound; + } + + // Offset tap coordinates by textRect origin to make them relative to the origin of frame + point = CGPointMake(point.x - textRect.origin.x, point.y - textRect.origin.y); + // Convert tap coordinates (start at top left) to CT coordinates (start at bottom left) + point = CGPointMake(point.x, textRect.size.height - point.y); + + CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)optimizedAttributedText); + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, textRect); + + CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [self.textLabel.attributedText length]), path, NULL); + + if (frame == NULL) { + CFRelease(path); + return NSNotFound; + } + + CFArrayRef lines = CTFrameGetLines(frame); + + NSInteger numberOfLines = self.textLabel.numberOfLines > 0 ? MIN(self.textLabel.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines); + + //NSLog(@"num lines: %d", numberOfLines); + + if (numberOfLines == 0) { + CFRelease(frame); + CFRelease(path); + return NSNotFound; + } + + NSUInteger idx = NSNotFound; + + CGPoint lineOrigins[numberOfLines]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins); + + for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) { + + CGPoint lineOrigin = lineOrigins[lineIndex]; + CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex); + + // Get bounding information of line + CGFloat ascent, descent, leading, width; + width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading); + CGFloat yMin = floor(lineOrigin.y - descent); + CGFloat yMax = ceil(lineOrigin.y + ascent); + + // Check if we've already passed the line + if (point.y > yMax) { + break; + } + + // Check if the point is within this line vertically + if (point.y >= yMin) { + + // Check if the point is within this line horizontally + if (point.x >= lineOrigin.x && point.x <= lineOrigin.x + width) { + + // Convert CT coordinates to line-relative coordinates + CGPoint relativePoint = CGPointMake(point.x - lineOrigin.x, point.y - lineOrigin.y); + idx = CTLineGetStringIndexForPosition(line, relativePoint); + + break; + } + } + } + + CFRelease(frame); + CFRelease(path); + + return idx; +} + +#pragma mark - public + +-(void)bubbleViewPressed:(id)sender +{ + UITapGestureRecognizer *tap = (UITapGestureRecognizer *)sender; + CGPoint point = [tap locationInView:_textLabel]; + CFIndex charIndex = [self characterIndexAtPoint:point]; + + [self highlightLinksWithIndex:NSNotFound]; + + for (NSTextCheckingResult *match in _urlMatches) { + + if ([match resultType] == NSTextCheckingTypeLink) { + + NSRange matchRange = [match range]; + + if ([self isIndex:charIndex inRange:matchRange]) { + + [self routerEventWithName:kRouterEventTextURLTapEventName userInfo:@{KMESSAGEKEY:self.model, @"url":match.URL}]; + break; + } + } + } +} + ++(CGFloat)heightForBubbleWithObject:(MessageModel *)object +{ + CGSize textBlockMinSize = {TEXTLABEL_MAX_WIDTH, CGFLOAT_MAX}; + CGSize size; + static float systemVersion; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue]; + }); + if (systemVersion >= 7.0) { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + [paragraphStyle setLineSpacing:[[self class] lineSpacing]];//调整行间距 + size = [object.content boundingRectWithSize:textBlockMinSize options:NSStringDrawingUsesLineFragmentOrigin + attributes:@{ + NSFontAttributeName:[[self class] textLabelFont], + NSParagraphStyleAttributeName:paragraphStyle + } + context:nil].size; + }else{ + size = [object.content sizeWithFont:[self textLabelFont] + constrainedToSize:textBlockMinSize + lineBreakMode:[self textLabelLineBreakModel]]; + } + return 2 * BUBBLE_VIEW_PADDING + size.height; +} + ++(UIFont *)textLabelFont +{ + return [UIFont systemFontOfSize:LABEL_FONT_SIZE]; +} + ++(CGFloat)lineSpacing{ + return LABEL_LINESPACE; +} + ++(NSLineBreakMode)textLabelLineBreakModel +{ + return NSLineBreakByCharWrapping; +} + + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatVideoBubbleView.h b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatVideoBubbleView.h new file mode 100644 index 0000000..9b65ccf --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatVideoBubbleView.h @@ -0,0 +1,19 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatImageBubbleView.h" + +extern NSString *const kRouterEventChatCellVideoTapEventName; + +@interface EMChatVideoBubbleView : EMChatImageBubbleView + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatVideoBubbleView.m b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatVideoBubbleView.m new file mode 100644 index 0000000..ec7cf8f --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/ChatCellBubble/EMChatVideoBubbleView.m @@ -0,0 +1,56 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatVideoBubbleView.h" + +NSString *const kRouterEventChatCellVideoTapEventName = @"kRouterEventChatCellVideoTapEventName"; + +@interface EMChatVideoBubbleView () + +@property (strong, nonatomic)UIButton *videoPlayButton; + +@end + +@implementation EMChatVideoBubbleView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + self.videoPlayButton = [UIButton buttonWithType:UIButtonTypeCustom]; + UIImage *backgroundImage = [UIImage imageNamed:@"chat_video_play.png"]; + [self.videoPlayButton setBackgroundImage:backgroundImage forState:UIControlStateNormal]; + [self.videoPlayButton addTarget:self action:@selector(playVideoAction:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.videoPlayButton]; + } + return self; +} + +//- (void)bubbleViewPressed:(id)sender +//{ +// //图片点击事件, 啥都不做 +//} + +- (void)playVideoAction:(id)sender{ + [self routerEventWithName:kRouterEventChatCellVideoTapEventName userInfo:@{KMESSAGEKEY:self.model}]; +} + +- (void)layoutSubviews{ + [super layoutSubviews]; + CGFloat width = 50.0f; + CGFloat height = 50.0f; + CGFloat x = self.frame.size.width/2 - width/2; + CGFloat y = self.frame.size.height/2 - height/2; + [self.videoPlayButton setFrame:CGRectMake(x, y, width, height)]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatTimeCell.h b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatTimeCell.h new file mode 100644 index 0000000..3a34dc4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatTimeCell.h @@ -0,0 +1,17 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +@interface EMChatTimeCell : UITableViewCell + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatTimeCell.m b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatTimeCell.m new file mode 100644 index 0000000..2bc129e --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatTimeCell.m @@ -0,0 +1,45 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatTimeCell.h" + +@implementation EMChatTimeCell + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + } + self.backgroundColor = [UIColor clearColor]; + self.textLabel.backgroundColor = [UIColor clearColor]; + self.textLabel.textAlignment = NSTextAlignmentCenter; + self.textLabel.font = [UIFont systemFontOfSize:14]; + self.textLabel.textColor = [UIColor grayColor]; + self.selectionStyle = UITableViewCellSelectionStyleNone; + + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewBaseCell.h b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewBaseCell.h new file mode 100644 index 0000000..7eaf40e --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewBaseCell.h @@ -0,0 +1,55 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "MessageModel.h" +#import "EMChatBaseBubbleView.h" + +#import "UIResponder+Router.h" + +#define HEAD_SIZE 40 // 头像大小 +#define HEAD_PADDING 5 // 头像到cell的内间距和头像到bubble的间距 +#define CELLPADDING 8 // Cell之间间距 + +#define NAME_LABEL_WIDTH 180 // nameLabel最大宽度 +#define NAME_LABEL_HEIGHT 20 // nameLabel 高度 +#define NAME_LABEL_PADDING 5 // nameLabel间距 +#define NAME_LABEL_FONT_SIZE 14 // 字体 + +extern NSString *const kRouterEventChatHeadImageTapEventName; + +@interface EMChatViewBaseCell : UITableViewCell +{ + UIImageView *_headImageView; + UILabel *_nameLabel; + EMChatBaseBubbleView *_bubbleView; + + CGFloat _nameLabelHeight; + MessageModel *_messageModel; +} + +@property (nonatomic, strong) MessageModel *messageModel; + +@property (nonatomic, strong) UIImageView *headImageView; //头像 +@property (nonatomic, strong) UILabel *nameLabel; //姓名(暂时不支持显示) +@property (nonatomic, strong) EMChatBaseBubbleView *bubbleView; //内容区域 + +- (id)initWithMessageModel:(MessageModel *)model reuseIdentifier:(NSString *)reuseIdentifier; + +- (void)setupSubviewsForMessageModel:(MessageModel *)model; + ++ (NSString *)cellIdentifierForMessageModel:(MessageModel *)model; + ++ (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath withObject:(MessageModel *)model; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewBaseCell.m b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewBaseCell.m new file mode 100644 index 0000000..be3ba6f --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewBaseCell.m @@ -0,0 +1,161 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatViewBaseCell.h" +//#import "UIImageView+EMWebCache.h" + +NSString *const kRouterEventChatHeadImageTapEventName = @"kRouterEventChatHeadImageTapEventName"; + +@interface EMChatViewBaseCell() + +@end + +@implementation EMChatViewBaseCell + +- (id)initWithMessageModel:(MessageModel *)model reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(headImagePressed:)]; + CGFloat originX = HEAD_PADDING; + if (model.isSender) { + originX = self.bounds.size.width - HEAD_SIZE - HEAD_PADDING; + } + _headImageView = [[UIImageView alloc] initWithFrame:CGRectMake(originX, CELLPADDING, HEAD_SIZE, HEAD_SIZE)]; + [_headImageView addGestureRecognizer:tap]; + _headImageView.userInteractionEnabled = YES; + _headImageView.multipleTouchEnabled = YES; + _headImageView.backgroundColor = [UIColor clearColor]; + [self.contentView addSubview:_headImageView]; + + _nameLabel = [[UILabel alloc] init]; + _nameLabel.backgroundColor = [UIColor clearColor]; + _nameLabel.textColor = [UIColor grayColor]; + _nameLabel.textAlignment = NSTextAlignmentLeft; + _nameLabel.font = [UIFont systemFontOfSize:12]; + [self.contentView addSubview:_nameLabel]; + + [self setupSubviewsForMessageModel:model]; + } + return self; +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect frame = _headImageView.frame; + frame.origin.x = _messageModel.isSender ? (self.bounds.size.width - _headImageView.frame.size.width - HEAD_PADDING) : HEAD_PADDING; + _headImageView.frame = frame; + + [_nameLabel sizeToFit]; + frame = _nameLabel.frame; + frame.origin.x = HEAD_PADDING * 2 + CGRectGetWidth(_headImageView.frame) + NAME_LABEL_PADDING; + frame.origin.y = CGRectGetMinY(_headImageView.frame); + frame.size.width = NAME_LABEL_WIDTH; + _nameLabel.frame = frame; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +#pragma mark - setter + +- (void)setMessageModel:(MessageModel *)messageModel +{ + _messageModel = messageModel; + + _nameLabel.hidden = (messageModel.messageType == eMessageTypeChat); + + UIImage *placeholderImage = [UIImage imageNamed:@"chatListCellHead"]; + [self.headImageView sd_setImageWithURL:_messageModel.headImageURL placeholderImage:placeholderImage]; +} + +#pragma mark - private + +-(void)headImagePressed:(id)sender +{ + [super routerEventWithName:kRouterEventChatHeadImageTapEventName userInfo:@{KMESSAGEKEY:self.messageModel}]; +} + +- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo +{ + [super routerEventWithName:eventName userInfo:userInfo]; +} + +#pragma mark - public + +- (void)setupSubviewsForMessageModel:(MessageModel *)model +{ + if (model.isSender) { + self.headImageView.frame = CGRectMake(self.bounds.size.width - HEAD_SIZE - HEAD_PADDING, CELLPADDING, HEAD_SIZE, HEAD_SIZE); + } + else{ + self.headImageView.frame = CGRectMake(0, CELLPADDING, HEAD_SIZE, HEAD_SIZE); + } +} + ++ (NSString *)cellIdentifierForMessageModel:(MessageModel *)model +{ + NSString *identifier = @"MessageCell"; + if (model.isSender) { + identifier = [identifier stringByAppendingString:@"Sender"]; + } + else{ + identifier = [identifier stringByAppendingString:@"Receiver"]; + } + + switch (model.type) { + case eMessageBodyType_Text: + { + identifier = [identifier stringByAppendingString:@"Text"]; + } + break; + case eMessageBodyType_Image: + { + identifier = [identifier stringByAppendingString:@"Image"]; + } + break; + case eMessageBodyType_Voice: + { + identifier = [identifier stringByAppendingString:@"Audio"]; + } + break; + case eMessageBodyType_Location: + { + identifier = [identifier stringByAppendingString:@"Location"]; + } + break; + case eMessageBodyType_Video: + { + identifier = [identifier stringByAppendingString:@"Video"]; + } + break; + + default: + break; + } + + return identifier; +} + ++ (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath withObject:(MessageModel *)model +{ + return HEAD_SIZE + CELLPADDING; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewCell.h b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewCell.h new file mode 100644 index 0000000..c08959b --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewCell.h @@ -0,0 +1,35 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatViewBaseCell.h" + +#import "EMChatTextBubbleView.h" +#import "EMChatImageBubbleView.h" +#import "EMChatAudioBubbleView.h" +#import "EMChatVideoBubbleView.h" +#import "EMChatLocationBubbleView.h" + +#define SEND_STATUS_SIZE 20 // 发送状态View的Size +#define ACTIVTIYVIEW_BUBBLE_PADDING 5 // 菊花和bubbleView之间的间距 + +extern NSString *const kResendButtonTapEventName; +extern NSString *const kShouldResendCell; + +@interface EMChatViewCell : EMChatViewBaseCell + +//sender +@property (nonatomic, strong) UIActivityIndicatorView *activtiy; +@property (nonatomic, strong) UIView *activityView; +@property (nonatomic, strong) UIButton *retryButton; +@property (nonatomic, strong) UILabel *hasRead; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewCell.m b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewCell.m new file mode 100644 index 0000000..2f1e496 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatCell/EMChatViewCell.m @@ -0,0 +1,262 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "EMChatViewCell.h" +#import "EMChatVideoBubbleView.h" +#import "UIResponder+Router.h" + +NSString *const kResendButtonTapEventName = @"kResendButtonTapEventName"; +NSString *const kShouldResendCell = @"kShouldResendCell"; + +@implementation EMChatViewCell + +- (id)initWithMessageModel:(MessageModel *)model reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithMessageModel:model reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + self.headImageView.clipsToBounds = YES; + self.headImageView.layer.cornerRadius = 3.0; + } + return self; +} + +- (BOOL)canBecomeFirstResponder +{ + return YES; +} + +-(void)layoutSubviews +{ + [super layoutSubviews]; + + CGRect bubbleFrame = _bubbleView.frame; + bubbleFrame.origin.y = self.headImageView.frame.origin.y; + + if (self.messageModel.isSender) { + bubbleFrame.origin.y = self.headImageView.frame.origin.y; + // 菊花状态 (因不确定菊花具体位置,要在子类中实现位置的修改) + _hasRead.hidden = YES; + switch (self.messageModel.status) { + case eMessageDeliveryState_Delivering: + { + [_activityView setHidden:NO]; + [_retryButton setHidden:YES]; + [_activtiy setHidden:NO]; + [_activtiy startAnimating]; + } + break; + case eMessageDeliveryState_Delivered: + { + [_activtiy stopAnimating]; + [_retryButton setHidden:YES]; + if (self.messageModel.message.isReadAcked) + { + _activityView.hidden = NO; + _hasRead.hidden = NO; + } + else + { + [_activityView setHidden:YES]; + } + } + break; + case eMessageDeliveryState_Pending: + case eMessageDeliveryState_Failure: + { + [_activityView setHidden:NO]; + [_activtiy stopAnimating]; + [_activtiy setHidden:YES]; + [_retryButton setHidden:NO]; + } + break; + default: + break; + } + + bubbleFrame.origin.x = self.headImageView.frame.origin.x - bubbleFrame.size.width - HEAD_PADDING; + _bubbleView.frame = bubbleFrame; + + CGRect frame = self.activityView.frame; + if (_hasRead.hidden) + { + frame.size.width = SEND_STATUS_SIZE; + } + else + { + frame.size.width = _hasRead.frame.size.width; + } + frame.origin.x = bubbleFrame.origin.x - frame.size.width - ACTIVTIYVIEW_BUBBLE_PADDING; + frame.origin.y = _bubbleView.center.y - frame.size.height / 2; + self.activityView.frame = frame; + } + else{ + bubbleFrame.origin.x = HEAD_PADDING * 2 + HEAD_SIZE; + if (self.messageModel.messageType != eMessageTypeChat) { + bubbleFrame.origin.y = NAME_LABEL_HEIGHT + NAME_LABEL_PADDING; + } + _bubbleView.frame = bubbleFrame; + } +} + +- (void)setMessageModel:(MessageModel *)model +{ + [super setMessageModel:model]; + + if (model.messageType != eMessageTypeChat) { + _nameLabel.text = model.nickName; + _nameLabel.hidden = model.isSender; + } + + _bubbleView.model = self.messageModel; + [_bubbleView sizeToFit]; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +#pragma mark - action + +// 重发按钮事件 +-(void)retryButtonPressed:(UIButton *)sender +{ + [self routerEventWithName:kResendButtonTapEventName + userInfo:@{kShouldResendCell:self}]; +} + +#pragma mark - private + +- (void)setupSubviewsForMessageModel:(MessageModel *)messageModel +{ + [super setupSubviewsForMessageModel:messageModel]; + + if (messageModel.isSender) { + // 发送进度显示view + _activityView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SEND_STATUS_SIZE, SEND_STATUS_SIZE)]; + [_activityView setHidden:YES]; + [self.contentView addSubview:_activityView]; + + // 重发按钮 + _retryButton = [UIButton buttonWithType:UIButtonTypeSystem]; + _retryButton.frame = CGRectMake(0, 0, SEND_STATUS_SIZE, SEND_STATUS_SIZE); + [_retryButton addTarget:self action:@selector(retryButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; +// [_retryButton setImage:[UIImage imageNamed:@"messageSendFail.png"] forState:UIControlStateNormal]; + [_retryButton setBackgroundImage:[UIImage imageNamed:@"messageSendFail.png"] forState:UIControlStateNormal]; + //[_retryButton setBackgroundColor:[UIColor redColor]]; + [_activityView addSubview:_retryButton]; + + // 菊花 + _activtiy = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + _activtiy.backgroundColor = [UIColor clearColor]; + [_activityView addSubview:_activtiy]; + + //已读 + _hasRead = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, SEND_STATUS_SIZE, SEND_STATUS_SIZE)]; + _hasRead.text = @"已读"; + _hasRead.textAlignment = NSTextAlignmentCenter; + _hasRead.font = [UIFont systemFontOfSize:12]; + [_hasRead sizeToFit]; + [_activityView addSubview:_hasRead]; + } + + _bubbleView = [self bubbleViewForMessageModel:messageModel]; + [self.contentView addSubview:_bubbleView]; +} + +- (EMChatBaseBubbleView *)bubbleViewForMessageModel:(MessageModel *)messageModel +{ + switch (messageModel.type) { + case eMessageBodyType_Text: + { + return [[EMChatTextBubbleView alloc] init]; + } + break; + case eMessageBodyType_Image: + { + return [[EMChatImageBubbleView alloc] init]; + } + break; + case eMessageBodyType_Voice: + { + return [[EMChatAudioBubbleView alloc] init]; + } + break; + case eMessageBodyType_Location: + { + return [[EMChatLocationBubbleView alloc] init]; + } + break; + case eMessageBodyType_Video: + { + return [[EMChatVideoBubbleView alloc] init]; + } + break; + default: + break; + } + + return nil; +} + ++ (CGFloat)bubbleViewHeightForMessageModel:(MessageModel *)messageModel +{ + switch (messageModel.type) { + case eMessageBodyType_Text: + { + return [EMChatTextBubbleView heightForBubbleWithObject:messageModel]; + } + break; + case eMessageBodyType_Image: + { + return [EMChatImageBubbleView heightForBubbleWithObject:messageModel]; + } + break; + case eMessageBodyType_Voice: + { + return [EMChatAudioBubbleView heightForBubbleWithObject:messageModel]; + } + break; + case eMessageBodyType_Location: + { + return [EMChatLocationBubbleView heightForBubbleWithObject:messageModel]; + } + break; + case eMessageBodyType_Video: + { + return [EMChatVideoBubbleView heightForBubbleWithObject:messageModel]; + } + break; + default: + break; + } + + return HEAD_SIZE; +} + +#pragma mark - public + ++ (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath withObject:(MessageModel *)model +{ + NSInteger bubbleHeight = [self bubbleViewHeightForMessageModel:model]; + NSInteger headHeight = HEAD_PADDING * 2 + HEAD_SIZE; + if ((model.messageType != eMessageTypeChat) && !model.isSender) { + headHeight += NAME_LABEL_HEIGHT; + } + return MAX(headHeight, bubbleHeight + NAME_LABEL_HEIGHT + NAME_LABEL_PADDING) + CELLPADDING; +} + + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatMainViewController.h b/Ash_AWord/ViewControllers/Chat/ChatMainViewController.h new file mode 100644 index 0000000..e5d016c --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatMainViewController.h @@ -0,0 +1,18 @@ +// +// ChatMainViewController.h +// Ash_AWord +// +// Created by xmfish on 15/6/18. +// Copyright (c) 2015年 ash. All rights reserved. +// + +#import +#import "MessageTableView.h" +@interface ChatMainViewController : UIViewController +@property (weak, nonatomic) IBOutlet MessageTableView *tableView; +@property (weak, nonatomic) IBOutlet UIView *toolView; + +@property (strong, nonatomic)NSString* otherUserName; +@property (strong, nonatomic)NSString* otherUserAvatar; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatMainViewController.m b/Ash_AWord/ViewControllers/Chat/ChatMainViewController.m new file mode 100644 index 0000000..269a9a5 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatMainViewController.m @@ -0,0 +1,1041 @@ +// +// ChatMainViewController.m +// Ash_AWord +// +// Created by xmfish on 15/6/18. +// Copyright (c) 2015年 ash. All rights reserved. +// + +#import "ChatMainViewController.h" +#import "DXMessageToolBar.h" +#import "DXChatBarMoreView.h" +#import +#import +#import "EMCDDeviceManager.h" +#import "EMChatVoice.h" +#import "EMChatVideo.h" +#import "LocationViewController.h" +#import "CallViewController.h" +#import "EaseMob.h" +#import "ChatSendHelper.h" +#import "EMChatTimeCell.h" +#import "MessageViewModel.h" +#import "MessageModel.h" +#import "EMChatViewCell.h" +#import "NSDate+Category.h" +#import "MessageModelManager.h" +#import "NSDateFormatter+Category.h" +#import "MessageReadManager.h" +#define KPageCount 20 + +@interface ChatMainViewController () +{ + DXMessageToolBar *_chatToolBar; + NSMutableArray* _dataSource; + NSMutableArray *_messages; + dispatch_queue_t _messageQueue; + NSDate *_chatTagDate; + +} +@property (strong, nonatomic) EMConversation *conversation;//会话管理者 +@property (strong, nonatomic) MessageReadManager *messageReadManager;//message阅读的管理者 + +@end + +@implementation ChatMainViewController +- (MessageReadManager *)messageReadManager +{ + if (_messageReadManager == nil) { + _messageReadManager = [MessageReadManager defaultManager]; + } + + return _messageReadManager; +} + +- (instancetype)initWithChatter:(NSString *)chatter conversationType:(EMConversationType)type +{ + self = [super initWithNibName:nil bundle:nil]; + if (self) { +// _isPlayingAudio = NO; +// _chatter = chatter; +// _conversationType = type; + _messages = [NSMutableArray array]; + + //根据接收者的username获取当前会话的管理者 + _conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:chatter + conversationType:type]; + [_conversation markAllMessagesAsRead:YES]; + } + + return self; +} +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view from its nib. + _tableView.dataSource = self; + _tableView.delegate = self; + _dataSource = [NSMutableArray array]; + _messages = [NSMutableArray array]; + _messageQueue = dispatch_queue_create("easemob.com", NULL); + + self.navigationItem.title = _otherUserName; + + //根据接收者的username获取当前会话的管理者 + _conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:@"admin" conversationType:eConversationTypeChat]; + [_conversation markAllMessagesAsRead:YES]; + + _chatToolBar = [[DXMessageToolBar alloc] initWithFrame:CGRectMake(0, kScreenHeight-[DXMessageToolBar defaultHeight], kScreenWidth, [DXMessageToolBar defaultHeight])]; + _chatToolBar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin; + _chatToolBar.delegate = self; + + ChatMoreType type = ChatMoreTypeChat; + DXChatBarMoreView* dxChatBarMoreView = [[DXChatBarMoreView alloc] initWithFrame:CGRectMake(0, (kVerticalPadding * 2 + kInputTextViewMinHeight), _chatToolBar.frame.size.width, 80) typw:type]; + dxChatBarMoreView.delegate = self; + _chatToolBar.moreView = dxChatBarMoreView; + _chatToolBar.moreView.backgroundColor = [UIColor colorWithRed:240.0/255.0 green:242.0/255.0 blue:247.0/255.0 alpha:1.0]; + _chatToolBar.moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; + [self.view addSubview:_chatToolBar]; + + +#warning 以下三行代码必须写,注册为SDK的ChatManager的delegate + [EMCDDeviceManager sharedInstance].delegate = self; + [[EaseMob sharedInstance].chatManager removeDelegate:self]; + //注册为SDK的ChatManager的delegate + [[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil]; + + [[EaseMob sharedInstance].callManager removeDelegate:self]; + // 注册为Call的Delegate + [[EaseMob sharedInstance].callManager addDelegate:self delegateQueue:nil]; + + + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(keyBoardHidden)]; + [self.view addGestureRecognizer:tap]; + + //通过会话管理者获取已收发消息 + [self loadMoreMessages]; +} + +#pragma mark - DXMessageToolBarDelegate +- (void)inputTextViewWillBeginEditing:(XHMessageTextView *)messageInputTextView{ +} + +- (void)didChangeFrameToHeight:(CGFloat)toHeight +{ + [UIView animateWithDuration:0.3 animations:^{ + CGRect rect = self.tableView.frame; + rect.origin.y = 0; + rect.size.height = self.view.frame.size.height - toHeight; + self.tableView.frame = rect; + }]; + [self scrollViewToBottom:NO]; +} +- (void)scrollViewToBottom:(BOOL)animated +{ + if (self.tableView.contentSize.height > self.tableView.frame.size.height) + { + CGPoint offset = CGPointMake(0, self.tableView.contentSize.height - self.tableView.frame.size.height); + [self.tableView setContentOffset:offset animated:animated]; + } +} + +- (void)didSendText:(NSString *)text +{ + if (text && text.length > 0) { + [self sendTextMessage:text]; + } +} + +/** + * 按下录音按钮开始录音 + */ +#pragma mark - private + +- (BOOL)canRecord +{ + __block BOOL bCanRecord = YES; + if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending) + { + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + if ([audioSession respondsToSelector:@selector(requestRecordPermission:)]) { + [audioSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) { + bCanRecord = granted; + }]; + } + } + + return bCanRecord; +} +- (void)didStartRecordingVoiceAction:(UIView *)recordView +{ + if ([self canRecord]) { + DXRecordView *tmpView = (DXRecordView *)recordView; + tmpView.center = self.view.center; + [self.view addSubview:tmpView]; + [self.view bringSubviewToFront:recordView]; + int x = arc4random() % 100000; + NSTimeInterval time = [[NSDate date] timeIntervalSince1970]; + NSString *fileName = [NSString stringWithFormat:@"%d%d",(int)time,x]; + + [[EMCDDeviceManager sharedInstance] asyncStartRecordingWithFileName:fileName + completion:^(NSError *error) + { + if (error) { + NSLog(NSLocalizedString(@"message.startRecordFail", @"failure to start recording")); + } + }]; + } +} + +/** + * 手指向上滑动取消录音 + */ +- (void)didCancelRecordingVoiceAction:(UIView *)recordView +{ + [[EMCDDeviceManager sharedInstance] cancelCurrentRecording]; +} + +/** + * 松开手指完成录音 + */ +- (void)didFinishRecoingVoiceAction:(UIView *)recordView +{ + __weak typeof(self) weakSelf = self; + [[EMCDDeviceManager sharedInstance] asyncStopRecordingWithCompletion:^(NSString *recordPath, NSInteger aDuration, NSError *error) { + if (!error) { + EMChatVoice *voice = [[EMChatVoice alloc] initWithFile:recordPath + displayName:@"audio"]; + voice.duration = aDuration; +// [weakSelf sendAudioMessage:voice]; + }else { +// [weakSelf showHudInView:self.view hint:@"录音时间太短了"]; + _chatToolBar.recordButton.enabled = NO; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ +// [weakSelf hideHud]; + _chatToolBar.recordButton.enabled = YES; + }); + } + }]; +} + + +#pragma mark - UIImagePickerControllerDelegate + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + NSString *mediaType = info[UIImagePickerControllerMediaType]; + if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) { + NSURL *videoURL = info[UIImagePickerControllerMediaURL]; + [picker dismissViewControllerAnimated:YES completion:^{ + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"isShowPicker"]; + }]; + // video url: + // file:///private/var/mobile/Applications/B3CDD0B2-2F19-432B-9CFA-158700F4DE8F/tmp/capture-T0x16e39100.tmp.9R8weF/capturedvideo.mp4 + // we will convert it to mp4 format + NSURL *mp4 = [self convert2Mp4:videoURL]; + NSFileManager *fileman = [NSFileManager defaultManager]; + if ([fileman fileExistsAtPath:videoURL.path]) { + NSError *error = nil; + [fileman removeItemAtURL:videoURL error:&error]; + if (error) { + NSLog(@"failed to remove file, error:%@.", error); + } + } + EMChatVideo *chatVideo = [[EMChatVideo alloc] initWithFile:[mp4 relativePath] displayName:@"video.mp4"]; +// [self sendVideoMessage:chatVideo]; + + }else{ + UIImage *orgImage = info[UIImagePickerControllerOriginalImage]; + [picker dismissViewControllerAnimated:YES completion:^{ + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"isShowPicker"]; + }]; +// [self sendImageMessage:orgImage]; + } +// self.isInvisible = NO; +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"isShowPicker"]; + [picker dismissViewControllerAnimated:YES completion:nil]; +// self.isInvisible = NO; +} + +#pragma mark - EMChatBarMoreViewDelegate + +- (void)moreViewPhotoAction:(DXChatBarMoreView *)moreView +{ + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"isShowPicker"]; + // 隐藏键盘 + [self keyBoardHidden]; + + // 弹出照片选择 + + UIImagePickerController* picker = [[UIImagePickerController alloc] init]; + // picker.allowsEditing = YES; + picker.delegate = self; + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:picker animated:YES completion:nil]; + +} +// 点击背景隐藏 +-(void)keyBoardHidden +{ + [_chatToolBar endEditing:YES]; +} + +- (void)moreViewTakePicAction:(DXChatBarMoreView *)moreView +{ + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"isShowPicker"]; + [self keyBoardHidden]; + +#if TARGET_IPHONE_SIMULATOR +// [self showHint:NSLocalizedString(@"message.simulatorNotSupportCamera", @"simulator does not support taking picture")]; +#elif TARGET_OS_IPHONE + UIImagePickerController* picker = [[UIImagePickerController alloc] init]; + // picker.allowsEditing = YES; + picker.delegate = self; + picker.sourceType = UIImagePickerControllerSourceTypeCamera; + [self presentViewController:picker animated:YES completion:nil]; +#endif +} + +- (void)moreViewLocationAction:(DXChatBarMoreView *)moreView +{ + // 隐藏键盘 + [self keyBoardHidden]; + + LocationViewController *locationController = [[LocationViewController alloc] initWithNibName:nil bundle:nil]; + locationController.delegate = self; + [self.navigationController pushViewController:locationController animated:YES]; +} + +- (void)moreViewAudioCallAction:(DXChatBarMoreView *)moreView +{ + // 隐藏键盘 + [self keyBoardHidden]; +// [[NSNotificationCenter defaultCenter] postNotificationName:@"callOutWithChatter" object:@{@"chatter":self.chatter, @"type":[NSNumber numberWithInt:eCallSessionTypeAudio]}]; + + EMCallSession *callSession = nil; + EMError *error = nil; + + callSession = [[EaseMob sharedInstance].callManager asyncMakeVoiceCall:_conversation.chatter timeout:50 error:&error]; + + + CallViewController *callController = [[CallViewController alloc] initWithSession:callSession isIncoming:NO]; + callController.modalPresentationStyle = UIModalPresentationOverFullScreen; + [self presentViewController:callController animated:NO completion:nil]; +} + +- (void)moreViewVideoCallAction:(DXChatBarMoreView *)moreView +{ + // 隐藏键盘 + [self keyBoardHidden]; + EMCallSession *callSession = nil; + EMError *error = nil; + + if (![CallViewController canVideo]) { + return; + } + callSession = [[EaseMob sharedInstance].callManager asyncMakeVideoCall:_conversation.chatter timeout:50 error:&error]; + + + CallViewController *callController = [[CallViewController alloc] initWithSession:callSession isIncoming:NO]; + callController.modalPresentationStyle = UIModalPresentationOverFullScreen; + [self presentViewController:callController animated:NO completion:nil]; +} + +#pragma mark - helper +- (NSURL *)convert2Mp4:(NSURL *)movUrl { + NSURL *mp4Url = nil; + AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:movUrl options:nil]; + NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset]; + + if ([compatiblePresets containsObject:AVAssetExportPresetHighestQuality]) { + AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset + presetName:AVAssetExportPresetHighestQuality]; + mp4Url = [movUrl copy]; + mp4Url = [mp4Url URLByDeletingPathExtension]; + mp4Url = [mp4Url URLByAppendingPathExtension:@"mp4"]; + exportSession.outputURL = mp4Url; + exportSession.shouldOptimizeForNetworkUse = YES; + exportSession.outputFileType = AVFileTypeMPEG4; + dispatch_semaphore_t wait = dispatch_semaphore_create(0l); + [exportSession exportAsynchronouslyWithCompletionHandler:^{ + switch ([exportSession status]) { + case AVAssetExportSessionStatusFailed: { + NSLog(@"failed, error:%@.", exportSession.error); + } break; + case AVAssetExportSessionStatusCancelled: { + NSLog(@"cancelled."); + } break; + case AVAssetExportSessionStatusCompleted: { + NSLog(@"completed."); + } break; + default: { + NSLog(@"others."); + } break; + } + dispatch_semaphore_signal(wait); + }]; + long timeout = dispatch_semaphore_wait(wait, DISPATCH_TIME_FOREVER); + if (timeout) { + NSLog(@"timeout."); + } + if (wait) { + //dispatch_release(wait); + wait = nil; + } + } + + return mp4Url; +} + +#pragma mark UITableViewDelegate +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return _dataSource.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (indexPath.row < [_dataSource count]) { + id obj = [_dataSource objectAtIndex:indexPath.row]; + if ([obj isKindOfClass:[NSString class]]) { + EMChatTimeCell *timeCell = (EMChatTimeCell *)[tableView dequeueReusableCellWithIdentifier:@"MessageCellTime"]; + if (timeCell == nil) { + timeCell = [[EMChatTimeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MessageCellTime"]; + timeCell.backgroundColor = [UIColor clearColor]; + timeCell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + timeCell.textLabel.text = (NSString *)obj; + + return timeCell; + } + else{ + MessageModel *model = (MessageModel *)obj; + NSString *cellIdentifier = [EMChatViewCell cellIdentifierForMessageModel:model]; + EMChatViewCell *cell = (EMChatViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier]; + if (cell == nil) { + cell = [[EMChatViewCell alloc] initWithMessageModel:model reuseIdentifier:cellIdentifier]; + cell.backgroundColor = [UIColor clearColor]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + cell.messageModel = model; + + return cell; + } + } + + return nil; +} + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSObject *obj = [_dataSource objectAtIndex:indexPath.row]; + if ([obj isKindOfClass:[NSString class]]) { + return 40; + } + else{ + return [EMChatViewCell tableView:tableView heightForRowAtIndexPath:indexPath withObject:(MessageModel *)obj]; + } +} + +-(void)scrollViewDidScroll:(UIScrollView *)scrollView{ +// if (scrollView == _tableView) { +// [self.view endEditing:YES]; +// } +} + +#pragma mark - send message + +-(void)sendTextMessage:(NSString *)textMessage +{ + EMMessage *tempMessage = [ChatSendHelper sendTextMessageWithString:textMessage + toUsername:_conversation.chatter + messageType:eMessageTypeChat + requireEncryption:NO + ext:nil]; + [self addMessage:tempMessage]; +} +-(void)addMessage:(EMMessage *)message +{ + [_messages addObject:message]; + __weak ChatMainViewController *weakSelf = self; + dispatch_async(_messageQueue, ^{ + NSArray *messages = [weakSelf formatMessage:message]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [_dataSource addObjectsFromArray:messages]; + [weakSelf.tableView reloadData]; + [weakSelf.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[_dataSource count] - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; + }); + }); +} +-(NSMutableArray *)formatMessage:(EMMessage *)message +{ + NSMutableArray *ret = [[NSMutableArray alloc] init]; + NSDate *createDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp]; + NSTimeInterval tempDate = [createDate timeIntervalSinceDate:_chatTagDate]; + if (tempDate > 60 || tempDate < -60 || (_chatTagDate == nil)) { + [ret addObject:[createDate formattedTime]]; + _chatTagDate = createDate; + } + + MessageModel *model = [MessageModelManager modelWithMessage:message]; + model.nickName = @"haha"; +// if ([_delelgate respondsToSelector:@selector(nickNameWithChatter:)]) { +// NSString *showName = [_delelgate nickNameWithChatter:model.username]; +// model.nickName = showName?showName:model.username; +// }else { +// model.nickName = model.username; +// } + +// if ([_delelgate respondsToSelector:@selector(avatarWithChatter:)]) { +// model.headImageURL = [NSURL URLWithString:[_delelgate avatarWithChatter:model.username]]; +// } + if (model.isSender){ + model.headImageURL = [NSURL URLWithString:[AWordUser sharedInstance].userAvatar]; + }else{ + model.headImageURL = [NSURL URLWithString:_otherUserAvatar]; + } + + if (model) { + [ret addObject:model]; + } + + return ret; +} + + +#pragma mark - IChatManagerDelegate + +-(void)didSendMessage:(EMMessage *)message error:(EMError *)error +{ + [_dataSource enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) + { + if ([obj isKindOfClass:[MessageModel class]]) + { + MessageModel *model = (MessageModel*)obj; + if ([model.messageId isEqualToString:message.messageId]) + { + model.message.deliveryState = message.deliveryState; + *stop = YES; + } + } + }]; + [self.tableView reloadData]; +} + +- (void)reloadTableViewDataWithMessage:(EMMessage *)message{ + __weak ChatMainViewController *weakSelf = self; + dispatch_async(_messageQueue, ^{ + if ([_conversation.chatter isEqualToString:message.conversationChatter]) + { + for (int i = 0; i < _dataSource.count; i ++) { + id object = [_dataSource objectAtIndex:i]; + if ([object isKindOfClass:[MessageModel class]]) { + MessageModel *model = (MessageModel *)object; + if ([message.messageId isEqualToString:model.messageId]) { + MessageModel *cellModel = [MessageModelManager modelWithMessage:message]; + cellModel.nickName = cellModel.username; + + if (cellModel.isSender){ + cellModel.headImageURL = [NSURL URLWithString:[AWordUser sharedInstance].userAvatar]; + }else{ + cellModel.headImageURL = [NSURL URLWithString:_otherUserAvatar]; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.tableView beginUpdates]; + [_dataSource replaceObjectAtIndex:i withObject:cellModel]; + [weakSelf.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; + [weakSelf.tableView endUpdates]; + }); + break; + } + } + } + } + }); +} + +-(void)didReceiveMessage:(EMMessage *)message +{ + if ([_conversation.chatter isEqualToString:message.conversationChatter]) { + [self addMessage:message]; + if ([self shouldAckMessage:message read:NO]) + { + [self sendHasReadResponseForMessages:@[message]]; + } + if ([self shouldMarkMessageAsRead]) + { + [self markMessagesAsRead:@[message]]; + } + } +} +- (void)didReceiveMessageId:(NSString *)messageId + chatter:(NSString *)conversationChatter + error:(EMError *)error +{ + +} + +- (NSArray *)formatMessages:(NSArray *)messagesArray +{ + NSMutableArray *formatArray = [[NSMutableArray alloc] init]; + if ([messagesArray count] > 0) { + for (EMMessage *message in messagesArray) { + NSDate *createDate = [NSDate dateWithTimeIntervalInMilliSecondSince1970:(NSTimeInterval)message.timestamp]; + NSTimeInterval tempDate = [createDate timeIntervalSinceDate:_chatTagDate]; + if (tempDate > 60 || tempDate < -60 || (_chatTagDate == nil)) { + [formatArray addObject:[createDate formattedTime]]; + _chatTagDate = createDate; + } + + MessageModel *model = [MessageModelManager modelWithMessage:message]; + model.nickName = model.username; + + if (model.isSender){ + model.headImageURL = [NSURL URLWithString:[AWordUser sharedInstance].userAvatar]; + }else{ + model.headImageURL = [NSURL URLWithString:_otherUserAvatar]; + } + + if (model) { + [formatArray addObject:model]; + } + } + } + + return formatArray; +} + +- (void)downloadMessageAttachments:(MessageModel *)model +{ + void (^completion)(EMMessage *aMessage, EMError *error) = ^(EMMessage *aMessage, EMError *error) { + if (!error) + { + [self reloadTableViewDataWithMessage:model.message]; + } + else + { +// [self showHint:NSLocalizedString(@"message.thumImageFail", @"thumbnail for failure!")]; + } + }; + + if ([model.messageBody messageBodyType] == eMessageBodyType_Image) { + EMImageMessageBody *imageBody = (EMImageMessageBody *)model.messageBody; + if (imageBody.thumbnailDownloadStatus != EMAttachmentDownloadSuccessed) + { + //下载缩略图 + [[[EaseMob sharedInstance] chatManager] asyncFetchMessageThumbnail:model.message progress:nil completion:completion onQueue:nil]; + } + } + else if ([model.messageBody messageBodyType] == eMessageBodyType_Video) + { + EMVideoMessageBody *videoBody = (EMVideoMessageBody *)model.messageBody; + if (videoBody.thumbnailDownloadStatus != EMAttachmentDownloadSuccessed) + { + //下载缩略图 + [[[EaseMob sharedInstance] chatManager] asyncFetchMessageThumbnail:model.message progress:nil completion:completion onQueue:nil]; + } + } + else if ([model.messageBody messageBodyType] == eMessageBodyType_Voice) + { + EMVoiceMessageBody *voiceBody = (EMVoiceMessageBody*)model.messageBody; + if (voiceBody.attachmentDownloadStatus != EMAttachmentDownloadSuccessed) + { + //下载语言 + [[EaseMob sharedInstance].chatManager asyncFetchMessage:model.message progress:nil]; + } + } +} +- (void)didMessageAttachmentsStatusChanged:(EMMessage *)message error:(EMError *)error{ + if (!error) { + idfileBody = (id)[message.messageBodies firstObject]; + if ([fileBody messageBodyType] == eMessageBodyType_Image) { + EMImageMessageBody *imageBody = (EMImageMessageBody *)fileBody; + if ([imageBody thumbnailDownloadStatus] == EMAttachmentDownloadSuccessed) + { + [self reloadTableViewDataWithMessage:message]; + } + }else if([fileBody messageBodyType] == eMessageBodyType_Video){ + EMVideoMessageBody *videoBody = (EMVideoMessageBody *)fileBody; + if ([videoBody thumbnailDownloadStatus] == EMAttachmentDownloadSuccessed) + { + [self reloadTableViewDataWithMessage:message]; + } + }else if([fileBody messageBodyType] == eMessageBodyType_Voice){ + if ([fileBody attachmentDownloadStatus] == EMAttachmentDownloadSuccessed) + { + [self reloadTableViewDataWithMessage:message]; + } + } + + }else{ + + } +} + +- (void)didFetchingMessageAttachments:(EMMessage *)message progress:(float)progress{ + NSLog(@"didFetchingMessageAttachment: %f", progress); +} +- (void)loadMoreMessages +{ + __weak typeof(self) weakSelf = self; + dispatch_async(_messageQueue, ^{ + long long timestamp = [[NSDate date] timeIntervalSince1970] * 1000 + 1; + + NSArray *messages = [weakSelf.conversation loadNumbersOfMessages:([_messages count] + KPageCount) before:timestamp]; + if ([messages count] > 0) { + _messages = [messages mutableCopy]; + + NSInteger currentCount = [_dataSource count]; + _dataSource = [[weakSelf formatMessages:messages] mutableCopy]; + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.tableView reloadData]; + + [weakSelf.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[_dataSource count] - currentCount - 1 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO]; + }); + + //从数据库导入时重新下载没有下载成功的附件 + for (NSInteger i = 0; i < [_dataSource count]; i++) + { + id obj = _dataSource[i]; + if ([obj isKindOfClass:[MessageModel class]]) + { + [weakSelf downloadMessageAttachments:obj]; + } + } + + NSMutableArray *unreadMessages = [NSMutableArray array]; + for (NSInteger i = 0; i < [messages count]; i++) + { + EMMessage *message = messages[i]; + if ([self shouldAckMessage:message read:NO]) + { + [unreadMessages addObject:message]; + } + } + if ([unreadMessages count]) + { + [self sendHasReadResponseForMessages:unreadMessages]; + } + } + }); +} +- (BOOL)shouldAckMessage:(EMMessage *)message read:(BOOL)read +{ + NSString *account = [[EaseMob sharedInstance].chatManager loginInfo][kSDKUsername]; + if (message.messageType != eMessageTypeChat || message.isReadAcked || [account isEqualToString:message.from] || ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) ) + { + return NO; + } + + id body = [message.messageBodies firstObject]; + if (((body.messageBodyType == eMessageBodyType_Video) || + (body.messageBodyType == eMessageBodyType_Voice) || + (body.messageBodyType == eMessageBodyType_Image)) && + !read) + { + return NO; + } + else + { + return YES; + } +} + +- (BOOL)shouldMarkMessageAsRead +{ + if (([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)) + { + return NO; + } + + return YES; +} +- (void)sendHasReadResponseForMessages:(NSArray*)messages +{ + dispatch_async(_messageQueue, ^{ + for (EMMessage *message in messages) + { + [[EaseMob sharedInstance].chatManager sendReadAckForMessage:message]; + } + }); +} +- (void)markMessagesAsRead:(NSArray*)messages +{ + EMConversation *conversation = _conversation; + dispatch_async(_messageQueue, ^{ + for (EMMessage *message in messages) + { + [conversation markMessageWithId:message.messageId asRead:YES]; + } + }); +} + +#pragma mark - UIResponder actions + +- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo +{ + MessageModel *model = [userInfo objectForKey:KMESSAGEKEY]; + if ([eventName isEqualToString:kRouterEventTextURLTapEventName]) { + [self chatTextCellUrlPressed:[userInfo objectForKey:@"url"]]; + } + else if ([eventName isEqualToString:kRouterEventAudioBubbleTapEventName]) { + [self chatAudioCellBubblePressed:model]; + } + else if ([eventName isEqualToString:kRouterEventImageBubbleTapEventName]){ + [self chatImageCellBubblePressed:model]; + } + else if ([eventName isEqualToString:kRouterEventLocationBubbleTapEventName]){ + [self chatLocationCellBubblePressed:model]; + } + else if([eventName isEqualToString:kResendButtonTapEventName]){ + EMChatViewCell *resendCell = [userInfo objectForKey:kShouldResendCell]; + MessageModel *messageModel = resendCell.messageModel; + if ((messageModel.status != eMessageDeliveryState_Failure) && (messageModel.status != eMessageDeliveryState_Pending)) + { + return; + } + id chatManager = [[EaseMob sharedInstance] chatManager]; + [chatManager asyncResendMessage:messageModel.message progress:nil]; + NSIndexPath *indexPath = [self.tableView indexPathForCell:resendCell]; + [self.tableView beginUpdates]; + [self.tableView reloadRowsAtIndexPaths:@[indexPath] + withRowAnimation:UITableViewRowAnimationNone]; + [self.tableView endUpdates]; + }else if([eventName isEqualToString:kRouterEventChatCellVideoTapEventName]){ + [self chatVideoCellPressed:model]; + } +} + +//链接被点击 +- (void)chatTextCellUrlPressed:(NSURL *)url +{ + if (url) { + [[UIApplication sharedApplication] openURL:url]; + } +} + +// 语音的bubble被点击 +-(void)chatAudioCellBubblePressed:(MessageModel *)model +{ + id body = [model.message.messageBodies firstObject]; + EMAttachmentDownloadStatus downloadStatus = [body attachmentDownloadStatus]; + if (downloadStatus == EMAttachmentDownloading) { +// [self showHint:NSLocalizedString(@"message.downloadingAudio", @"downloading voice, click later")]; + [MBProgressHUD checkHudWithView:self.view label:NSLocalizedString(@"message.downloadingAudio", @"downloading voice, click later") hidesAfter:1.0]; + return; + } + else if (downloadStatus == EMAttachmentDownloadFailure) + { + [MBProgressHUD checkHudWithView:self.view label:NSLocalizedString(@"message.downloadingAudio", @"downloading voice, click later") hidesAfter:1.0]; + + [[EaseMob sharedInstance].chatManager asyncFetchMessage:model.message progress:nil]; + + return; + } + + // 播放音频 + if (model.type == eMessageBodyType_Voice) { + //发送已读回执 + if ([self shouldAckMessage:model.message read:YES]) + { + [self sendHasReadResponseForMessages:@[model.message]]; + } + __weak ChatMainViewController *weakSelf = self; + BOOL isPrepare = [self.messageReadManager prepareMessageAudioModel:model updateViewCompletion:^(MessageModel *prevAudioModel, MessageModel *currentAudioModel) { + if (prevAudioModel || currentAudioModel) { + [weakSelf.tableView reloadData]; + } + }]; + + if (isPrepare) { +// _isPlayingAudio = YES; + __weak ChatMainViewController *weakSelf = self; + [[EMCDDeviceManager sharedInstance] enableProximitySensor]; + [[EMCDDeviceManager sharedInstance] asyncPlayingWithPath:model.chatVoice.localPath completion:^(NSError *error) { + [weakSelf.messageReadManager stopMessageAudioModel]; + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.tableView reloadData]; +// weakSelf.isPlayingAudio = NO; + [[EMCDDeviceManager sharedInstance] disableProximitySensor]; + }); + }]; + } + else{ +// _isPlayingAudio = NO; + } + } +} + +// 位置的bubble被点击 +-(void)chatLocationCellBubblePressed:(MessageModel *)model +{ +// _isScrollToBottom = NO; + LocationViewController *locationController = [[LocationViewController alloc] initWithLocation:CLLocationCoordinate2DMake(model.latitude, model.longitude)]; + [self.navigationController pushViewController:locationController animated:YES]; +} + +- (void)chatVideoCellPressed:(MessageModel *)model{ + EMVideoMessageBody *videoBody = (EMVideoMessageBody*)model.messageBody; + if (videoBody.attachmentDownloadStatus == EMAttachmentDownloadSuccessed) + { + NSString *localPath = model.message == nil ? model.localPath : [[model.message.messageBodies firstObject] localPath]; + if (localPath && localPath.length > 0) + { + //发送已读回执 + if ([self shouldAckMessage:model.message read:YES]) + { + [self sendHasReadResponseForMessages:@[model.message]]; + } + [self playVideoWithVideoPath:localPath]; + return; + } + } + + __weak ChatMainViewController *weakSelf = self; + id chatManager = [[EaseMob sharedInstance] chatManager]; + [MBProgressHUD hudWithView:self.view label:NSLocalizedString(@"message.downloadingVideo", @"downloading video...")]; + [chatManager asyncFetchMessage:model.message progress:nil completion:^(EMMessage *aMessage, EMError *error) { + [MBProgressHUD hideAllHUDsForView:self.view animated:YES]; + if (!error) { + //发送已读回执 + if ([weakSelf shouldAckMessage:model.message read:YES]) + { + [weakSelf sendHasReadResponseForMessages:@[model.message]]; + } + NSString *localPath = aMessage == nil ? model.localPath : [[aMessage.messageBodies firstObject] localPath]; + if (localPath && localPath.length > 0) { + [weakSelf playVideoWithVideoPath:localPath]; + } + }else{ + [MBProgressHUD checkHudWithView:self.view label:NSLocalizedString(@"message.videoFail", @"video for failure!") hidesAfter:1.0]; + } + } onQueue:nil]; +} + +- (void)playVideoWithVideoPath:(NSString *)videoPath +{ +// _isScrollToBottom = NO; + NSURL *videoURL = [NSURL fileURLWithPath:videoPath]; + MPMoviePlayerViewController *moviePlayerController = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL]; + [moviePlayerController.moviePlayer prepareToPlay]; + moviePlayerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile; + [self presentMoviePlayerViewControllerAnimated:moviePlayerController]; +} + +// 图片的bubble被点击 +-(void)chatImageCellBubblePressed:(MessageModel *)model +{ + __weak ChatMainViewController *weakSelf = self; + id chatManager = [[EaseMob sharedInstance] chatManager]; + if ([model.messageBody messageBodyType] == eMessageBodyType_Image) { + EMImageMessageBody *imageBody = (EMImageMessageBody *)model.messageBody; + if (imageBody.thumbnailDownloadStatus == EMAttachmentDownloadSuccessed) { + if (imageBody.attachmentDownloadStatus == EMAttachmentDownloadSuccessed) + { + //发送已读回执 + if ([self shouldAckMessage:model.message read:YES]) + { + [self sendHasReadResponseForMessages:@[model.message]]; + } + NSString *localPath = model.message == nil ? model.localPath : [[model.message.messageBodies firstObject] localPath]; + if (localPath && localPath.length > 0) { + UIImage *image = [UIImage imageWithContentsOfFile:localPath]; +// self.isScrollToBottom = NO; + if (image) + { + [self.messageReadManager showBrowserWithImages:@[image]]; + } + else + { + NSLog(@"Read %@ failed!", localPath); + } + return ; + } + } + [MBProgressHUD hudWithView:self.view label:NSLocalizedString(@"message.downloadingImage", @"downloading a image...")]; + + [chatManager asyncFetchMessage:model.message progress:nil completion:^(EMMessage *aMessage, EMError *error) { + [MBProgressHUD hideAllHUDsForView:self.view animated:YES]; + if (!error) { + //发送已读回执 + if ([weakSelf shouldAckMessage:model.message read:YES]) + { + [weakSelf sendHasReadResponseForMessages:@[model.message]]; + } + NSString *localPath = aMessage == nil ? model.localPath : [[aMessage.messageBodies firstObject] localPath]; + if (localPath && localPath.length > 0) { + UIImage *image = [UIImage imageWithContentsOfFile:localPath]; +// weakSelf.isScrollToBottom = NO; + if (image) + { + [weakSelf.messageReadManager showBrowserWithImages:@[image]]; + } + else + { + NSLog(@"Read %@ failed!", localPath); + } + return ; + } + } + [MBProgressHUD errorHudWithView:self.view label:NSLocalizedString(@"message.imageFail", @"image for failure!") hidesAfter:1.0]; + } onQueue:nil]; + }else{ + //获取缩略图 + [chatManager asyncFetchMessageThumbnail:model.message progress:nil completion:^(EMMessage *aMessage, EMError *error) { + if (!error) { + [weakSelf reloadTableViewDataWithMessage:model.message]; + }else{ +// [weakSelf showHint:NSLocalizedString(@"message.thumImageFail", @"thumbnail for failure!")]; + [MBProgressHUD errorHudWithView:self.view label:NSLocalizedString(@"message.thumImageFail", @"thumbnail for failure!") hidesAfter:1.0]; + + } + + } onQueue:nil]; + } + }else if ([model.messageBody messageBodyType] == eMessageBodyType_Video) { + //获取缩略图 + EMVideoMessageBody *videoBody = (EMVideoMessageBody *)model.messageBody; + if (videoBody.thumbnailDownloadStatus != EMAttachmentDownloadSuccessed) { + [chatManager asyncFetchMessageThumbnail:model.message progress:nil completion:^(EMMessage *aMessage, EMError *error) { + if (!error) { + [weakSelf reloadTableViewDataWithMessage:model.message]; + }else{ + [MBProgressHUD errorHudWithView:self.view label:NSLocalizedString(@"message.thumImageFail", @"thumbnail for failure!") hidesAfter:1.0]; + + } + } onQueue:nil]; + } + } +} + + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatMainViewController.xib b/Ash_AWord/ViewControllers/Chat/ChatMainViewController.xib new file mode 100644 index 0000000..8666205 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatMainViewController.xib @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ash_AWord/ViewControllers/Chat/ChatSendHelper.h b/Ash_AWord/ViewControllers/Chat/ChatSendHelper.h new file mode 100644 index 0000000..196977c --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatSendHelper.h @@ -0,0 +1,184 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import "EMMessage.h" +#import "EaseMob.h" +@interface ChatSendHelper : NSObject + +/** + * 发送文字消息(包括系统表情) + * + * @param str 发送的文字 + * @param username 接收方 + * @param isChatGroup 是否是群聊 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendTextMessageWithString:(NSString *)str + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送文字消息(包括系统表情) + * + * @param str 发送的文字 + * @param username 接收方 + * @param messageType 消息类型 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendTextMessageWithString:(NSString *)str + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送图片消息 + * + * @param image 发送的图片 + * @param username 接收方 + * @param isChatGroup 是否是群聊 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendImageMessageWithImage:(UIImage *)image + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送图片消息 + * + * @param image 发送的图片 + * @param username 接收方 + * @param messageType 消息类型 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendImageMessageWithImage:(UIImage *)image + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送音频消息 + * + * @param voice 发送的音频 + * @param username 接收方 + * @param isChatGroup 是否是群聊 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendVoice:(EMChatVoice *)voice + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送音频消息 + * + * @param voice 发送的音频 + * @param username 接收方 + * @param messageType 消息类型 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendVoice:(EMChatVoice *)voice + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; +/** + * 发送位置消息(定位) + * + * @param latitude 经度 + * @param longitude 纬度 + * @param address 位置描述信息 + * @param username 接收方 + * @param isChatGroup 是否是群聊 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendLocationLatitude:(double)latitude + longitude:(double)longitude + address:(NSString *)address + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送位置消息(定位) + * + * @param latitude 经度 + * @param longitude 纬度 + * @param address 位置描述信息 + * @param username 接收方 + * @param messageType 消息类型 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendLocationLatitude:(double)latitude + longitude:(double)longitude + address:(NSString *)address + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送视频文件消息 + * + * @param video 发送的视频 + * @param username 接收方 + * @param isChatGroup 是否是群聊 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendVideo:(EMChatVideo *)video + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; + +/** + * 发送视频文件消息 + * + * @param video 发送的视频 + * @param username 接收方 + * @param messageType 消息类型 + * @param requireEncryption 是否加密 + * @param ext 扩展信息 + * @return 封装的消息体 + */ ++(EMMessage *)sendVideo:(EMChatVideo *)video + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext; +@end diff --git a/Ash_AWord/ViewControllers/Chat/ChatSendHelper.m b/Ash_AWord/ViewControllers/Chat/ChatSendHelper.m new file mode 100644 index 0000000..343146e --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ChatSendHelper.m @@ -0,0 +1,156 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "ChatSendHelper.h" +#import "ConvertToCommonEmoticonsHelper.h" +#import "EaseMob.h" +@interface ChatImageOptions : NSObject + +@property (assign, nonatomic) CGFloat compressionQuality; + +@end + +@implementation ChatImageOptions + +@end + +@implementation ChatSendHelper + ++(EMMessage *)sendTextMessageWithString:(NSString *)str + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMMessageType type = isChatGroup ? eMessageTypeGroupChat : eMessageTypeChat; + return [self sendTextMessageWithString:str toUsername:username messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendTextMessageWithString:(NSString *)str + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + // 表情映射。 + NSString *willSendText = [ConvertToCommonEmoticonsHelper convertToCommonEmoticons:str]; + EMChatText *text = [[EMChatText alloc] initWithText:willSendText]; + EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithChatObject:text]; + return [self sendMessage:username messageBody:body messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendImageMessageWithImage:(UIImage *)image + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMMessageType type = isChatGroup ? eMessageTypeGroupChat : eMessageTypeChat; + return [self sendImageMessageWithImage:image toUsername:username messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendImageMessageWithImage:(UIImage *)image + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMChatImage *chatImage = [[EMChatImage alloc] initWithUIImage:image displayName:@"image.jpg"]; + id options = [[ChatImageOptions alloc] init]; + [options setCompressionQuality:0.6]; + [chatImage setImageOptions:options]; + EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithImage:chatImage thumbnailImage:nil]; + return [self sendMessage:username messageBody:body messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendVoice:(EMChatVoice *)voice + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMMessageType type = isChatGroup ? eMessageTypeGroupChat : eMessageTypeChat; + return [self sendVoice:voice toUsername:username messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendVoice:(EMChatVoice *)voice + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMVoiceMessageBody *body = [[EMVoiceMessageBody alloc] initWithChatObject:voice]; + return [self sendMessage:username messageBody:body messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendVideo:(EMChatVideo *)video + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMMessageType type = isChatGroup ? eMessageTypeGroupChat : eMessageTypeChat; + return [self sendVideo:video toUsername:username messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendVideo:(EMChatVideo *)video + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMVideoMessageBody *body = [[EMVideoMessageBody alloc] initWithChatObject:video]; + return [self sendMessage:username messageBody:body messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendLocationLatitude:(double)latitude + longitude:(double)longitude + address:(NSString *)address + toUsername:(NSString *)username + isChatGroup:(BOOL)isChatGroup + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMMessageType type = isChatGroup ? eMessageTypeGroupChat : eMessageTypeChat; + return [self sendLocationLatitude:latitude longitude:longitude address:address toUsername:username messageType:type requireEncryption:requireEncryption ext:ext]; +} + ++(EMMessage *)sendLocationLatitude:(double)latitude + longitude:(double)longitude + address:(NSString *)address + toUsername:(NSString *)username + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMChatLocation *chatLocation = [[EMChatLocation alloc] initWithLatitude:latitude longitude:longitude address:address]; + EMLocationMessageBody *body = [[EMLocationMessageBody alloc] initWithChatObject:chatLocation]; + return [self sendMessage:username messageBody:body messageType:type requireEncryption:requireEncryption ext:ext]; +} + +// 发送消息 ++(EMMessage *)sendMessage:(NSString *)username + messageBody:(id)body + messageType:(EMMessageType)type + requireEncryption:(BOOL)requireEncryption + ext:(NSDictionary *)ext +{ + EMMessage *retureMsg = [[EMMessage alloc] initWithReceiver:username bodies:[NSArray arrayWithObject:body]]; + retureMsg.requireEncryption = requireEncryption; + retureMsg.messageType = type; + retureMsg.ext = ext; + EMMessage *message = [[EaseMob sharedInstance].chatManager asyncSendMessage:retureMsg progress:nil]; + + return message; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/ConvertToCommonEmoticonsHelper.h b/Ash_AWord/ViewControllers/Chat/ConvertToCommonEmoticonsHelper.h new file mode 100644 index 0000000..6af5f8b --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ConvertToCommonEmoticonsHelper.h @@ -0,0 +1,14 @@ +// +// ConvertToCommonEmoticonsHelper.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 14-6-30. +// Copyright (c) 2014年 dujiepeng. All rights reserved. +// + +#import + +@interface ConvertToCommonEmoticonsHelper : NSObject ++ (NSString *)convertToCommonEmoticons:(NSString *)text; ++ (NSString *)convertToSystemEmoticons:(NSString *)text; +@end diff --git a/Ash_AWord/ViewControllers/Chat/ConvertToCommonEmoticonsHelper.m b/Ash_AWord/ViewControllers/Chat/ConvertToCommonEmoticonsHelper.m new file mode 100644 index 0000000..3df6b49 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/ConvertToCommonEmoticonsHelper.m @@ -0,0 +1,537 @@ +// +// ConvertToCommonEmoticonsHelper.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 14-6-30. +// Copyright (c) 2014年 dujiepeng. All rights reserved. +// + +#import "ConvertToCommonEmoticonsHelper.h" +#import "Emoji.h" + +@implementation ConvertToCommonEmoticonsHelper + +#pragma mark - emotics ++ (NSString *)convertToCommonEmoticons:(NSString *)text { + int allEmoticsCount = (int)[Emoji allEmoji].count; + NSMutableString *retText = [[NSMutableString alloc] initWithString:text]; + for(int i=0; i + +typedef enum{ + ChatMoreTypeChat, + ChatMoreTypeGroupChat, +}ChatMoreType; + +@protocol DXChatBarMoreViewDelegate; +@interface DXChatBarMoreView : UIView + +@property (nonatomic,assign) id delegate; + +@property (nonatomic, strong) UIButton *photoButton; +@property (nonatomic, strong) UIButton *takePicButton; +@property (nonatomic, strong) UIButton *locationButton; +@property (nonatomic, strong) UIButton *videoButton; +@property (nonatomic, strong) UIButton *audioCallButton; +@property (nonatomic, strong) UIButton *videoCallButton; + +- (instancetype)initWithFrame:(CGRect)frame typw:(ChatMoreType)type; + +- (void)setupSubviewsForType:(ChatMoreType)type; + +@end + +@protocol DXChatBarMoreViewDelegate + +@required +- (void)moreViewTakePicAction:(DXChatBarMoreView *)moreView; +- (void)moreViewPhotoAction:(DXChatBarMoreView *)moreView; +- (void)moreViewLocationAction:(DXChatBarMoreView *)moreView; +- (void)moreViewAudioCallAction:(DXChatBarMoreView *)moreView; +- (void)moreViewVideoCallAction:(DXChatBarMoreView *)moreView; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXChatBarMoreView.m b/Ash_AWord/ViewControllers/Chat/DXChatBarMoreView.m new file mode 100644 index 0000000..efb2ed9 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXChatBarMoreView.m @@ -0,0 +1,116 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "DXChatBarMoreView.h" + +#define CHAT_BUTTON_SIZE 50 +#define INSETS 8 + +@implementation DXChatBarMoreView + +- (instancetype)initWithFrame:(CGRect)frame typw:(ChatMoreType)type +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + [self setupSubviewsForType:type]; + } + return self; +} + +- (void)setupSubviewsForType:(ChatMoreType)type +{ + self.backgroundColor = [UIColor clearColor]; + CGFloat insets = (self.frame.size.width - 4 * CHAT_BUTTON_SIZE) / 5; + + _photoButton =[UIButton buttonWithType:UIButtonTypeCustom]; + [_photoButton setFrame:CGRectMake(insets, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE)]; + [_photoButton setImage:[UIImage imageNamed:@"chatBar_colorMore_photo"] forState:UIControlStateNormal]; + [_photoButton setImage:[UIImage imageNamed:@"chatBar_colorMore_photoSelected"] forState:UIControlStateHighlighted]; + [_photoButton addTarget:self action:@selector(photoAction) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_photoButton]; + + _locationButton =[UIButton buttonWithType:UIButtonTypeCustom]; + [_locationButton setFrame:CGRectMake(insets * 2 + CHAT_BUTTON_SIZE, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE)]; + [_locationButton setImage:[UIImage imageNamed:@"chatBar_colorMore_location"] forState:UIControlStateNormal]; + [_locationButton setImage:[UIImage imageNamed:@"chatBar_colorMore_locationSelected"] forState:UIControlStateHighlighted]; + [_locationButton addTarget:self action:@selector(locationAction) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_locationButton]; + + _takePicButton =[UIButton buttonWithType:UIButtonTypeCustom]; + [_takePicButton setFrame:CGRectMake(insets * 3 + CHAT_BUTTON_SIZE * 2, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE)]; + [_takePicButton setImage:[UIImage imageNamed:@"chatBar_colorMore_camera"] forState:UIControlStateNormal]; + [_takePicButton setImage:[UIImage imageNamed:@"chatBar_colorMore_cameraSelected"] forState:UIControlStateHighlighted]; + [_takePicButton addTarget:self action:@selector(takePicAction) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_takePicButton]; + + CGRect frame = self.frame; + if (type == ChatMoreTypeChat) { + frame.size.height = 150; + _audioCallButton =[UIButton buttonWithType:UIButtonTypeCustom]; + [_audioCallButton setFrame:CGRectMake(insets * 4 + CHAT_BUTTON_SIZE * 3, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE)]; + [_audioCallButton setImage:[UIImage imageNamed:@"chatBar_colorMore_audioCall"] forState:UIControlStateNormal]; + [_audioCallButton setImage:[UIImage imageNamed:@"chatBar_colorMore_audioCallSelected"] forState:UIControlStateHighlighted]; + [_audioCallButton addTarget:self action:@selector(takeAudioCallAction) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_audioCallButton]; + + _videoCallButton =[UIButton buttonWithType:UIButtonTypeCustom]; + [_videoCallButton setFrame:CGRectMake(insets, 10 * 2 + CHAT_BUTTON_SIZE + 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE)]; + [_videoCallButton setImage:[UIImage imageNamed:@"chatBar_colorMore_videoCall"] forState:UIControlStateNormal]; + [_videoCallButton setImage:[UIImage imageNamed:@"chatBar_colorMore_videoCallSelected"] forState:UIControlStateHighlighted]; + [_videoCallButton addTarget:self action:@selector(takeVideoCallAction) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:_videoCallButton]; + } + else if (type == ChatMoreTypeGroupChat) + { + frame.size.height = 80; + } + self.frame = frame; +} + +#pragma mark - action + +- (void)takePicAction{ + if(_delegate && [_delegate respondsToSelector:@selector(moreViewTakePicAction:)]){ + [_delegate moreViewTakePicAction:self]; + } +} + +- (void)photoAction +{ + if (_delegate && [_delegate respondsToSelector:@selector(moreViewPhotoAction:)]) { + [_delegate moreViewPhotoAction:self]; + } +} + +- (void)locationAction +{ + if (_delegate && [_delegate respondsToSelector:@selector(moreViewLocationAction:)]) { + [_delegate moreViewLocationAction:self]; + } +} + +- (void)takeAudioCallAction +{ + if (_delegate && [_delegate respondsToSelector:@selector(moreViewAudioCallAction:)]) { + [_delegate moreViewAudioCallAction:self]; + } +} + +- (void)takeVideoCallAction +{ + if (_delegate && [_delegate respondsToSelector:@selector(moreViewVideoCallAction:)]) { + [_delegate moreViewVideoCallAction:self]; + } +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXFaceView.h b/Ash_AWord/ViewControllers/Chat/DXFaceView.h new file mode 100644 index 0000000..c0d610c --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXFaceView.h @@ -0,0 +1,32 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "FacialView.h" + +@protocol DXFaceDelegate + +@required +- (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete; +- (void)sendFace; + +@end + + +@interface DXFaceView : UIView + +@property (nonatomic, assign) id delegate; + +- (BOOL)stringIsFace:(NSString *)string; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXFaceView.m b/Ash_AWord/ViewControllers/Chat/DXFaceView.m new file mode 100644 index 0000000..4cceadc --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXFaceView.m @@ -0,0 +1,68 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "DXFaceView.h" + +@interface DXFaceView () +{ + FacialView *_facialView; +} + +@end + +@implementation DXFaceView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + _facialView = [[FacialView alloc] initWithFrame: CGRectMake(5, 5, frame.size.width - 10, self.bounds.size.height - 10)]; + [_facialView loadFacialView:1 size:CGSizeMake(30, 30)]; + _facialView.delegate = self; + [self addSubview:_facialView]; + } + return self; +} + +#pragma mark - FacialViewDelegate + +-(void)selectedFacialView:(NSString*)str{ + if (_delegate) { + [_delegate selectedFacialView:str isDelete:NO]; + } +} + +-(void)deleteSelected:(NSString *)str{ + if (_delegate) { + [_delegate selectedFacialView:str isDelete:YES]; + } +} + +- (void)sendFace +{ + if (_delegate) { + [_delegate sendFace]; + } +} + +#pragma mark - public + +- (BOOL)stringIsFace:(NSString *)string +{ + if ([_facialView.faces containsObject:string]) { + return YES; + } + + return NO; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXMessageToolBar.h b/Ash_AWord/ViewControllers/Chat/DXMessageToolBar.h new file mode 100755 index 0000000..bf03cb6 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXMessageToolBar.h @@ -0,0 +1,183 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "XHMessageTextView.h" + +#import "DXChatBarMoreView.h" +#import "DXFaceView.h" +#import "DXRecordView.h" + +#define kInputTextViewMinHeight 36 +#define kInputTextViewMaxHeight 200 +#define kHorizontalPadding 8 +#define kVerticalPadding 5 + +#define kTouchToRecord NSLocalizedString(@"message.toolBar.record.touch", @"hold down to talk") +#define kTouchToFinish NSLocalizedString(@"message.toolBar.record.send", @"loosen to send") + + +/** + * 类说明: + * 1、推荐使用[initWithFrame:...]方法进行初始化 + * 2、提供默认的录音,表情,更多按钮的附加页面 + * 3、可自定义以上的附加页面 + */ + + +@protocol DXMessageToolBarDelegate; +@interface DXMessageToolBar : UIView + +@property (nonatomic, weak) id delegate; + +@property (strong, nonatomic) UIButton *recordButton; + +/** + * 操作栏背景图片 + */ +@property (strong, nonatomic) UIImage *toolbarBackgroundImage; + +/** + * 背景图片 + */ +@property (strong, nonatomic) UIImage *backgroundImage; + +/** + * 更多的附加页面 + */ +@property (strong, nonatomic) UIView *moreView; + +/** + * 表情的附加页面 + */ +@property (strong, nonatomic) UIView *faceView; + +/** + * 录音的附加页面 + */ +@property (strong, nonatomic) UIView *recordView; + +/** + * 用于输入文本消息的输入框 + */ +@property (strong, nonatomic) XHMessageTextView *inputTextView; + +/** + * 文字输入区域最大高度,必须 > KInputTextViewMinHeight(最小高度)并且 < KInputTextViewMaxHeight,否则设置无效 + */ +@property (nonatomic) CGFloat maxTextInputViewHeight; + +/** + * 初始化方法 + * + * @param frame 位置及大小 + * + * @return DXMessageToolBar + */ +- (instancetype)initWithFrame:(CGRect)frame; + +/** + * 默认高度 + * + * @return 默认高度 + */ ++ (CGFloat)defaultHeight; + +/** + * 取消触摸录音键 + */ +- (void)cancelTouchRecord; + +@end + +@protocol DXMessageToolBarDelegate + +@optional + +/** + * 在普通状态和语音状态之间进行切换时,会触发这个回调函数 + * + * @param changedToRecord 是否改为发送语音状态 + */ +- (void)didStyleChangeToRecord:(BOOL)changedToRecord; + +///** +// * 点击“表情”按钮触发 +// * +// * @param isSelected 是否选中。YES,显示表情页面;NO,收起表情页面 +// */ +//- (void)didSelectedFaceButton:(BOOL)isSelected; +// +///** +// * 点击“更多”按钮触发 +// * +// * @param isSelected 是否选中。YES,显示更多页面;NO,收起更多页面 +// */ +//- (void)didSelectedMoreButton:(BOOL)isSelected; + +/** + * 文字输入框开始编辑 + * + * @param inputTextView 输入框对象 + */ +- (void)inputTextViewDidBeginEditing:(XHMessageTextView *)messageInputTextView; + +/** + * 文字输入框将要开始编辑 + * + * @param inputTextView 输入框对象 + */ +- (void)inputTextViewWillBeginEditing:(XHMessageTextView *)messageInputTextView; + +/** + * 发送文字消息,可能包含系统自带表情 + * + * @param text 文字消息 + */ +- (void)didSendText:(NSString *)text; + +/** + * 发送第三方表情,不会添加到文字输入框中 + * + * @param faceLocalPath 选中的表情的本地路径 + */ +- (void)didSendFace:(NSString *)faceLocalPath; + +/** + * 按下录音按钮开始录音 + */ +- (void)didStartRecordingVoiceAction:(UIView *)recordView; +/** + * 手指向上滑动取消录音 + */ +- (void)didCancelRecordingVoiceAction:(UIView *)recordView; +/** + * 松开手指完成录音 + */ +- (void)didFinishRecoingVoiceAction:(UIView *)recordView; +/** + * 当手指离开按钮的范围内时,主要为了通知外部的HUD + */ +- (void)didDragOutsideAction:(UIView *)recordView; +/** + * 当手指再次进入按钮的范围内时,主要也是为了通知外部的HUD + */ +- (void)didDragInsideAction:(UIView *)recordView; + +@required +/** + * 高度变到toHeight + */ +- (void)didChangeFrameToHeight:(CGFloat)toHeight; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXMessageToolBar.m b/Ash_AWord/ViewControllers/Chat/DXMessageToolBar.m new file mode 100755 index 0000000..2b3db9b --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXMessageToolBar.m @@ -0,0 +1,682 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "DXMessageToolBar.h" + +@interface DXMessageToolBar() +{ + CGFloat _previousTextViewContentHeight;//上一次inputTextView的contentSize.height +} + +@property (nonatomic) CGFloat version; + +/** + * 背景 + */ +@property (strong, nonatomic) UIImageView *toolbarBackgroundImageView; +@property (strong, nonatomic) UIImageView *backgroundImageView; + +/** + * 按钮、输入框、toolbarView + */ +@property (strong, nonatomic) UIView *toolbarView; +@property (strong, nonatomic) UIButton *styleChangeButton; +@property (strong, nonatomic) UIButton *moreButton; +@property (strong, nonatomic) UIButton *faceButton; + +/** + * 底部扩展页面 + */ +@property (nonatomic) BOOL isShowButtomView; +@property (strong, nonatomic) UIView *activityButtomView;//当前活跃的底部扩展页面 + +@end + +@implementation DXMessageToolBar + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (frame.size.height < (kVerticalPadding * 2 + kInputTextViewMinHeight)) { + frame.size.height = kVerticalPadding * 2 + kInputTextViewMinHeight; + } + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + [self setupConfigure]; + } + return self; +} + +- (void)setFrame:(CGRect)frame +{ + if (frame.size.height < (kVerticalPadding * 2 + kInputTextViewMinHeight)) { + frame.size.height = kVerticalPadding * 2 + kInputTextViewMinHeight; + } + [super setFrame:frame]; +} + +- (void)willMoveToSuperview:(UIView *)newSuperview +{ + // 当别的地方需要add的时候,就会调用这里 + if (newSuperview) { + [self setupSubviews]; + } + + [super willMoveToSuperview:newSuperview]; +} + +- (void)didMoveToSuperview +{ + [super didMoveToSuperview]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil]; + + _delegate = nil; + _inputTextView.delegate = nil; + _inputTextView = nil; +} + +#pragma mark - getter + +- (UIImageView *)backgroundImageView +{ + if (_backgroundImageView == nil) { + _backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds]; + _backgroundImageView.backgroundColor = [UIColor clearColor]; + _backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + } + + return _backgroundImageView; +} + +- (UIImageView *)toolbarBackgroundImageView +{ + if (_toolbarBackgroundImageView == nil) { + _toolbarBackgroundImageView = [[UIImageView alloc] init]; + _toolbarBackgroundImageView.backgroundColor = [UIColor clearColor]; + _toolbarBackgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + } + + return _toolbarBackgroundImageView; +} + +- (UIView *)toolbarView +{ + if (_toolbarView == nil) { + _toolbarView = [[UIView alloc] init]; + _toolbarView.backgroundColor = [UIColor clearColor]; + } + + return _toolbarView; +} + +#pragma mark - setter + +- (void)setBackgroundImage:(UIImage *)backgroundImage +{ + _backgroundImage = backgroundImage; + self.backgroundImageView.image = backgroundImage; +} + +- (void)setToolbarBackgroundImage:(UIImage *)toolbarBackgroundImage +{ + _toolbarBackgroundImage = toolbarBackgroundImage; + self.toolbarBackgroundImageView.image = toolbarBackgroundImage; +} + +- (void)setMaxTextInputViewHeight:(CGFloat)maxTextInputViewHeight +{ + if (maxTextInputViewHeight > kInputTextViewMaxHeight) { + maxTextInputViewHeight = kInputTextViewMaxHeight; + } + _maxTextInputViewHeight = maxTextInputViewHeight; +} + +#pragma mark - UITextViewDelegate + +- (BOOL)textViewShouldBeginEditing:(UITextView *)textView +{ + if ([self.delegate respondsToSelector:@selector(inputTextViewWillBeginEditing:)]) { + [self.delegate inputTextViewWillBeginEditing:self.inputTextView]; + } + + self.faceButton.selected = NO; + self.styleChangeButton.selected = NO; + self.moreButton.selected = NO; + return YES; +} + +- (void)textViewDidBeginEditing:(UITextView *)textView +{ + [textView becomeFirstResponder]; + + if ([self.delegate respondsToSelector:@selector(inputTextViewDidBeginEditing:)]) { + [self.delegate inputTextViewDidBeginEditing:self.inputTextView]; + } +} + +- (void)textViewDidEndEditing:(UITextView *)textView +{ + [textView resignFirstResponder]; +} + +- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text +{ + if ([text isEqualToString:@"\n"]) { + if ([self.delegate respondsToSelector:@selector(didSendText:)]) { + [self.delegate didSendText:textView.text]; + self.inputTextView.text = @""; + [self willShowInputTextViewToHeight:[self getTextViewContentH:self.inputTextView]];; + } + + return NO; + } + return YES; +} + +- (void)textViewDidChange:(UITextView *)textView +{ + [self willShowInputTextViewToHeight:[self getTextViewContentH:textView]]; +} + +#pragma mark - DXFaceDelegate + +- (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete +{ + NSString *chatText = self.inputTextView.text; + + if (!isDelete && str.length > 0) { + self.inputTextView.text = [NSString stringWithFormat:@"%@%@",chatText,str]; + } + else { + if (chatText.length >= 2) + { + NSString *subStr = [chatText substringFromIndex:chatText.length-2]; + if ([(DXFaceView *)self.faceView stringIsFace:subStr]) { + self.inputTextView.text = [chatText substringToIndex:chatText.length-2]; + [self textViewDidChange:self.inputTextView]; + return; + } + } + + if (chatText.length > 0) { + self.inputTextView.text = [chatText substringToIndex:chatText.length-1]; + } + } + + [self textViewDidChange:self.inputTextView]; +} +- (void)sendFace +{ + NSString *chatText = self.inputTextView.text; + if (chatText.length > 0) { + if ([self.delegate respondsToSelector:@selector(didSendText:)]) { + [self.delegate didSendText:chatText]; + self.inputTextView.text = @""; + [self willShowInputTextViewToHeight:[self getTextViewContentH:self.inputTextView]];; + } + } +} + +#pragma mark - UIKeyboardNotification + +- (void)keyboardWillChangeFrame:(NSNotification *)notification +{ + NSDictionary *userInfo = notification.userInfo; + CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; + CGRect beginFrame = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; + CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; + + void(^animations)() = ^{ + [self willShowKeyboardFromFrame:beginFrame toFrame:endFrame]; + }; + + void(^completion)(BOOL) = ^(BOOL finished){ + }; + + [UIView animateWithDuration:duration delay:0.0f options:(curve << 16 | UIViewAnimationOptionBeginFromCurrentState) animations:animations completion:completion]; +} + +#pragma mark - private + +/** + * 设置初始属性 + */ +- (void)setupConfigure +{ + self.version = [[[UIDevice currentDevice] systemVersion] floatValue]; + + self.maxTextInputViewHeight = kInputTextViewMaxHeight; + + self.activityButtomView = nil; + self.isShowButtomView = NO; + self.backgroundImageView.image = [[UIImage imageNamed:@"messageToolbarBg"] stretchableImageWithLeftCapWidth:0.5 topCapHeight:10]; + [self addSubview:self.backgroundImageView]; + + self.toolbarView.frame = CGRectMake(0, 0, self.frame.size.width, kVerticalPadding * 2 + kInputTextViewMinHeight); + self.toolbarBackgroundImageView.frame = self.toolbarView.bounds; + [self.toolbarView addSubview:self.toolbarBackgroundImageView]; + [self addSubview:self.toolbarView]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; +} + +- (void)setupSubviews +{ + CGFloat allButtonWidth = 0.0; + CGFloat textViewLeftMargin = 6.0; + + //转变输入样式 + self.styleChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(kHorizontalPadding, kVerticalPadding, kInputTextViewMinHeight, kInputTextViewMinHeight)]; + self.styleChangeButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; + [self.styleChangeButton setImage:[UIImage imageNamed:@"chatBar_record"] forState:UIControlStateNormal]; + [self.styleChangeButton setImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; + [self.styleChangeButton addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside]; + self.styleChangeButton.tag = 0; + allButtonWidth += CGRectGetMaxX(self.styleChangeButton.frame); + textViewLeftMargin += CGRectGetMaxX(self.styleChangeButton.frame); + + //更多 + self.moreButton = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds) - kHorizontalPadding - kInputTextViewMinHeight, kVerticalPadding, kInputTextViewMinHeight, kInputTextViewMinHeight)]; + self.moreButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin; + [self.moreButton setImage:[UIImage imageNamed:@"chatBar_more"] forState:UIControlStateNormal]; + [self.moreButton setImage:[UIImage imageNamed:@"chatBar_moreSelected"] forState:UIControlStateHighlighted]; + [self.moreButton setImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; + [self.moreButton addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside]; + self.moreButton.tag = 2; + allButtonWidth += CGRectGetWidth(self.moreButton.frame) + kHorizontalPadding * 2.5; + + //表情 + self.faceButton = [[UIButton alloc] initWithFrame:CGRectMake(CGRectGetMinX(self.moreButton.frame) - kInputTextViewMinHeight - kHorizontalPadding, kVerticalPadding, kInputTextViewMinHeight, kInputTextViewMinHeight)]; + self.faceButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin; + [self.faceButton setImage:[UIImage imageNamed:@"chatBar_face"] forState:UIControlStateNormal]; + [self.faceButton setImage:[UIImage imageNamed:@"chatBar_faceSelected"] forState:UIControlStateHighlighted]; + [self.faceButton setImage:[UIImage imageNamed:@"chatBar_keyboard"] forState:UIControlStateSelected]; + [self.faceButton addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside]; + self.faceButton.tag = 1; + allButtonWidth += CGRectGetWidth(self.faceButton.frame) + kHorizontalPadding * 1.5; + + + // 输入框的高度和宽度 + CGFloat width = CGRectGetWidth(self.bounds) - (allButtonWidth ? allButtonWidth : (textViewLeftMargin * 2)); + // 初始化输入框 + self.inputTextView = [[XHMessageTextView alloc] initWithFrame:CGRectMake(textViewLeftMargin, kVerticalPadding, width, kInputTextViewMinHeight)]; + self.inputTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight; +// self.inputTextView.contentMode = UIViewContentModeCenter; + _inputTextView.scrollEnabled = YES; + _inputTextView.returnKeyType = UIReturnKeySend; + _inputTextView.enablesReturnKeyAutomatically = YES; // UITextView内部判断send按钮是否可以用 + _inputTextView.placeHolder = NSLocalizedString(@"message.toolBar.inputPlaceHolder", @"input a new message"); + _inputTextView.delegate = self; + _inputTextView.backgroundColor = [UIColor clearColor]; + _inputTextView.layer.borderColor = [UIColor colorWithWhite:0.8f alpha:1.0f].CGColor; + _inputTextView.layer.borderWidth = 0.65f; + _inputTextView.layer.cornerRadius = 6.0f; + _previousTextViewContentHeight = [self getTextViewContentH:_inputTextView]; + + //录制 + self.recordButton = [[UIButton alloc] initWithFrame:CGRectMake(textViewLeftMargin, kVerticalPadding, width, kInputTextViewMinHeight)]; + self.recordButton.titleLabel.font = [UIFont systemFontOfSize:15.0]; + [self.recordButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateNormal]; + [self.recordButton setBackgroundImage:[[UIImage imageNamed:@"chatBar_recordBg"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateNormal]; + [self.recordButton setBackgroundImage:[[UIImage imageNamed:@"chatBar_recordSelectedBg"] stretchableImageWithLeftCapWidth:10 topCapHeight:10] forState:UIControlStateHighlighted]; + [self.recordButton setTitle:kTouchToRecord forState:UIControlStateNormal]; + [self.recordButton setTitle:kTouchToFinish forState:UIControlStateHighlighted]; + self.recordButton.hidden = YES; + [self.recordButton addTarget:self action:@selector(recordButtonTouchDown) forControlEvents:UIControlEventTouchDown]; + [self.recordButton addTarget:self action:@selector(recordButtonTouchUpOutside) forControlEvents:UIControlEventTouchUpOutside]; + [self.recordButton addTarget:self action:@selector(recordButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; + [self.recordButton addTarget:self action:@selector(recordDragOutside) forControlEvents:UIControlEventTouchDragExit]; + [self.recordButton addTarget:self action:@selector(recordDragInside) forControlEvents:UIControlEventTouchDragEnter]; + self.recordButton.hidden = YES; + + if (!self.moreView) { + self.moreView = [[DXChatBarMoreView alloc] initWithFrame:CGRectMake(0, (kVerticalPadding * 2 + kInputTextViewMinHeight), self.frame.size.width, 80) typw:ChatMoreTypeGroupChat]; + self.moreView.backgroundColor = [UIColor lightGrayColor]; + self.moreView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; + } + + if (!self.faceView) { + self.faceView = [[DXFaceView alloc] initWithFrame:CGRectMake(0, (kVerticalPadding * 2 + kInputTextViewMinHeight), self.frame.size.width, 200)]; + [(DXFaceView *)self.faceView setDelegate:self]; + self.faceView.backgroundColor = [UIColor lightGrayColor]; + self.faceView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin; + } + + if (!self.recordView) { + self.recordView = [[DXRecordView alloc] initWithFrame:CGRectMake(90, 130, 140, 140)]; + } + + [self.toolbarView addSubview:self.styleChangeButton]; + [self.toolbarView addSubview:self.moreButton]; + [self.toolbarView addSubview:self.faceButton]; + [self.toolbarView addSubview:self.inputTextView]; + [self.toolbarView addSubview:self.recordButton]; +} + +#pragma mark - change frame + +- (void)willShowBottomHeight:(CGFloat)bottomHeight +{ + CGRect fromFrame = self.frame; + CGFloat toHeight = self.toolbarView.frame.size.height + bottomHeight; + CGRect toFrame = CGRectMake(fromFrame.origin.x, fromFrame.origin.y + (fromFrame.size.height - toHeight), fromFrame.size.width, toHeight); + + //如果需要将所有扩展页面都隐藏,而此时已经隐藏了所有扩展页面,则不进行任何操作 + if(bottomHeight == 0 && self.frame.size.height == self.toolbarView.frame.size.height) + { + return; + } + + if (bottomHeight == 0) { + self.isShowButtomView = NO; + } + else{ + self.isShowButtomView = YES; + } + + self.frame = toFrame; + + if (_delegate && [_delegate respondsToSelector:@selector(didChangeFrameToHeight:)]) { + [_delegate didChangeFrameToHeight:toHeight]; + } +} + +- (void)willShowBottomView:(UIView *)bottomView +{ + if (![self.activityButtomView isEqual:bottomView]) { + CGFloat bottomHeight = bottomView ? bottomView.frame.size.height : 0; + [self willShowBottomHeight:bottomHeight]; + + if (bottomView) { + CGRect rect = bottomView.frame; + rect.origin.y = CGRectGetMaxY(self.toolbarView.frame); + bottomView.frame = rect; + [self addSubview:bottomView]; + } + + if (self.activityButtomView) { + [self.activityButtomView removeFromSuperview]; + } + self.activityButtomView = bottomView; + } +} + +- (void)willShowKeyboardFromFrame:(CGRect)beginFrame toFrame:(CGRect)toFrame +{ + if (beginFrame.origin.y == [[UIScreen mainScreen] bounds].size.height) + { + //一定要把self.activityButtomView置为空 + [self willShowBottomHeight:toFrame.size.height]; + if (self.activityButtomView) { + [self.activityButtomView removeFromSuperview]; + } + self.activityButtomView = nil; + } + else if (toFrame.origin.y == [[UIScreen mainScreen] bounds].size.height) + { + [self willShowBottomHeight:0]; + } + else{ + [self willShowBottomHeight:toFrame.size.height]; + } +} + +- (void)willShowInputTextViewToHeight:(CGFloat)toHeight +{ + if (toHeight < kInputTextViewMinHeight) { + toHeight = kInputTextViewMinHeight; + } + if (toHeight > self.maxTextInputViewHeight) { + toHeight = self.maxTextInputViewHeight; + } + + if (toHeight == _previousTextViewContentHeight) + { + return; + } + else{ + CGFloat changeHeight = toHeight - _previousTextViewContentHeight; + + CGRect rect = self.frame; + rect.size.height += changeHeight; + rect.origin.y -= changeHeight; + self.frame = rect; + + rect = self.toolbarView.frame; + rect.size.height += changeHeight; + self.toolbarView.frame = rect; + + if (self.version < 7.0) { + [self.inputTextView setContentOffset:CGPointMake(0.0f, (self.inputTextView.contentSize.height - self.inputTextView.frame.size.height) / 2) animated:YES]; + } + _previousTextViewContentHeight = toHeight; + + if (_delegate && [_delegate respondsToSelector:@selector(didChangeFrameToHeight:)]) { + [_delegate didChangeFrameToHeight:self.frame.size.height]; + } + } +} + +- (CGFloat)getTextViewContentH:(UITextView *)textView +{ + if (self.version >= 7.0) + { + return ceilf([textView sizeThatFits:textView.frame.size].height); + } else { + return textView.contentSize.height; + } +} + +#pragma mark - action + +- (void)buttonAction:(id)sender +{ + UIButton *button = (UIButton *)sender; + button.selected = !button.selected; + NSInteger tag = button.tag; + + switch (tag) { + case 0://切换状态 + { + if (button.selected) { + self.faceButton.selected = NO; + self.moreButton.selected = NO; + //录音状态下,不显示底部扩展页面 + [self willShowBottomView:nil]; + + //将inputTextView内容置空,以使toolbarView回到最小高度 + self.inputTextView.text = @""; + [self textViewDidChange:self.inputTextView]; + [self.inputTextView resignFirstResponder]; + } + else{ + //键盘也算一种底部扩展页面 + [self.inputTextView becomeFirstResponder]; + } + + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + self.recordButton.hidden = !button.selected; + self.inputTextView.hidden = button.selected; + } completion:^(BOOL finished) { + + }]; + + if ([self.delegate respondsToSelector:@selector(didStyleChangeToRecord:)]) { + [self.delegate didStyleChangeToRecord:button.selected]; + } + } + break; + case 1://表情 + { + if (button.selected) { + self.moreButton.selected = NO; + //如果选择表情并且处于录音状态,切换成文字输入状态,但是不显示键盘 + if (self.styleChangeButton.selected) { + self.styleChangeButton.selected = NO; + } + else{//如果处于文字输入状态,使文字输入框失去焦点 + [self.inputTextView resignFirstResponder]; + } + + [self willShowBottomView:self.faceView]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + self.recordButton.hidden = button.selected; + self.inputTextView.hidden = !button.selected; + } completion:^(BOOL finished) { + + }]; + } else { + if (!self.styleChangeButton.selected) { + [self.inputTextView becomeFirstResponder]; + } + else{ + [self willShowBottomView:nil]; + } + } + } + break; + case 2://更多 + { + if (button.selected) { + self.faceButton.selected = NO; + //如果选择表情并且处于录音状态,切换成文字输入状态,但是不显示键盘 + if (self.styleChangeButton.selected) { + self.styleChangeButton.selected = NO; + } + else{//如果处于文字输入状态,使文字输入框失去焦点 + [self.inputTextView resignFirstResponder]; + } + + [self willShowBottomView:self.moreView]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + self.recordButton.hidden = button.selected; + self.inputTextView.hidden = !button.selected; + } completion:^(BOOL finished) { + + }]; + } + else + { + self.styleChangeButton.selected = NO; + [self.inputTextView becomeFirstResponder]; + } + } + break; + + default: + break; + } +} + +- (void)recordButtonTouchDown +{ + if ([self.recordView isKindOfClass:[DXRecordView class]]) { + [(DXRecordView *)self.recordView recordButtonTouchDown]; + } + + if (_delegate && [_delegate respondsToSelector:@selector(didStartRecordingVoiceAction:)]) { + [_delegate didStartRecordingVoiceAction:self.recordView]; + } +} + +- (void)recordButtonTouchUpOutside +{ + if (_delegate && [_delegate respondsToSelector:@selector(didCancelRecordingVoiceAction:)]) + { + [_delegate didCancelRecordingVoiceAction:self.recordView]; + } + + if ([self.recordView isKindOfClass:[DXRecordView class]]) { + [(DXRecordView *)self.recordView recordButtonTouchUpOutside]; + } + + [self.recordView removeFromSuperview]; +} + +- (void)recordButtonTouchUpInside +{ + if ([self.recordView isKindOfClass:[DXRecordView class]]) { + [(DXRecordView *)self.recordView recordButtonTouchUpInside]; + } + + if ([self.delegate respondsToSelector:@selector(didFinishRecoingVoiceAction:)]) + { + [self.delegate didFinishRecoingVoiceAction:self.recordView]; + } + + [self.recordView removeFromSuperview]; +} + +- (void)recordDragOutside +{ + if ([self.recordView isKindOfClass:[DXRecordView class]]) { + [(DXRecordView *)self.recordView recordButtonDragOutside]; + } + + if ([self.delegate respondsToSelector:@selector(didDragOutsideAction:)]) + { + [self.delegate didDragOutsideAction:self.recordView]; + } +} + +- (void)recordDragInside +{ + if ([self.recordView isKindOfClass:[DXRecordView class]]) { + [(DXRecordView *)self.recordView recordButtonDragInside]; + } + + if ([self.delegate respondsToSelector:@selector(didDragInsideAction:)]) + { + [self.delegate didDragInsideAction:self.recordView]; + } +} + +#pragma mark - public + +/** + * 停止编辑 + */ +- (BOOL)endEditing:(BOOL)force +{ + BOOL result = [super endEditing:force]; + + self.faceButton.selected = NO; + self.moreButton.selected = NO; + [self willShowBottomView:nil]; + + return result; +} + +/** + * 取消触摸录音键 + */ +- (void)cancelTouchRecord +{ +// self.recordButton.selected = NO; +// self.recordButton.highlighted = NO; + if ([_recordView isKindOfClass:[DXRecordView class]]) { + [(DXRecordView *)_recordView recordButtonTouchUpInside]; + [_recordView removeFromSuperview]; + } +} + ++ (CGFloat)defaultHeight +{ + return kVerticalPadding * 2 + kInputTextViewMinHeight; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXRecordView.h b/Ash_AWord/ViewControllers/Chat/DXRecordView.h new file mode 100644 index 0000000..031ee77 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXRecordView.h @@ -0,0 +1,28 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +@interface DXRecordView : UIView + +// 录音按钮按下 +-(void)recordButtonTouchDown; +// 手指在录音按钮内部时离开 +-(void)recordButtonTouchUpInside; +// 手指在录音按钮外部时离开 +-(void)recordButtonTouchUpOutside; +// 手指移动到录音按钮内部 +-(void)recordButtonDragInside; +// 手指移动到录音按钮外部 +-(void)recordButtonDragOutside; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DXRecordView.m b/Ash_AWord/ViewControllers/Chat/DXRecordView.m new file mode 100755 index 0000000..ba09c6c --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DXRecordView.m @@ -0,0 +1,146 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "DXRecordView.h" +#import "EMCDDeviceManager.h" +@interface DXRecordView () +{ + NSTimer *_timer; + // 显示动画的ImageView + UIImageView *_recordAnimationView; + // 提示文字 + UILabel *_textLabel; +} + +@end + +@implementation DXRecordView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + UIView *bgView = [[UIView alloc] initWithFrame:self.bounds]; + bgView.backgroundColor = [UIColor grayColor]; + bgView.layer.cornerRadius = 5; + bgView.layer.masksToBounds = YES; + bgView.alpha = 0.6; + [self addSubview:bgView]; + + _recordAnimationView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 0, self.bounds.size.width - 20, self.bounds.size.height - 10)]; + _recordAnimationView.image = [UIImage imageNamed:@"VoiceSearchFeedback001"]; + [self addSubview:_recordAnimationView]; + + _textLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, + self.bounds.size.height - 30, + self.bounds.size.width - 10, + 25)]; + + _textLabel.textAlignment = NSTextAlignmentCenter; + _textLabel.backgroundColor = [UIColor clearColor]; + _textLabel.text = NSLocalizedString(@"message.toolBar.record.upCancel", @"Fingers up slide, cancel sending"); + [self addSubview:_textLabel]; + _textLabel.font = [UIFont systemFontOfSize:13]; + _textLabel.textColor = [UIColor whiteColor]; + _textLabel.layer.cornerRadius = 5; + _textLabel.layer.borderColor = [[UIColor redColor] colorWithAlphaComponent:0.5].CGColor; + _textLabel.layer.masksToBounds = YES; + } + return self; +} + +// 录音按钮按下 +-(void)recordButtonTouchDown +{ + // 需要根据声音大小切换recordView动画 + _textLabel.text = NSLocalizedString(@"message.toolBar.record.upCancel", @"Fingers up slide, cancel sending"); + _textLabel.backgroundColor = [UIColor clearColor]; + _timer = [NSTimer scheduledTimerWithTimeInterval:0.05 + target:self + selector:@selector(setVoiceImage) + userInfo:nil + repeats:YES]; + +} +// 手指在录音按钮内部时离开 +-(void)recordButtonTouchUpInside +{ + [_timer invalidate]; +} +// 手指在录音按钮外部时离开 +-(void)recordButtonTouchUpOutside +{ + [_timer invalidate]; +} +// 手指移动到录音按钮内部 +-(void)recordButtonDragInside +{ + _textLabel.text = NSLocalizedString(@"message.toolBar.record.upCancel", @"Fingers up slide, cancel sending"); + _textLabel.backgroundColor = [UIColor clearColor]; +} + +// 手指移动到录音按钮外部 +-(void)recordButtonDragOutside +{ + _textLabel.text = NSLocalizedString(@"message.toolBar.record.loosenCancel", @"loosen the fingers, to cancel sending"); + _textLabel.backgroundColor = [UIColor redColor]; +} + +-(void)setVoiceImage { + _recordAnimationView.image = [UIImage imageNamed:@"VoiceSearchFeedback001"]; + double voiceSound = 0; + voiceSound = [[EMCDDeviceManager sharedInstance] emPeekRecorderVoiceMeter]; + if (0 < voiceSound <= 0.05) { + [_recordAnimationView setImage:[UIImage imageNamed:@"VoiceSearchFeedback001"]]; + }else if (0.05 +#import "EMCDDeviceManagerProximitySensorDelegate.h" + +@protocol EMCDDeviceManagerDelegate + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/delegates/EMCDDeviceManagerProximitySensorDelegate.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/delegates/EMCDDeviceManagerProximitySensorDelegate.h new file mode 100644 index 0000000..7a6f37d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/delegates/EMCDDeviceManagerProximitySensorDelegate.h @@ -0,0 +1,20 @@ +// +// EMCDDeviceManagerProximitySensorDelegate.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import + +@protocol EMCDDeviceManagerProximitySensorDelegate +/*! + @method + @brief 当手机靠近耳朵时或者离开耳朵时的回调方法 + @param isCloseToUser YES为靠近了用户, NO为远离了用户 + @discussion + @result + */ +- (void)proximitySensorChanged:(BOOL)isCloseToUser; +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioPlayerUtil.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioPlayerUtil.h new file mode 100644 index 0000000..1362bc4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioPlayerUtil.h @@ -0,0 +1,25 @@ +// +// EMAudioPlayerUtil.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/8/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import + +@interface EMAudioPlayerUtil : NSObject +// 当前是否正在播放 ++ (BOOL)isPlaying; + +// 得到当前播放音频路径 ++ (NSString *)playingFilePath; + +// 播放指定路径下音频(wav) ++ (void)asyncPlayingWithPath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completon; + +// 停止当前播放音频 ++ (void)stopCurrentPlaying; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioPlayerUtil.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioPlayerUtil.m new file mode 100644 index 0000000..916667d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioPlayerUtil.m @@ -0,0 +1,154 @@ +// +// EMAudioPlayerUtil.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/8/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMAudioPlayerUtil.h" +#import +#import "EMErrorDefs.h" +static EMAudioPlayerUtil *audioPlayerUtil = nil; + +@interface EMAudioPlayerUtil () { + AVAudioPlayer *_player; + void (^playFinish)(NSError *error); +} + +@end + +@implementation EMAudioPlayerUtil + +#pragma mark - public ++ (BOOL)isPlaying{ + return [[EMAudioPlayerUtil sharedInstance] isPlaying]; +} + ++ (NSString *)playingFilePath{ + return [[EMAudioPlayerUtil sharedInstance] playingFilePath]; +} + ++ (void)asyncPlayingWithPath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completon{ + [[EMAudioPlayerUtil sharedInstance] asyncPlayingWithPath:aFilePath + completion:completon]; +} + ++ (void)stopCurrentPlaying{ + [[EMAudioPlayerUtil sharedInstance] stopCurrentPlaying]; +} + + +#pragma mark - private ++ (EMAudioPlayerUtil *)sharedInstance{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + audioPlayerUtil = [[self alloc] init]; + }); + + return audioPlayerUtil; +} + +// 当前是否正在播放 +- (BOOL)isPlaying +{ + return !!_player; +} + +// 得到当前播放音频路径 +- (NSString *)playingFilePath +{ + NSString *path = nil; + if (_player && _player.isPlaying) { + path = _player.url.path; + } + + return path; +} + +- (void)asyncPlayingWithPath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completon{ + playFinish = completon; + NSError *error = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + if (![fm fileExistsAtPath:aFilePath]) { + error = [NSError errorWithDomain:@"File path not exist" + code:EMErrorAttachmentNotFound + userInfo:nil]; + if (playFinish) { + playFinish(error); + } + playFinish = nil; + + return; + } + + NSURL *wavUrl = [[NSURL alloc] initFileURLWithPath:aFilePath]; + _player = [[AVAudioPlayer alloc] initWithContentsOfURL:wavUrl error:&error]; + if (error || !_player) { + _player = nil; + error = [NSError errorWithDomain:@"Failed to initialize AVAudioPlayer" + code:EMErrorInitFailure + userInfo:nil]; + if (playFinish) { + playFinish(error); + } + playFinish = nil; + return; + } + + _player.delegate = self; + [_player prepareToPlay]; + [_player play]; +} + +// 停止当前播放 +- (void)stopCurrentPlaying{ + if(_player){ + _player.delegate = nil; + [_player stop]; + _player = nil; + } + if (playFinish) { + playFinish = nil; + } +} + +- (void)dealloc{ + if (_player) { + _player.delegate = nil; + [_player stop]; + _player = nil; + } + playFinish = nil; +} + +#pragma mark - AVAudioPlayerDelegate +- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player + successfully:(BOOL)flag{ + if (playFinish) { + playFinish(nil); + } + if (_player) { + _player.delegate = nil; + _player = nil; + } + playFinish = nil; +} + +- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player + error:(NSError *)error{ + if (playFinish) { + NSError *error = [NSError errorWithDomain:@"Play failure" + code:EMErrorFailure + userInfo:nil]; + playFinish(error); + } + if (_player) { + _player.delegate = nil; + _player = nil; + } +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioRecorderUtil.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioRecorderUtil.h new file mode 100644 index 0000000..a371ab6 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioRecorderUtil.h @@ -0,0 +1,27 @@ +// +// EMAudioRecorderUtil.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/8/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import +#import +@interface EMAudioRecorderUtil : NSObject + +// 当前是否正在录音 ++(BOOL)isRecording; + +// 开始录音 ++ (void)asyncStartRecordingWithPreparePath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completion; +// 停止录音 ++(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath))completion; + +// 取消录音 ++(void)cancelCurrentRecording; + +// current recorder ++(AVAudioRecorder *)recorder; +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioRecorderUtil.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioRecorderUtil.m new file mode 100644 index 0000000..86ac37b --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMAudioRecorderUtil.m @@ -0,0 +1,171 @@ +// +// EMAudioRecorderUtil.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/8/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMAudioRecorderUtil.h" +#import "EMErrorDefs.h" +static EMAudioRecorderUtil *audioRecorderUtil = nil; + +@interface EMAudioRecorderUtil () { + NSDate *_startDate; + NSDate *_endDate; + + void (^recordFinish)(NSString *recordPath); +} +@property (nonatomic, strong) AVAudioRecorder *recorder; +@property (nonatomic, strong) NSDictionary *recordSetting; + +@end + +@implementation EMAudioRecorderUtil + +#pragma mark - Public +// 当前是否正在录音 ++(BOOL)isRecording{ + return [[EMAudioRecorderUtil sharedInstance] isRecording]; +} + +// 开始录音 ++ (void)asyncStartRecordingWithPreparePath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completion{ + [[EMAudioRecorderUtil sharedInstance] asyncStartRecordingWithPreparePath:aFilePath + completion:completion]; +} + +// 停止录音 ++(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath))completion{ + [[EMAudioRecorderUtil sharedInstance] asyncStopRecordingWithCompletion:completion]; +} + +// 取消录音 ++(void)cancelCurrentRecording{ + [[EMAudioRecorderUtil sharedInstance] cancelCurrentRecording]; +} + ++(AVAudioRecorder *)recorder{ + return [EMAudioRecorderUtil sharedInstance].recorder; +} + +#pragma mark - getter +- (NSDictionary *)recordSetting +{ + if (!_recordSetting) { + _recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys: + [NSNumber numberWithFloat: 8000.0],AVSampleRateKey, //采样率 + [NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey, + [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//采样位数 默认 16 + [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,//通道的数目 + nil]; + } + + return _recordSetting; +} + +#pragma mark - Private ++(EMAudioRecorderUtil *)sharedInstance{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + audioRecorderUtil = [[self alloc] init]; + }); + + return audioRecorderUtil; +} + +-(instancetype)init{ + if (self = [super init]) { + + } + + return self; +} + +-(void)dealloc{ + if (_recorder) { + _recorder.delegate = nil; + [_recorder stop]; + [_recorder deleteRecording]; + _recorder = nil; + } + recordFinish = nil; +} + +-(BOOL)isRecording{ + return !!_recorder; +} + +// 开始录音,文件放到aFilePath下 +- (void)asyncStartRecordingWithPreparePath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completion +{ + NSError *error = nil; + NSString *wavFilePath = [[aFilePath stringByDeletingPathExtension] + stringByAppendingPathExtension:@"wav"]; + NSURL *wavUrl = [[NSURL alloc] initFileURLWithPath:wavFilePath]; + _recorder = [[AVAudioRecorder alloc] initWithURL:wavUrl + settings:self.recordSetting + error:&error]; + if(!_recorder || error) + { + _recorder = nil; + if (completion) { + error = [NSError errorWithDomain:@"Failed to initialize AVAudioRecorder" + code:EMErrorInitFailure + userInfo:nil]; + completion(error); + } + return ; + } + _startDate = [NSDate date]; + _recorder.meteringEnabled = YES; + _recorder.delegate = self; + + [_recorder record]; + if (completion) { + completion(error); + } +} + +// 停止录音 +-(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath))completion{ + recordFinish = completion; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self->_recorder stop]; + }); +} + +// 取消录音 +- (void)cancelCurrentRecording +{ + _recorder.delegate = nil; + if (_recorder.recording) { + [_recorder stop]; + } + _recorder = nil; + recordFinish = nil; +} + + +#pragma mark - AVAudioRecorderDelegate +- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder + successfully:(BOOL)flag +{ + NSString *recordPath = [[_recorder url] path]; + if (recordFinish) { + if (!flag) { + recordPath = nil; + } + recordFinish(recordPath); + } + _recorder = nil; + recordFinish = nil; +} + +- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder + error:(NSError *)error{ + NSLog(@"audioRecorderEncodeErrorDidOccur"); +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Media.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Media.h new file mode 100644 index 0000000..0312e8d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Media.h @@ -0,0 +1,41 @@ +// +// EMCDDeviceManager+Media.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManagerBase.h" + +@interface EMCDDeviceManager (Media) + +#pragma mark - AudioPlayer +// 播放音频 +- (void)asyncPlayingWithPath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completon; +// 停止播放 +- (void)stopPlaying; + +- (void)stopPlayingWithChangeCategory:(BOOL)isChange; + +// 当前是否正在播放 +-(BOOL)isPlaying; + +#pragma mark - AudioRecorder +// 开始录音 +- (void)asyncStartRecordingWithFileName:(NSString *)fileName + completion:(void(^)(NSError *error))completion; + +// 停止录音 +-(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath, + NSInteger aDuration, + NSError *error))completion; +// 取消录音 +-(void)cancelCurrentRecording; + + +// 当前是否正在录音 +-(BOOL)isRecording; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Media.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Media.m new file mode 100644 index 0000000..6d75f5a --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Media.m @@ -0,0 +1,284 @@ +// +// EMCDDeviceManager+Media.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManager+Media.h" +#import "EMAudioPlayerUtil.h" +#import "EMAudioRecorderUtil.h" +#import "EMVoiceConverter.h" + +typedef NS_ENUM(NSInteger, EMAudioSession){ + EM_DEFAULT = 0, + EM_AUDIOPLAYER, + EM_AUDIORECORDER +}; + +@implementation EMCDDeviceManager (Media) +#pragma mark - AudioPlayer +// 播放音频 +- (void)asyncPlayingWithPath:(NSString *)aFilePath + completion:(void(^)(NSError *error))completon{ + BOOL isNeedSetActive = YES; + // 如果正在播放音频,停止当前播放。 + if([EMAudioPlayerUtil isPlaying]){ + [EMAudioPlayerUtil stopCurrentPlaying]; + isNeedSetActive = NO; + } + + if (isNeedSetActive) { + // 设置播放时需要的category + [self setupAudioSessionCategory:EM_AUDIOPLAYER + isActive:YES]; + } + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *wavFilePath = [[aFilePath stringByDeletingPathExtension] stringByAppendingPathExtension:@"wav"]; + //如果转换后的wav文件不存在, 则去转换一下 + if (![fileManager fileExistsAtPath:wavFilePath]) { + BOOL covertRet = [self convertAMR:aFilePath toWAV:wavFilePath]; + if (!covertRet) { + if (completon) { + completon([NSError errorWithDomain:@"File format conversion failed" + code:EMErrorFileTypeConvertionFailure + userInfo:nil]); + } + return ; + } + } + [EMAudioPlayerUtil asyncPlayingWithPath:wavFilePath + completion:^(NSError *error) + { + [self setupAudioSessionCategory:EM_DEFAULT + isActive:NO]; + if (completon) { + completon(error); + } + }]; +} + +// 停止播放 +- (void)stopPlaying{ + [EMAudioPlayerUtil stopCurrentPlaying]; + [self setupAudioSessionCategory:EM_DEFAULT + isActive:NO]; +} + +- (void)stopPlayingWithChangeCategory:(BOOL)isChange{ + [EMAudioPlayerUtil stopCurrentPlaying]; + if (isChange) { + [self setupAudioSessionCategory:EM_DEFAULT + isActive:NO]; + } +} + +// 获取播放状态 +- (BOOL)isPlaying{ + return [EMAudioPlayerUtil isPlaying]; +} + +#pragma mark - Recorder + ++(NSTimeInterval)recordMinDuration{ + return 1.0; +} + +// 开始录音 +- (void)asyncStartRecordingWithFileName:(NSString *)fileName + completion:(void(^)(NSError *error))completion{ + NSError *error = nil; + + // 判断当前是否是录音状态 + if ([self isRecording]) { + if (completion) { + error = [NSError errorWithDomain:@"Record voice is not over yet" + code:EMErrorAudioRecordStoping + userInfo:nil]; + completion(error); + } + return ; + } + + // 文件名不存在 + if (!fileName || [fileName length] == 0) { + error = [NSError errorWithDomain:@"File name not exist" + code:EMErrorAttachmentNotFound + userInfo:nil]; + completion(error); + return ; + } + + BOOL isNeedSetActive = YES; + if ([self isRecording]) { + [EMAudioRecorderUtil cancelCurrentRecording]; + isNeedSetActive = NO; + } + + [self setupAudioSessionCategory:EM_AUDIORECORDER + isActive:YES]; + + _recorderStartDate = [NSDate date]; + + NSString *recordPath = NSHomeDirectory(); + recordPath = [NSString stringWithFormat:@"%@/Library/appdata/chatbuffer/%@",recordPath,fileName]; + NSFileManager *fm = [NSFileManager defaultManager]; + if(![fm fileExistsAtPath:[recordPath stringByDeletingLastPathComponent]]){ + [fm createDirectoryAtPath:[recordPath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:nil]; + } + + [EMAudioRecorderUtil asyncStartRecordingWithPreparePath:recordPath + completion:completion]; +} + +// 停止录音 +-(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath, + NSInteger aDuration, + NSError *error))completion{ + NSError *error = nil; + // 当前是否在录音 + if(![self isRecording]){ + if (completion) { + error = [NSError errorWithDomain:@"Recording has not yet begun" + code:EMErrorAudioRecordNotStarted + userInfo:nil]; + completion(nil,0,error); + return; + } + } + + __weak typeof(self) weakSelf = self; + _recorderEndDate = [NSDate date]; + + if([_recorderEndDate timeIntervalSinceDate:_recorderStartDate] < [EMCDDeviceManager recordMinDuration]){ + if (completion) { + error = [NSError errorWithDomain:@"Recording time is too short" + code:EMErrorAudioRecordDurationTooShort + userInfo:nil]; + completion(nil,0,error); + } + + // 如果录音时间较短,延迟1秒停止录音(iOS中,如果快速开始,停止录音,UI上会出现红条,为了防止用户又迅速按下,UI上需要也加一个延迟,长度大于此处的延迟时间,不允许用户循序重新录音。PS:研究了QQ和微信,就这么玩的,聪明) + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)([EMCDDeviceManager recordMinDuration] * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [EMAudioRecorderUtil asyncStopRecordingWithCompletion:^(NSString *recordPath) { + [weakSelf setupAudioSessionCategory:EM_DEFAULT isActive:NO]; + }]; + }); + return ; + } + + [EMAudioRecorderUtil asyncStopRecordingWithCompletion:^(NSString *recordPath) { + if (completion) { + if (recordPath) { + //录音格式转换,从wav转为amr + NSString *amrFilePath = [[recordPath stringByDeletingPathExtension] + stringByAppendingPathExtension:@"amr"]; + BOOL convertResult = [self convertWAV:recordPath toAMR:amrFilePath]; + if (convertResult) { + // 删除录的wav + NSFileManager *fm = [NSFileManager defaultManager]; + [fm removeItemAtPath:recordPath error:nil]; + } + completion(amrFilePath,(int)[self->_recorderEndDate timeIntervalSinceDate:self->_recorderStartDate],nil); + } + [weakSelf setupAudioSessionCategory:EM_DEFAULT isActive:NO]; + } + }]; +} + +// 取消录音 +-(void)cancelCurrentRecording{ + [EMAudioRecorderUtil cancelCurrentRecording]; +} + +// 获取录音状态 +-(BOOL)isRecording{ + return [EMAudioRecorderUtil isRecording]; +} + +#pragma mark - Private +-(NSError *)setupAudioSessionCategory:(EMAudioSession)session + isActive:(BOOL)isActive{ + BOOL isNeedActive = NO; + if (isActive != _currActive) { + isNeedActive = YES; + _currActive = isActive; + } + NSError *error = nil; + NSString *audioSessionCategory = nil; + switch (session) { + case EM_AUDIOPLAYER: + // 设置播放category + audioSessionCategory = AVAudioSessionCategoryPlayback; + break; + case EM_AUDIORECORDER: + // 设置录音category + audioSessionCategory = AVAudioSessionCategoryRecord; + break; + default: + // 还原category + audioSessionCategory = AVAudioSessionCategoryAmbient; + break; + } + + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + // 如果当前category等于要设置的,不需要再设置 + if (![_currCategory isEqualToString:audioSessionCategory]) { + [audioSession setCategory:audioSessionCategory error:nil]; + } + if (isNeedActive) { + BOOL success = [audioSession setActive:isActive + withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation + error:&error]; + if(!success || error){ + error = [NSError errorWithDomain:@"Failed to initialize AVAudioPlayer" + code:EMErrorInitFailure + userInfo:nil]; + return error; + } + } + _currCategory = audioSessionCategory; + + return error; +} + +#pragma mark - Convert + +- (BOOL)convertAMR:(NSString *)amrFilePath + toWAV:(NSString *)wavFilePath +{ + BOOL ret = NO; + BOOL isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:amrFilePath]; + if (isFileExists) { + [EMVoiceConverter amrToWav:amrFilePath wavSavePath:wavFilePath]; + isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:wavFilePath]; + if (isFileExists) { + ret = YES; + } + } + + return ret; +} + +- (BOOL)convertWAV:(NSString *)wavFilePath + toAMR:(NSString *)amrFilePath { + BOOL ret = NO; + BOOL isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:wavFilePath]; + if (isFileExists) { + [EMVoiceConverter wavToAmr:wavFilePath amrSavePath:amrFilePath]; + isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:amrFilePath]; + if (!isFileExists) { + + } else { + ret = YES; + } + } + + return ret; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Microphone.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Microphone.h new file mode 100644 index 0000000..8efd82a --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Microphone.h @@ -0,0 +1,17 @@ +// +// EMCDDeviceManager+Microphone.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManager.h" + +@interface EMCDDeviceManager (Microphone) +// 判断麦克风是否可用 +- (BOOL)emCheckMicrophoneAvailability; + +// 获取录制音频时的音量(0~1) +- (double)emPeekRecorderVoiceMeter; +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Microphone.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Microphone.m new file mode 100644 index 0000000..ff953b1 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Microphone.m @@ -0,0 +1,41 @@ +// +// EMCDDeviceManager+Microphone.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManager+Microphone.h" +#import "EMAudioRecorderUtil.h" + +@implementation EMCDDeviceManager (Microphone) +// 判断麦克风是否可用 +- (BOOL)emCheckMicrophoneAvailability{ + __block BOOL ret = NO; + AVAudioSession *session = [AVAudioSession sharedInstance]; + if ([session respondsToSelector:@selector(requestRecordPermission:)]) { + [session performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) { + ret = granted; + }]; + } else { + ret = YES; + } + + return ret; +} + +// 获取录制音频时的音量(0~1) +- (double)emPeekRecorderVoiceMeter{ + double ret = 0.0; + if ([EMAudioRecorderUtil recorder].isRecording) { + [[EMAudioRecorderUtil recorder] updateMeters]; + //获取音量的平均值 [recorder averagePowerForChannel:0]; + //音量的最大值 [recorder peakPowerForChannel:0]; + double lowPassResults = pow(10, (0.05 * [[EMAudioRecorderUtil recorder] peakPowerForChannel:0])); + ret = lowPassResults; + } + + return ret; +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+ProximitySensor.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+ProximitySensor.h new file mode 100644 index 0000000..6e9bdb5 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+ProximitySensor.h @@ -0,0 +1,20 @@ +// +// EMCDDeviceManager+ProximitySensor.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManagerBase.h" + +@interface EMCDDeviceManager (ProximitySensor) +#pragma mark - proximity sensor +@property (nonatomic, readonly) BOOL isSupportProximitySensor; +@property (nonatomic, readonly) BOOL isCloseToUser; +@property (nonatomic, readonly) BOOL isProximitySensorEnabled; + +- (BOOL)enableProximitySensor; +- (BOOL)disableProximitySensor; +- (void)sensorStateChanged:(NSNotification *)notification; +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+ProximitySensor.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+ProximitySensor.m new file mode 100644 index 0000000..9deac05 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+ProximitySensor.m @@ -0,0 +1,64 @@ +// +// EMCDDeviceManager+ProximitySensor.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManager+ProximitySensor.h" + +@implementation EMCDDeviceManager (ProximitySensor) +@dynamic isSupportProximitySensor; +@dynamic isCloseToUser; + + +#pragma mark - proximity sensor +- (BOOL)isProximitySensorEnabled { + BOOL ret = NO; + ret = self.isSupportProximitySensor && [UIDevice currentDevice].proximityMonitoringEnabled; + + return ret; +} + +- (BOOL)enableProximitySensor { + BOOL ret = NO; + if (_isSupportProximitySensor) { + [[UIDevice currentDevice] setProximityMonitoringEnabled:YES]; + ret = YES; + } + + return ret; +} + +- (BOOL)disableProximitySensor { + BOOL ret = NO; + if (_isSupportProximitySensor) { + [[UIDevice currentDevice] setProximityMonitoringEnabled:NO]; + _isCloseToUser = NO; + ret = YES; + } + + return ret; +} + +- (void)sensorStateChanged:(NSNotification *)notification { + BOOL ret = NO; + if ([[UIDevice currentDevice] proximityState] == YES) { + ret = YES; + } + _isCloseToUser = ret; + if([self.delegate respondsToSelector:@selector(proximitySensorChanged:)]){ + [self.delegate proximitySensorChanged:_isCloseToUser]; + } +} + +#pragma mark - getter +- (BOOL)isCloseToUser { + return _isCloseToUser; +} + +- (BOOL)isSupportProximitySensor { + return _isSupportProximitySensor; +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Remind.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Remind.h new file mode 100644 index 0000000..109b180 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Remind.h @@ -0,0 +1,17 @@ +// +// EMCDDeviceManager+Remind.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManager.h" +#import +@interface EMCDDeviceManager (Remind) +// 播放接收到新消息时的声音 +- (SystemSoundID)playNewMessageSound; + +// 震动 +- (void)playVibration; +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Remind.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Remind.m new file mode 100644 index 0000000..ec93151 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager+Remind.m @@ -0,0 +1,55 @@ +// +// EMCDDeviceManager+Remind.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManager+Remind.h" + +/** + * 系统铃声播放完成后的回调 + */ +void EMSystemSoundFinishedPlayingCallback(SystemSoundID sound_id, void* user_data) +{ + AudioServicesDisposeSystemSoundID(sound_id); +} + +@implementation EMCDDeviceManager (Remind) +// 播放接收到新消息时的声音 +- (SystemSoundID)playNewMessageSound +{ + // 要播放的音频文件地址 + NSURL *bundlePath = [[NSBundle mainBundle] URLForResource:@"EaseMob" withExtension:@"bundle"]; + NSURL *audioPath = [[NSBundle bundleWithURL:bundlePath] URLForResource:@"in" withExtension:@"caf"]; + // 创建系统声音,同时返回一个ID + SystemSoundID soundID; + AudioServicesCreateSystemSoundID((__bridge CFURLRef)(audioPath), &soundID); + // Register the sound completion callback. + AudioServicesAddSystemSoundCompletion(soundID, + NULL, // uses the main run loop + NULL, // uses kCFRunLoopDefaultMode + EMSystemSoundFinishedPlayingCallback, // the name of our custom callback function + NULL // for user data, but we don't need to do that in this case, so we just pass NULL + ); + + AudioServicesPlaySystemSound(soundID); + + return soundID; +} + +// 震动 +- (void)playVibration +{ + // Register the sound completion callback. + AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate, + NULL, // uses the main run loop + NULL, // uses kCFRunLoopDefaultMode + EMSystemSoundFinishedPlayingCallback, // the name of our custom callback function + NULL // for user data, but we don't need to do that in this case, so we just pass NULL + ); + + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager.h new file mode 100644 index 0000000..8b9a920 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManager.h @@ -0,0 +1,17 @@ +// +// EMCDDeviceManager.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#ifndef ChatDemo_UI2_0_EMCDDeviceManager_h +#define ChatDemo_UI2_0_EMCDDeviceManager_h + +#import "EMCDDeviceManager+Media.h" +#import "EMCDDeviceManager+Remind.h" +#import "EMCDDeviceManager+Microphone.h" +#import "EMCDDeviceManager+ProximitySensor.h" + +#endif diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManagerBase.h b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManagerBase.h new file mode 100644 index 0000000..89b009e --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManagerBase.h @@ -0,0 +1,29 @@ +// +// EMCDDeviceManager.h +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import +#import "EMCDDeviceManagerDelegate.h" + +@interface EMCDDeviceManager : NSObject{ + // recorder + NSDate *_recorderStartDate; + NSDate *_recorderEndDate; + NSString *_currCategory; + BOOL _currActive; + + // proximitySensor + BOOL _isSupportProximitySensor; + BOOL _isCloseToUser; +} + +@property (nonatomic, assign) id delegate; + ++(EMCDDeviceManager *)sharedInstance; + + +@end diff --git a/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManagerBase.m b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManagerBase.m new file mode 100644 index 0000000..b1c4053 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/DeviceUtil/internal/EMCDDeviceManagerBase.m @@ -0,0 +1,71 @@ +// +// EMCDDeviceManager.m +// ChatDemo-UI2.0 +// +// Created by dujiepeng on 5/14/15. +// Copyright (c) 2015 dujiepeng. All rights reserved. +// + +#import "EMCDDeviceManagerBase.h" +#import "EMCDDeviceManager+ProximitySensor.h" + +static EMCDDeviceManager *emCDDeviceManager; +@interface EMCDDeviceManager (){ + +} + +@end + +@implementation EMCDDeviceManager ++(EMCDDeviceManager *)sharedInstance{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + emCDDeviceManager = [[EMCDDeviceManager alloc] init]; + }); + + return emCDDeviceManager; +} + +-(instancetype)init{ + if (self = [super init]) { + [self _setupProximitySensor]; + [self registerNotifications]; + } + return self; +} + +- (void)registerNotifications +{ + [self unregisterNotifications]; + if (_isSupportProximitySensor) { + static NSString *notif = @"UIDeviceProximityStateDidChangeNotification"; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(sensorStateChanged:) + name:notif + object:nil]; + } +} + +- (void)unregisterNotifications { + if (_isSupportProximitySensor) { + static NSString *notif = @"UIDeviceProximityStateDidChangeNotification"; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:notif + object:nil]; + } +} + +- (void)_setupProximitySensor +{ + UIDevice *device = [UIDevice currentDevice]; + [device setProximityMonitoringEnabled:YES]; + _isSupportProximitySensor = device.proximityMonitoringEnabled; + if (_isSupportProximitySensor) { + [device setProximityMonitoringEnabled:NO]; + } else { + + } +} + + +@end diff --git a/Ash_AWord/ViewControllers/Chat/Emoji/Emoji.h b/Ash_AWord/ViewControllers/Chat/Emoji/Emoji.h new file mode 100755 index 0000000..dc0ae58 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/Emoji/Emoji.h @@ -0,0 +1,44 @@ +/*! + @header emoji.h + @abstract 提供对iOS内置表情编码处理 + @author EaseMob Inc. + @version 1.00 2014/01/01 Creation (1.00) + */ + +#import + +#define MAKE_Q(x) @#x +#define MAKE_EM(x,y) MAKE_Q(x##y) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunicode" +#define MAKE_EMOJI(x) MAKE_EM(\U000,x) +#pragma clang diagnostic pop + +#define EMOJI_METHOD(x,y) + (NSString *)x { return MAKE_EMOJI(y); } +#define EMOJI_HMETHOD(x) + (NSString *)x; +#define EMOJI_CODE_TO_SYMBOL(x) ((((0x808080F0 | (x & 0x3F000) >> 4) | (x & 0xFC0) << 10) | (x & 0x1C0000) << 18) | (x & 0x3F) << 24); + +/*! + @class + @brief iOS内置表情编码处理类 + */ +@interface Emoji : NSObject + +/*! + @method + @brief unicode编码转换为iOS内置表情字符串 + @discussion + @param code iOS内置表情对应的unicode编码值 + @result iOS内置表情字符串 + */ ++ (NSString *)emojiWithCode:(int)code; + +/*! + @method + @brief 获取所有iOS内置表情 + @discussion + @result iOS表情字符串数组 + */ ++ (NSArray *)allEmoji; +@end diff --git a/Ash_AWord/ViewControllers/Chat/Emoji/Emoji.m b/Ash_AWord/ViewControllers/Chat/Emoji/Emoji.m new file mode 100755 index 0000000..3076b5d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/Emoji/Emoji.m @@ -0,0 +1,23 @@ +// +// Emoji.m +// Emoji +// +// Created by Aliksandr Andrashuk on 26.10.12. +// Copyright (c) 2012 Aliksandr Andrashuk. All rights reserved. +// + +#import "Emoji.h" +#import "EmojiEmoticons.h" + + +@implementation Emoji ++ (NSString *)emojiWithCode:(int)code { + int sym = EMOJI_CODE_TO_SYMBOL(code); + return [[NSString alloc] initWithBytes:&sym length:sizeof(sym) encoding:NSUTF8StringEncoding]; +} ++ (NSArray *)allEmoji { + NSMutableArray *array = [NSMutableArray new]; + [array addObjectsFromArray:[EmojiEmoticons allEmoticons]]; + return array; +} +@end diff --git a/Ash_AWord/ViewControllers/Chat/Emoji/EmojiEmoticons.h b/Ash_AWord/ViewControllers/Chat/Emoji/EmojiEmoticons.h new file mode 100755 index 0000000..e89b326 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/Emoji/EmojiEmoticons.h @@ -0,0 +1,92 @@ +// +// EmojiEmoticons.h +// Emoji +// +// Created by Aliksandr Andrashuk on 26.10.12. +// Copyright (c) 2012 Aliksandr Andrashuk. All rights reserved. +// + +#import +#import "Emoji.h" + +@interface EmojiEmoticons : NSObject + ++ (NSArray *)allEmoticons; + +EMOJI_HMETHOD(grinningFace); +EMOJI_HMETHOD(grinningFaceWithSmilingEyes); +EMOJI_HMETHOD(faceWithTearsOfJoy); +EMOJI_HMETHOD(smilingFaceWithOpenMouth); +EMOJI_HMETHOD(smilingFaceWithOpenMouthAndSmilingEyes); +EMOJI_HMETHOD(smilingFaceWithOpenMouthAndColdSweat); +EMOJI_HMETHOD(smilingFaceWithOpenMouthAndTightlyClosedEyes); +EMOJI_HMETHOD(smilingFaceWithHalo); +EMOJI_HMETHOD(smilingFaceWithHorns); +EMOJI_HMETHOD(winkingFace); +EMOJI_HMETHOD(smilingFaceWithSmilingEyes); +EMOJI_HMETHOD(faceSavouringDeliciousFood); +EMOJI_HMETHOD(relievedFace); +EMOJI_HMETHOD(smilingFaceWithHeartShapedEyes); +EMOJI_HMETHOD(smilingFaceWithSunglasses); +EMOJI_HMETHOD(smirkingFace); +EMOJI_HMETHOD(neutralFace); +EMOJI_HMETHOD(expressionlessFace); +EMOJI_HMETHOD(unamusedFace); +EMOJI_HMETHOD(faceWithColdSweat); +EMOJI_HMETHOD(pensiveFace); +EMOJI_HMETHOD(confusedFace); +EMOJI_HMETHOD(confoundedFace); +EMOJI_HMETHOD(kissingFace); +EMOJI_HMETHOD(faceThrowingAKiss); +EMOJI_HMETHOD(kissingFaceWithSmilingEyes); +EMOJI_HMETHOD(kissingFaceWithClosedEyes); +EMOJI_HMETHOD(faceWithStuckOutTongue); +EMOJI_HMETHOD(faceWithStuckOutTongueAndWinkingEye); +EMOJI_HMETHOD(faceWithStuckOutTongueAndTightlyClosedEyes); +EMOJI_HMETHOD(disappointedFace); +EMOJI_HMETHOD(worriedFace); +EMOJI_HMETHOD(angryFace); +EMOJI_HMETHOD(poutingFace); +EMOJI_HMETHOD(cryingFace); +EMOJI_HMETHOD(perseveringFace); +EMOJI_HMETHOD(faceWithLookOfTriumph); +EMOJI_HMETHOD(disappointedButRelievedFace); +EMOJI_HMETHOD(frowningFaceWithOpenMouth); +EMOJI_HMETHOD(anguishedFace); +EMOJI_HMETHOD(fearfulFace); +EMOJI_HMETHOD(wearyFace); +EMOJI_HMETHOD(sleepyFace); +EMOJI_HMETHOD(tiredFace); +EMOJI_HMETHOD(grimacingFace); +EMOJI_HMETHOD(loudlyCryingFace); +EMOJI_HMETHOD(faceWithOpenMouth); +EMOJI_HMETHOD(hushedFace); +EMOJI_HMETHOD(faceWithOpenMouthAndColdSweat); +EMOJI_HMETHOD(faceScreamingInFear); +EMOJI_HMETHOD(astonishedFace); +EMOJI_HMETHOD(flushedFace); +EMOJI_HMETHOD(sleepingFace); +EMOJI_HMETHOD(dizzyFace); +EMOJI_HMETHOD(faceWithoutMouth); +EMOJI_HMETHOD(faceWithMedicalMask); +EMOJI_HMETHOD(grinningCatFaceWithSmilingEyes); +EMOJI_HMETHOD(catFaceWithTearsOfJoy); +EMOJI_HMETHOD(smilingCatFaceWithOpenMouth); +EMOJI_HMETHOD(smilingCatFaceWithHeartShapedEyes); +EMOJI_HMETHOD(catFaceWithWrySmile); +EMOJI_HMETHOD(kissingCatFaceWithClosedEyes); +EMOJI_HMETHOD(poutingCatFace); +EMOJI_HMETHOD(cryingCatFace); +EMOJI_HMETHOD(wearyCatFace); +EMOJI_HMETHOD(faceWithNoGoodGesture); +EMOJI_HMETHOD(faceWithOkGesture); +EMOJI_HMETHOD(personBowingDeeply); +EMOJI_HMETHOD(seeNoEvilMonkey); +EMOJI_HMETHOD(hearNoEvilMonkey); +EMOJI_HMETHOD(speakNoEvilMonkey); +EMOJI_HMETHOD(happyPersonRaisingOneHand); +EMOJI_HMETHOD(personRaisingBothHandsInCelebration); +EMOJI_HMETHOD(personFrowning); +EMOJI_HMETHOD(personWithPoutingFace); +EMOJI_HMETHOD(personWithFoldedHands); +@end diff --git a/Ash_AWord/ViewControllers/Chat/Emoji/EmojiEmoticons.m b/Ash_AWord/ViewControllers/Chat/Emoji/EmojiEmoticons.m new file mode 100755 index 0000000..f8887db --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/Emoji/EmojiEmoticons.m @@ -0,0 +1,172 @@ +// +// EmojiEmoticons.m +// Emoji +// +// Created by Aliksandr Andrashuk on 26.10.12. +// Copyright (c) 2012 Aliksandr Andrashuk. All rights reserved. +// + +#import "EmojiEmoticons.h" + +@implementation EmojiEmoticons + ++ (NSArray *)allEmoticons { + NSMutableArray *array = [NSMutableArray new]; + NSMutableArray * localAry = [[NSMutableArray alloc] initWithObjects: + [Emoji emojiWithCode:0x1F60a], + [Emoji emojiWithCode:0x1F603], + [Emoji emojiWithCode:0x1F609], + [Emoji emojiWithCode:0x1F62e], + [Emoji emojiWithCode:0x1F60b], + [Emoji emojiWithCode:0x1F60e], + [Emoji emojiWithCode:0x1F621], + [Emoji emojiWithCode:0x1F616], + [Emoji emojiWithCode:0x1F633], + [Emoji emojiWithCode:0x1F61e], + [Emoji emojiWithCode:0x1F62d], + [Emoji emojiWithCode:0x1F610], + [Emoji emojiWithCode:0x1F607], + [Emoji emojiWithCode:0x1F62c], + [Emoji emojiWithCode:0x1F606], + [Emoji emojiWithCode:0x1F631], + [Emoji emojiWithCode:0x1F385], + [Emoji emojiWithCode:0x1F634], + [Emoji emojiWithCode:0x1F615], + [Emoji emojiWithCode:0x1F637], + [Emoji emojiWithCode:0x1F62f], + [Emoji emojiWithCode:0x1F60f], + [Emoji emojiWithCode:0x1F611], + [Emoji emojiWithCode:0x1F496], + [Emoji emojiWithCode:0x1F494], + [Emoji emojiWithCode:0x1F319], + [Emoji emojiWithCode:0x1f31f], + [Emoji emojiWithCode:0x1f31e], + [Emoji emojiWithCode:0x1F308], + [Emoji emojiWithCode:0x1F60d], + [Emoji emojiWithCode:0x1F61a], + [Emoji emojiWithCode:0x1F48b], + [Emoji emojiWithCode:0x1F339], + [Emoji emojiWithCode:0x1F342], + [Emoji emojiWithCode:0x1F44d], + + /*[Emoji emojiWithCode:0x1F602], + [Emoji emojiWithCode:0x1F603], + [Emoji emojiWithCode:0x1F604], + [Emoji emojiWithCode:0x1F609], + [Emoji emojiWithCode:0x1F613], + [Emoji emojiWithCode:0x1F614], + [Emoji emojiWithCode:0x1F616], + [Emoji emojiWithCode:0x1F618], + [Emoji emojiWithCode:0x1F61a], + [Emoji emojiWithCode:0x1F61c], + [Emoji emojiWithCode:0x1F61d], + [Emoji emojiWithCode:0x1F61e], + [Emoji emojiWithCode:0x1F620], + [Emoji emojiWithCode:0x1F621], + [Emoji emojiWithCode:0x1F622], + [Emoji emojiWithCode:0x1F623], + [Emoji emojiWithCode:0x1F628], + [Emoji emojiWithCode:0x1F62a], + [Emoji emojiWithCode:0x1F62d], + [Emoji emojiWithCode:0x1F630], + [Emoji emojiWithCode:0x1F631], + [Emoji emojiWithCode:0x1F632], + [Emoji emojiWithCode:0x1F633], + [Emoji emojiWithCode:0x1F645], + [Emoji emojiWithCode:0x1F646], + [Emoji emojiWithCode:0x1F647], + [Emoji emojiWithCode:0x1F64c], + [Emoji emojiWithCode:0x1F6a5], + [Emoji emojiWithCode:0x1F6a7], + [Emoji emojiWithCode:0x1F6b2], + [Emoji emojiWithCode:0x1F6b6], + [Emoji emojiWithCode:0x1F302], + [Emoji emojiWithCode:0x1F319], + [Emoji emojiWithCode:0x1F31f],*/ + nil]; + [array addObjectsFromArray:localAry]; + // for (int i=0x1F600; i<=0x1F64F; i++) { + // if (i < 0x1F641 || i > 0x1F644) { + // [array addObject:[Emoji emojiWithCode:i]]; + // } + // } + return array; +} + +EMOJI_METHOD(grinningFace,1F600); +EMOJI_METHOD(grinningFaceWithSmilingEyes,1F601); +EMOJI_METHOD(faceWithTearsOfJoy,1F602); +EMOJI_METHOD(smilingFaceWithOpenMouth,1F603); +EMOJI_METHOD(smilingFaceWithOpenMouthAndSmilingEyes,1F604); +EMOJI_METHOD(smilingFaceWithOpenMouthAndColdSweat,1F605); +EMOJI_METHOD(smilingFaceWithOpenMouthAndTightlyClosedEyes,1F606); +EMOJI_METHOD(smilingFaceWithHalo,1F607); +EMOJI_METHOD(smilingFaceWithHorns,1F608); +EMOJI_METHOD(winkingFace,1F609); +EMOJI_METHOD(smilingFaceWithSmilingEyes,1F60A); +EMOJI_METHOD(faceSavouringDeliciousFood,1F60B); +EMOJI_METHOD(relievedFace,1F60C); +EMOJI_METHOD(smilingFaceWithHeartShapedEyes,1F60D); +EMOJI_METHOD(smilingFaceWithSunglasses,1F60E); +EMOJI_METHOD(smirkingFace,1F60F); +EMOJI_METHOD(neutralFace,1F610); +EMOJI_METHOD(expressionlessFace,1F611); +EMOJI_METHOD(unamusedFace,1F612); +EMOJI_METHOD(faceWithColdSweat,1F613); +EMOJI_METHOD(pensiveFace,1F614); +EMOJI_METHOD(confusedFace,1F615); +EMOJI_METHOD(confoundedFace,1F616); +EMOJI_METHOD(kissingFace,1F617); +EMOJI_METHOD(faceThrowingAKiss,1F618); +EMOJI_METHOD(kissingFaceWithSmilingEyes,1F619); +EMOJI_METHOD(kissingFaceWithClosedEyes,1F61A); +EMOJI_METHOD(faceWithStuckOutTongue,1F61B); +EMOJI_METHOD(faceWithStuckOutTongueAndWinkingEye,1F61C); +EMOJI_METHOD(faceWithStuckOutTongueAndTightlyClosedEyes,1F61D); +EMOJI_METHOD(disappointedFace,1F61E); +EMOJI_METHOD(worriedFace,1F61F); +EMOJI_METHOD(angryFace,1F620); +EMOJI_METHOD(poutingFace,1F621); +EMOJI_METHOD(cryingFace,1F622); +EMOJI_METHOD(perseveringFace,1F623); +EMOJI_METHOD(faceWithLookOfTriumph,1F624); +EMOJI_METHOD(disappointedButRelievedFace,1F625); +EMOJI_METHOD(frowningFaceWithOpenMouth,1F626); +EMOJI_METHOD(anguishedFace,1F627); +EMOJI_METHOD(fearfulFace,1F628); +EMOJI_METHOD(wearyFace,1F629); +EMOJI_METHOD(sleepyFace,1F62A); +EMOJI_METHOD(tiredFace,1F62B); +EMOJI_METHOD(grimacingFace,1F62C); +EMOJI_METHOD(loudlyCryingFace,1F62D); +EMOJI_METHOD(faceWithOpenMouth,1F62E); +EMOJI_METHOD(hushedFace,1F62F); +EMOJI_METHOD(faceWithOpenMouthAndColdSweat,1F630); +EMOJI_METHOD(faceScreamingInFear,1F631); +EMOJI_METHOD(astonishedFace,1F632); +EMOJI_METHOD(flushedFace,1F633); +EMOJI_METHOD(sleepingFace,1F634); +EMOJI_METHOD(dizzyFace,1F635); +EMOJI_METHOD(faceWithoutMouth,1F636); +EMOJI_METHOD(faceWithMedicalMask,1F637); +EMOJI_METHOD(grinningCatFaceWithSmilingEyes,1F638); +EMOJI_METHOD(catFaceWithTearsOfJoy,1F639); +EMOJI_METHOD(smilingCatFaceWithOpenMouth,1F63A); +EMOJI_METHOD(smilingCatFaceWithHeartShapedEyes,1F63B); +EMOJI_METHOD(catFaceWithWrySmile,1F63C); +EMOJI_METHOD(kissingCatFaceWithClosedEyes,1F63D); +EMOJI_METHOD(poutingCatFace,1F63E); +EMOJI_METHOD(cryingCatFace,1F63F); +EMOJI_METHOD(wearyCatFace,1F640); +EMOJI_METHOD(faceWithNoGoodGesture,1F645); +EMOJI_METHOD(faceWithOkGesture,1F646); +EMOJI_METHOD(personBowingDeeply,1F647); +EMOJI_METHOD(seeNoEvilMonkey,1F648); +EMOJI_METHOD(hearNoEvilMonkey,1F649); +EMOJI_METHOD(speakNoEvilMonkey,1F64A); +EMOJI_METHOD(happyPersonRaisingOneHand,1F64B); +EMOJI_METHOD(personRaisingBothHandsInCelebration,1F64C); +EMOJI_METHOD(personFrowning,1F64D); +EMOJI_METHOD(personWithPoutingFace,1F64E); +EMOJI_METHOD(personWithFoldedHands,1F64F); +@end diff --git a/Ash_AWord/ViewControllers/Chat/FacialView.h b/Ash_AWord/ViewControllers/Chat/FacialView.h new file mode 100644 index 0000000..935cce3 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/FacialView.h @@ -0,0 +1,36 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +@protocol FacialViewDelegate + +@optional +-(void)selectedFacialView:(NSString*)str; +-(void)deleteSelected:(NSString *)str; +-(void)sendFace; + +@end + + +@interface FacialView : UIView +{ + NSArray *_faces; +} + +@property(nonatomic) id delegate; + +@property(strong, nonatomic, readonly) NSArray *faces; + +-(void)loadFacialView:(int)page size:(CGSize)size; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/FacialView.m b/Ash_AWord/ViewControllers/Chat/FacialView.m new file mode 100755 index 0000000..ea15d4a --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/FacialView.m @@ -0,0 +1,95 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "FacialView.h" +#import "Emoji.h" + +@interface FacialView () + +@end + +@implementation FacialView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + _faces = [Emoji allEmoji]; + } + return self; +} + + +//给faces设置位置 +-(void)loadFacialView:(int)page size:(CGSize)size +{ + int maxRow = 5; + int maxCol = 8; + CGFloat itemWidth = self.frame.size.width / maxCol; + CGFloat itemHeight = self.frame.size.height / maxRow; + + UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [deleteButton setBackgroundColor:[UIColor clearColor]]; + [deleteButton setFrame:CGRectMake((maxCol - 1) * itemWidth, (maxRow - 1) * itemHeight, itemWidth, itemHeight)]; + [deleteButton setImage:[UIImage imageNamed:@"faceDelete"] forState:UIControlStateNormal]; + deleteButton.tag = 10000; + [deleteButton addTarget:self action:@selector(selected:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:deleteButton]; + + UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [sendButton setTitle:NSLocalizedString(@"send", @"Send") forState:UIControlStateNormal]; + [sendButton setFrame:CGRectMake((maxCol - 2) * itemWidth - 10, (maxRow - 1) * itemHeight + 5, itemWidth + 10, itemHeight - 10)]; + [sendButton addTarget:self action:@selector(sendAction:) forControlEvents:UIControlEventTouchUpInside]; + [sendButton setBackgroundColor:[UIColor colorWithRed:10 / 255.0 green:82 / 255.0 blue:104 / 255.0 alpha:1.0]]; + [self addSubview:sendButton]; + + for (int row = 0; row < maxRow; row++) { + for (int col = 0; col < maxCol; col++) { + int index = row * maxCol + col; + if (index < [_faces count]) { + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + [button setBackgroundColor:[UIColor clearColor]]; + [button setFrame:CGRectMake(col * itemWidth, row * itemHeight, itemWidth, itemHeight)]; + [button.titleLabel setFont:[UIFont fontWithName:@"AppleColorEmoji" size:29.0]]; + [button setTitle: [_faces objectAtIndex:(row * maxCol + col)] forState:UIControlStateNormal]; + button.tag = row * maxCol + col; + [button addTarget:self action:@selector(selected:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:button]; + } + else{ + break; + } + } + } +} + + +-(void)selected:(UIButton*)bt +{ + if (bt.tag == 10000 && _delegate) { + [_delegate deleteSelected:nil]; + }else{ + NSString *str = [_faces objectAtIndex:bt.tag]; + if (_delegate) { + [_delegate selectedFacialView:str]; + } + } +} + +- (void)sendAction:(id)sender +{ + if (_delegate) { + [_delegate sendFace]; + } +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/LocationViewController.h b/Ash_AWord/ViewControllers/Chat/LocationViewController.h new file mode 100644 index 0000000..0e82b3f --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/LocationViewController.h @@ -0,0 +1,29 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import + +@protocol LocationViewDelegate + +-(void)sendLocationLatitude:(double)latitude + longitude:(double)longitude + andAddress:(NSString *)address; +@end + +@interface LocationViewController : UIViewController + +@property (nonatomic, assign) id delegate; + +- (instancetype)initWithLocation:(CLLocationCoordinate2D)locationCoordinate; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/LocationViewController.m b/Ash_AWord/ViewControllers/Chat/LocationViewController.m new file mode 100755 index 0000000..f5a83f0 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/LocationViewController.m @@ -0,0 +1,231 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import +#import "LocationViewController.h" + +//#import "UIViewController+HUD.h" + +static LocationViewController *defaultLocation = nil; + +@interface LocationViewController () +{ + MKMapView *_mapView; + MKPointAnnotation *_annotation; + CLLocationManager *_locationManager; + CLLocationCoordinate2D _currentLocationCoordinate; + BOOL _isSendLocation; +} + +@property (strong, nonatomic) NSString *addressString; + +@end + +@implementation LocationViewController + +@synthesize addressString = _addressString; + +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + _isSendLocation = YES; + } + + return self; +} + +- (instancetype)initWithLocation:(CLLocationCoordinate2D)locationCoordinate +{ + self = [super initWithNibName:nil bundle:nil]; + if (self) { + _isSendLocation = NO; + _currentLocationCoordinate = locationCoordinate; + } + + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.title = NSLocalizedString(@"location.messageType", @"location message"); + +// UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 44, 44)]; +// [backButton setImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal]; +// [backButton addTarget:self.navigationController action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside]; +// UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; +// [self.navigationItem setLeftBarButtonItem:backItem]; + + _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds]; + _mapView.delegate = self; + _mapView.mapType = MKMapTypeStandard; + _mapView.zoomEnabled = YES; + [self.view addSubview:_mapView]; + + if (_isSendLocation) { + _mapView.showsUserLocation = YES;//显示当前位置 + + UIButton *sendButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 60, 44)]; + [sendButton setTitle:NSLocalizedString(@"send", @"Send") forState:UIControlStateNormal]; + [sendButton setTitleColor:[UIColor appMainColor] forState:UIControlStateNormal]; + [sendButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted]; + [sendButton addTarget:self action:@selector(sendLocation) forControlEvents:UIControlEventTouchUpInside]; + [self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithCustomView:sendButton]]; + self.navigationItem.rightBarButtonItem.enabled = NO; + + + [self startLocation]; + } + else{ + [self removeToLocation:_currentLocationCoordinate]; + } +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +-(void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; +} + +-(void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; +} + +#pragma mark - class methods + ++ (instancetype)defaultLocation +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + defaultLocation = [[LocationViewController alloc] initWithNibName:nil bundle:nil]; + }); + + return defaultLocation; +} + +#pragma mark - MKMapViewDelegate + +- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation +{ + __weak typeof(self) weakSelf = self; + CLGeocoder *geocoder = [[CLGeocoder alloc] init]; + [geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray *array, NSError *error) { + if (!error && array.count > 0) { + CLPlacemark *placemark = [array objectAtIndex:0]; + weakSelf.addressString = placemark.name; + + [self removeToLocation:userLocation.coordinate]; + } + }]; +} + +- (void)mapView:(MKMapView *)mapView didFailToLocateUserWithError:(NSError *)error +{ + // [self showHint:NSLocalizedString(@"location.fail", @"locate failure")]; + [MBProgressHUD errorHudWithView:self.view label:NSLocalizedString(@"location.fail", @"locate failure") hidesAfter:1.0]; + if (error.code == 0) { + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil + message:[error.userInfo objectForKey:NSLocalizedRecoverySuggestionErrorKey] + delegate:nil + cancelButtonTitle:@"确定" + otherButtonTitles:nil, nil]; + [alertView show]; + } +} + +- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status +{ + switch (status) { + case kCLAuthorizationStatusNotDetermined: + if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) + { + [_locationManager requestWhenInUseAuthorization]; + } + break; + case kCLAuthorizationStatusDenied: + { + + } + default: + break; + } +} + +#pragma mark - public + +- (void)startLocation +{ + if([CLLocationManager locationServicesEnabled]){ + _locationManager = [[CLLocationManager alloc] init]; + _locationManager.delegate = self; + _locationManager.distanceFilter = 5; + _locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;//kCLLocationAccuracyBest; + if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { + [_locationManager requestWhenInUseAuthorization]; + } + } + + if (_isSendLocation) { + self.navigationItem.rightBarButtonItem.enabled = NO; + } + +// [self showHudInView:self.view hint:NSLocalizedString(@"location.ongoning", @"locating...")]; + [MBProgressHUD hudWithView:self.view label:NSLocalizedString(@"location.ongoning", @"locating...")]; +} + +-(void)createAnnotationWithCoords:(CLLocationCoordinate2D)coords +{ + if (_annotation == nil) { + _annotation = [[MKPointAnnotation alloc] init]; + } + else{ + [_mapView removeAnnotation:_annotation]; + } + _annotation.coordinate = coords; + [_mapView addAnnotation:_annotation]; +} + +- (void)removeToLocation:(CLLocationCoordinate2D)locationCoordinate +{ + [MBProgressHUD hideHUDForView:self.view animated:YES]; + + _currentLocationCoordinate = locationCoordinate; + float zoomLevel = 0.01; + MKCoordinateRegion region = MKCoordinateRegionMake(_currentLocationCoordinate, MKCoordinateSpanMake(zoomLevel, zoomLevel)); + [_mapView setRegion:[_mapView regionThatFits:region] animated:YES]; + + if (_isSendLocation) { + self.navigationItem.rightBarButtonItem.enabled = YES; + } + + [self createAnnotationWithCoords:_currentLocationCoordinate]; +} + +- (void)sendLocation +{ + if (_delegate && [_delegate respondsToSelector:@selector(sendLocationLatitude:longitude:andAddress:)]) { + [_delegate sendLocationLatitude:_currentLocationCoordinate.latitude longitude:_currentLocationCoordinate.longitude andAddress:_addressString]; + } + + [self.navigationController popViewControllerAnimated:YES]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageModel.h b/Ash_AWord/ViewControllers/Chat/MessageModel.h new file mode 100644 index 0000000..155876a --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageModel.h @@ -0,0 +1,61 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import +#import "EaseMob.h" +#define KFIRETIME 20 + +@interface MessageModel : NSObject +{ + BOOL _isPlaying; +} + +@property (nonatomic) MessageBodyType type; +@property (nonatomic, readonly) MessageDeliveryState status; + +@property (nonatomic) BOOL isSender; //是否是发送者 +@property (nonatomic) BOOL isRead; //是否已读 +@property (nonatomic) EMMessageType messageType; // 消息类型(单聊,群里,聊天室) + +@property (nonatomic, strong, readonly) NSString *messageId; +@property (nonatomic, strong) NSURL *headImageURL; +@property (nonatomic, strong) NSString *nickName; +@property (nonatomic, strong) NSString *username; + +//text +@property (nonatomic, strong) NSString *content; + +//image +@property (nonatomic) CGSize size; +@property (nonatomic) CGSize thumbnailSize; +@property (nonatomic, strong) NSURL *imageRemoteURL; +@property (nonatomic, strong) NSURL *thumbnailRemoteURL; +@property (nonatomic, strong) UIImage *image; +@property (nonatomic, strong) UIImage *thumbnailImage; + +//audio +@property (nonatomic, strong) NSString *localPath; +@property (nonatomic, strong) NSString *remotePath; +@property (nonatomic) NSInteger time; +@property (nonatomic, strong) EMChatVoice *chatVoice; +@property (nonatomic) BOOL isPlaying; +@property (nonatomic) BOOL isPlayed; + +//location +@property (nonatomic, strong) NSString *address; +@property (nonatomic) double latitude; +@property (nonatomic) double longitude; + +@property (nonatomic, strong)id messageBody; +@property (nonatomic, strong)EMMessage *message; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageModel.m b/Ash_AWord/ViewControllers/Chat/MessageModel.m new file mode 100644 index 0000000..3e5ba4d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageModel.m @@ -0,0 +1,43 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "MessageModel.h" + +@implementation MessageModel + +- (instancetype)init +{ + self = [super init]; + + if (self) + { + //code + } + + return self; +} + +- (void)dealloc{ + +} + +- (NSString *)messageId +{ + return _message.messageId; +} + +- (MessageDeliveryState)status +{ + return _message.deliveryState; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageModelManager.h b/Ash_AWord/ViewControllers/Chat/MessageModelManager.h new file mode 100644 index 0000000..dea0ced --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageModelManager.h @@ -0,0 +1,19 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +@interface MessageModelManager : NSObject + ++ (id)modelWithMessage:(EMMessage *)message; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageModelManager.m b/Ash_AWord/ViewControllers/Chat/MessageModelManager.m new file mode 100644 index 0000000..8c125b4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageModelManager.m @@ -0,0 +1,116 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "MessageModelManager.h" +#import "ConvertToCommonEmoticonsHelper.h" +#import "MessageModel.h" + +@implementation MessageModelManager + ++ (id)modelWithMessage:(EMMessage *)message +{ + id messageBody = [message.messageBodies firstObject]; + NSDictionary *userInfo = [[EaseMob sharedInstance].chatManager loginInfo]; + NSString *login = [userInfo objectForKey:kSDKUsername]; + NSString *sender = (message.messageType == eMessageTypeChat) ? message.from : message.groupSenderName; + BOOL isSender = [login isEqualToString:sender] ? YES : NO; + + MessageModel *model = [[MessageModel alloc] init]; + model.isRead = message.isRead; + model.messageBody = messageBody; + model.message = message; + model.type = messageBody.messageBodyType; + model.isSender = isSender; + model.isPlaying = NO; + model.messageType = message.messageType; + if (model.messageType != eMessageTypeChat) { + model.username = message.groupSenderName; + } + else{ + model.username = message.from; + } + + /* + if (isSender) { + model.headImageURL = nil; + } + else{ + model.headImageURL = nil; + } + */ + + switch (messageBody.messageBodyType) { + case eMessageBodyType_Text: + { + // 表情映射。 + NSString *didReceiveText = [ConvertToCommonEmoticonsHelper + convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text]; + model.content = didReceiveText; + } + break; + case eMessageBodyType_Image: + { + EMImageMessageBody *imgMessageBody = (EMImageMessageBody*)messageBody; + model.thumbnailSize = imgMessageBody.thumbnailSize; + model.size = imgMessageBody.size; + model.localPath = imgMessageBody.localPath; + model.thumbnailImage = [UIImage imageWithContentsOfFile:imgMessageBody.thumbnailLocalPath]; + if (isSender) + { + model.image = [UIImage imageWithContentsOfFile:imgMessageBody.thumbnailLocalPath]; + }else { + model.imageRemoteURL = [NSURL URLWithString:imgMessageBody.remotePath]; + } + } + break; + case eMessageBodyType_Location: + { + model.address = ((EMLocationMessageBody *)messageBody).address; + model.latitude = ((EMLocationMessageBody *)messageBody).latitude; + model.longitude = ((EMLocationMessageBody *)messageBody).longitude; + } + break; + case eMessageBodyType_Voice: + { + model.time = ((EMVoiceMessageBody *)messageBody).duration; + model.chatVoice = (EMChatVoice *)((EMVoiceMessageBody *)messageBody).chatObject; + if (message.ext) { + NSDictionary *dict = message.ext; + BOOL isPlayed = [[dict objectForKey:@"isPlayed"] boolValue]; + model.isPlayed = isPlayed; + }else { + NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@NO,@"isPlayed", nil]; + message.ext = dict; + [message updateMessageExtToDB]; + } + // 本地音频路径 + model.localPath = ((EMVoiceMessageBody *)messageBody).localPath; + model.remotePath = ((EMVoiceMessageBody *)messageBody).remotePath; + } + break; + case eMessageBodyType_Video:{ + EMVideoMessageBody *videoMessageBody = (EMVideoMessageBody*)messageBody; + model.thumbnailSize = videoMessageBody.size; + model.size = videoMessageBody.size; + model.localPath = videoMessageBody.thumbnailLocalPath; + model.thumbnailImage = [UIImage imageWithContentsOfFile:videoMessageBody.thumbnailLocalPath]; + model.image = model.thumbnailImage; + } + break; + default: + break; + } + + return model; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageReadManager.h b/Ash_AWord/ViewControllers/Chat/MessageReadManager.h new file mode 100644 index 0000000..5864a9d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageReadManager.h @@ -0,0 +1,48 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#import "MWPhotoBrowser.h" +#import "MessageModel.h" + +typedef void (^FinishBlock)(BOOL success); +typedef void (^PlayBlock)(BOOL playing, MessageModel *messageModel); + +@class EMChatFireBubbleView; +@interface MessageReadManager : NSObject + +@property (strong, nonatomic) MWPhotoBrowser *photoBrowser; +@property (strong, nonatomic) FinishBlock finishBlock; + +@property (strong, nonatomic) MessageModel *audioMessageModel; + ++ (id)defaultManager; + +//default +- (void)showBrowserWithImages:(NSArray *)imageArray; + +/** + * 准备播放语音文件 + * + * @param messageModel 要播放的语音文件 + * @param updateCompletion 需要更新model所在的Cell + * + * @return 若返回NO,则不需要调用播放方法 + * + */ +- (BOOL)prepareMessageAudioModel:(MessageModel *)messageModel + updateViewCompletion:(void (^)(MessageModel *prevAudioModel, MessageModel *currentAudioModel))updateCompletion; + +- (MessageModel *)stopMessageAudioModel; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageReadManager.m b/Ash_AWord/ViewControllers/Chat/MessageReadManager.m new file mode 100644 index 0000000..47e5d9f --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageReadManager.m @@ -0,0 +1,204 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "MessageReadManager.h" +//#import "UIImageView+EMWebCache.h" +#import "EMCDDeviceManager.h" + +static MessageReadManager *detailInstance = nil; + +@interface MessageReadManager() + +@property (strong, nonatomic) UIWindow *keyWindow; + +@property (strong, nonatomic) NSMutableArray *photos; +@property (strong, nonatomic) UINavigationController *photoNavigationController; + +@property (strong, nonatomic) UIAlertView *textAlertView; + +@end + +@implementation MessageReadManager + ++ (id)defaultManager +{ + @synchronized(self){ + static dispatch_once_t pred; + dispatch_once(&pred, ^{ + detailInstance = [[self alloc] init]; + }); + } + + return detailInstance; +} + +#pragma mark - getter + +- (UIWindow *)keyWindow +{ + if(_keyWindow == nil) + { + _keyWindow = [[UIApplication sharedApplication] keyWindow]; + } + + return _keyWindow; +} + +- (NSMutableArray *)photos +{ + if (_photos == nil) { + _photos = [[NSMutableArray alloc] init]; + } + + return _photos; +} + +- (MWPhotoBrowser *)photoBrowser +{ + if (_photoBrowser == nil) { + _photoBrowser = [[MWPhotoBrowser alloc] initWithDelegate:self]; + _photoBrowser.displayActionButton = YES; + _photoBrowser.displayNavArrows = YES; + _photoBrowser.displaySelectionButtons = NO; + _photoBrowser.alwaysShowControls = NO; + _photoBrowser.wantsFullScreenLayout = YES; + _photoBrowser.zoomPhotosToFill = YES; + _photoBrowser.enableGrid = NO; + _photoBrowser.startOnGrid = NO; + [_photoBrowser setCurrentPhotoIndex:0]; + } + + return _photoBrowser; +} + +- (UINavigationController *)photoNavigationController +{ + if (_photoNavigationController == nil) { + _photoNavigationController = [[UINavigationController alloc] initWithRootViewController:self.photoBrowser]; + _photoNavigationController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + } + + [self.photoBrowser reloadData]; + return _photoNavigationController; +} + +#pragma mark - MWPhotoBrowserDelegate + +- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser +{ + return [self.photos count]; +} + +- (id )photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index +{ + if (index < self.photos.count) + { + return [self.photos objectAtIndex:index]; + } + + return nil; +} + + +#pragma mark - private + + +#pragma mark - public + +- (void)showBrowserWithImages:(NSArray *)imageArray +{ + if (imageArray && [imageArray count] > 0) { + NSMutableArray *photoArray = [NSMutableArray array]; + for (id object in imageArray) { + MWPhoto *photo; + if ([object isKindOfClass:[UIImage class]]) { + photo = [MWPhoto photoWithImage:object]; + } + else if ([object isKindOfClass:[NSURL class]]) + { + photo = [MWPhoto photoWithURL:object]; + } + else if ([object isKindOfClass:[NSString class]]) + { + + } + [photoArray addObject:photo]; + } + + self.photos = photoArray; + } + + UIViewController *rootController = [self.keyWindow rootViewController]; + [rootController presentViewController:self.photoNavigationController animated:YES completion:nil]; +} + +- (BOOL)prepareMessageAudioModel:(MessageModel *)messageModel + updateViewCompletion:(void (^)(MessageModel *prevAudioModel, MessageModel *currentAudioModel))updateCompletion +{ + BOOL isPrepare = NO; + + if(messageModel.type == eMessageBodyType_Voice) + { + MessageModel *prevAudioModel = self.audioMessageModel; + MessageModel *currentAudioModel = messageModel; + self.audioMessageModel = messageModel; + + BOOL isPlaying = messageModel.isPlaying; + if (isPlaying) { + messageModel.isPlaying = NO; + self.audioMessageModel = nil; + currentAudioModel = nil; + [[EMCDDeviceManager sharedInstance] stopPlaying]; + } + else { + messageModel.isPlaying = YES; + prevAudioModel.isPlaying = NO; + isPrepare = YES; + + if (!messageModel.isPlayed) { + messageModel.isPlayed = YES; + EMMessage *chatMessage = messageModel.message; + if (chatMessage.ext) { + NSMutableDictionary *dict = [chatMessage.ext mutableCopy]; + if (![[dict objectForKey:@"isPlayed"] boolValue]) { + [dict setObject:@YES forKey:@"isPlayed"]; + chatMessage.ext = dict; + [chatMessage updateMessageExtToDB]; + } + } + } + } + + if (updateCompletion) { + updateCompletion(prevAudioModel, currentAudioModel); + } + } + + return isPrepare; +} + +- (MessageModel *)stopMessageAudioModel +{ + MessageModel *model = nil; + if (self.audioMessageModel.type == eMessageBodyType_Voice) { + if (self.audioMessageModel.isPlaying) { + model = self.audioMessageModel; + } + self.audioMessageModel.isPlaying = NO; + self.audioMessageModel = nil; + } + + return model; +} + + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageTableView.h b/Ash_AWord/ViewControllers/Chat/MessageTableView.h new file mode 100644 index 0000000..24abcf4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageTableView.h @@ -0,0 +1,13 @@ +// +// MessageTableView.h +// ASHMessageTableViewDemo +// +// Created by xmfish on 15/1/19. +// Copyright (c) 2015年 ash. All rights reserved. +// + +#import + +@interface MessageTableView : UITableView + +@end diff --git a/Ash_AWord/ViewControllers/Chat/MessageTableView.m b/Ash_AWord/ViewControllers/Chat/MessageTableView.m new file mode 100644 index 0000000..422f84b --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/MessageTableView.m @@ -0,0 +1,27 @@ +// +// MessageTableView.m +// ASHMessageTableViewDemo +// +// Created by xmfish on 15/1/19. +// Copyright (c) 2015年 ash. All rights reserved. +// + +#import "MessageTableView.h" + +@implementation MessageTableView + +- (void)setContentSize:(CGSize)contentSize +{ + if (!CGSizeEqualToSize(self.contentSize, CGSizeZero)) + { + if (contentSize.height > self.contentSize.height) + { + CGPoint offset = self.contentOffset; + offset.y += (contentSize.height - self.contentSize.height); + self.contentOffset = offset; + } + } + [super setContentSize:contentSize]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/NSDate+Category.h b/Ash_AWord/ViewControllers/Chat/NSDate+Category.h new file mode 100755 index 0000000..6f5b7c0 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/NSDate+Category.h @@ -0,0 +1,94 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +#define D_MINUTE 60 +#define D_HOUR 3600 +#define D_DAY 86400 +#define D_WEEK 604800 +#define D_YEAR 31556926 + +@interface NSDate (Category) + +- (NSString *)timeIntervalDescription;//距离当前的时间间隔描述 +- (NSString *)minuteDescription;/*精确到分钟的日期描述*/ +- (NSString *)formattedTime; +- (NSString *)formattedDateDescription;//格式化日期描述 +- (double)timeIntervalSince1970InMilliSecond; ++ (NSDate *)dateWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond; ++ (NSString *)formattedTimeFromTimeInterval:(long long)time; +// Relative dates from the current date ++ (NSDate *) dateTomorrow; ++ (NSDate *) dateYesterday; ++ (NSDate *) dateWithDaysFromNow: (NSInteger) days; ++ (NSDate *) dateWithDaysBeforeNow: (NSInteger) days; ++ (NSDate *) dateWithHoursFromNow: (NSInteger) dHours; ++ (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours; ++ (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes; ++ (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes; + +// Comparing dates +- (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate; +- (BOOL) isToday; +- (BOOL) isTomorrow; +- (BOOL) isYesterday; +- (BOOL) isSameWeekAsDate: (NSDate *) aDate; +- (BOOL) isThisWeek; +- (BOOL) isNextWeek; +- (BOOL) isLastWeek; +- (BOOL) isSameMonthAsDate: (NSDate *) aDate; +- (BOOL) isThisMonth; +- (BOOL) isSameYearAsDate: (NSDate *) aDate; +- (BOOL) isThisYear; +- (BOOL) isNextYear; +- (BOOL) isLastYear; +- (BOOL) isEarlierThanDate: (NSDate *) aDate; +- (BOOL) isLaterThanDate: (NSDate *) aDate; +- (BOOL) isInFuture; +- (BOOL) isInPast; + +// Date roles +- (BOOL) isTypicallyWorkday; +- (BOOL) isTypicallyWeekend; + +// Adjusting dates +- (NSDate *) dateByAddingDays: (NSInteger) dDays; +- (NSDate *) dateBySubtractingDays: (NSInteger) dDays; +- (NSDate *) dateByAddingHours: (NSInteger) dHours; +- (NSDate *) dateBySubtractingHours: (NSInteger) dHours; +- (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes; +- (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes; +- (NSDate *) dateAtStartOfDay; + +// Retrieving intervals +- (NSInteger) minutesAfterDate: (NSDate *) aDate; +- (NSInteger) minutesBeforeDate: (NSDate *) aDate; +- (NSInteger) hoursAfterDate: (NSDate *) aDate; +- (NSInteger) hoursBeforeDate: (NSDate *) aDate; +- (NSInteger) daysAfterDate: (NSDate *) aDate; +- (NSInteger) daysBeforeDate: (NSDate *) aDate; +- (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate; + +// Decomposing dates +@property (readonly) NSInteger nearestHour; +@property (readonly) NSInteger hour; +@property (readonly) NSInteger minute; +@property (readonly) NSInteger seconds; +@property (readonly) NSInteger day; +@property (readonly) NSInteger month; +@property (readonly) NSInteger week; +@property (readonly) NSInteger weekday; +@property (readonly) NSInteger nthWeekday; // e.g. 2nd Tuesday of the month == 2 +@property (readonly) NSInteger year; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/NSDate+Category.m b/Ash_AWord/ViewControllers/Chat/NSDate+Category.m new file mode 100755 index 0000000..fc2c8ac --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/NSDate+Category.m @@ -0,0 +1,526 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "NSDate+Category.h" +#import "NSDateFormatter+Category.h" + +#define DATE_COMPONENTS (NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit) +#define CURRENT_CALENDAR [NSCalendar currentCalendar] + +@implementation NSDate (Category) + +/*距离当前的时间间隔描述*/ +- (NSString *)timeIntervalDescription +{ + NSTimeInterval timeInterval = -[self timeIntervalSinceNow]; + if (timeInterval < 60) { + return NSLocalizedString(@"NSDateCategory.text1", @""); + } else if (timeInterval < 3600) { + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text2", @""), timeInterval / 60]; + } else if (timeInterval < 86400) { + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text3", @""), timeInterval / 3600]; + } else if (timeInterval < 2592000) {//30天内 + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text4", @""), timeInterval / 86400]; + } else if (timeInterval < 31536000) {//30天至1年内 + NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text5", @"")]; + return [dateFormatter stringFromDate:self]; + } else { + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text6", @""), timeInterval / 31536000]; + } +} + +/*精确到分钟的日期描述*/ +- (NSString *)minuteDescription +{ + NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyy-MM-dd"]; + + NSString *theDay = [dateFormatter stringFromDate:self];//日期的年月日 + NSString *currentDay = [dateFormatter stringFromDate:[NSDate date]];//当前年月日 + if ([theDay isEqualToString:currentDay]) {//当天 + [dateFormatter setDateFormat:@"ah:mm"]; + return [dateFormatter stringFromDate:self]; + } else if ([[dateFormatter dateFromString:currentDay] timeIntervalSinceDate:[dateFormatter dateFromString:theDay]] == 86400) {//昨天 + [dateFormatter setDateFormat:@"ah:mm"]; + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text7", @'"'), [dateFormatter stringFromDate:self]]; + } else if ([[dateFormatter dateFromString:currentDay] timeIntervalSinceDate:[dateFormatter dateFromString:theDay]] < 86400 * 7) {//间隔一周内 + [dateFormatter setDateFormat:@"EEEE ah:mm"]; + return [dateFormatter stringFromDate:self]; + } else {//以前 + [dateFormatter setDateFormat:@"yyyy-MM-dd ah:mm"]; + return [dateFormatter stringFromDate:self]; + } +} + + + +/*标准时间日期描述*/ +-(NSString *)formattedTime{ + + + + NSDateFormatter* formatter = [[NSDateFormatter alloc]init]; + [formatter setDateFormat:@"YYYY-MM-dd"]; + NSString * dateNow = [formatter stringFromDate:[NSDate date]]; + NSDateComponents *components = [[NSDateComponents alloc] init]; + [components setDay:[[dateNow substringWithRange:NSMakeRange(8,2)] intValue]]; + [components setMonth:[[dateNow substringWithRange:NSMakeRange(5,2)] intValue]]; + [components setYear:[[dateNow substringWithRange:NSMakeRange(0,4)] intValue]]; + NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSDate *date = [gregorian dateFromComponents:components]; //今天 0点时间 + + + NSInteger hour = [self hoursAfterDate:date]; + NSDateFormatter *dateFormatter = nil; + NSString *ret = @""; + + //hasAMPM==TURE为12小时制,否则为24小时制 + NSString *formatStringForHours = [NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]]; + NSRange containsA = [formatStringForHours rangeOfString:@"a"]; + BOOL hasAMPM = containsA.location != NSNotFound; + + if (!hasAMPM) { //24小时制 + if (hour <= 24 && hour >= 0) { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"HH:mm"]; + }else if (hour < 0 && hour >= -24) { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text8", @"")]; + }else { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyy-MM-dd"]; + } + }else { + if (hour >= 0 && hour <= 6) { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text9", @"")]; + }else if (hour > 6 && hour <=11 ) { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text10", @"")]; + }else if (hour > 11 && hour <= 17) { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text11", @"")]; + }else if (hour > 17 && hour <= 24) { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text12", @"")]; + }else if (hour < 0 && hour >= -24){ + dateFormatter = [NSDateFormatter dateFormatterWithFormat:NSLocalizedString(@"NSDateCategory.text13", @"")]; + }else { + dateFormatter = [NSDateFormatter dateFormatterWithFormat:@"yyyy-MM-dd"]; + } + + } + + ret = [dateFormatter stringFromDate:self]; + return ret; +} + + +/*格式化日期描述*/ +- (NSString *)formattedDateDescription +{ + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + + [dateFormatter setDateFormat:@"yyyy-MM-dd"]; + NSString *theDay = [dateFormatter stringFromDate:self];//日期的年月日 + NSString *currentDay = [dateFormatter stringFromDate:[NSDate date]];//当前年月日 + + NSInteger timeInterval = -[self timeIntervalSinceNow]; + if (timeInterval < 60) { + return NSLocalizedString(@"NSDateCategory.text1", @""); + } else if (timeInterval < 3600) {//1小时内 + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text2", @""), timeInterval / 60]; + } else if (timeInterval < 21600) {//6小时内 + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text3", @""), timeInterval / 3600]; + } else if ([theDay isEqualToString:currentDay]) {//当天 + [dateFormatter setDateFormat:@"HH:mm"]; + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text14", @""), [dateFormatter stringFromDate:self]]; + } else if ([[dateFormatter dateFromString:currentDay] timeIntervalSinceDate:[dateFormatter dateFromString:theDay]] == 86400) {//昨天 + [dateFormatter setDateFormat:@"HH:mm"]; + return [NSString stringWithFormat:NSLocalizedString(@"NSDateCategory.text7", @""), [dateFormatter stringFromDate:self]]; + } else {//以前 + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm"]; + return [dateFormatter stringFromDate:self]; + } +} + +- (double)timeIntervalSince1970InMilliSecond { + double ret; + ret = [self timeIntervalSince1970] * 1000; + + return ret; +} + ++ (NSDate *)dateWithTimeIntervalInMilliSecondSince1970:(double)timeIntervalInMilliSecond { + NSDate *ret = nil; + double timeInterval = timeIntervalInMilliSecond; + // judge if the argument is in secconds(for former data structure). + if(timeIntervalInMilliSecond > 140000000000) { + timeInterval = timeIntervalInMilliSecond / 1000; + } + ret = [NSDate dateWithTimeIntervalSince1970:timeInterval]; + + return ret; +} + ++ (NSString *)formattedTimeFromTimeInterval:(long long)time{ + return [[NSDate dateWithTimeIntervalInMilliSecondSince1970:time] formattedTime]; +} + +#pragma mark Relative Dates + ++ (NSDate *) dateWithDaysFromNow: (NSInteger) days +{ + // Thanks, Jim Morrison + return [[NSDate date] dateByAddingDays:days]; +} + ++ (NSDate *) dateWithDaysBeforeNow: (NSInteger) days +{ + // Thanks, Jim Morrison + return [[NSDate date] dateBySubtractingDays:days]; +} + ++ (NSDate *) dateTomorrow +{ + return [NSDate dateWithDaysFromNow:1]; +} + ++ (NSDate *) dateYesterday +{ + return [NSDate dateWithDaysBeforeNow:1]; +} + ++ (NSDate *) dateWithHoursFromNow: (NSInteger) dHours +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_HOUR * dHours; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + ++ (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_HOUR * dHours; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + ++ (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + ++ (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_MINUTE * dMinutes; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + +#pragma mark Comparing Dates + +- (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate +{ + NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate]; + return ((components1.year == components2.year) && + (components1.month == components2.month) && + (components1.day == components2.day)); +} + +- (BOOL) isToday +{ + return [self isEqualToDateIgnoringTime:[NSDate date]]; +} + +- (BOOL) isTomorrow +{ + return [self isEqualToDateIgnoringTime:[NSDate dateTomorrow]]; +} + +- (BOOL) isYesterday +{ + return [self isEqualToDateIgnoringTime:[NSDate dateYesterday]]; +} + +// This hard codes the assumption that a week is 7 days +- (BOOL) isSameWeekAsDate: (NSDate *) aDate +{ + NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate]; + + // Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week + if (components1.week != components2.week) return NO; + + // Must have a time interval under 1 week. Thanks @aclark + return (fabs([self timeIntervalSinceDate:aDate]) < D_WEEK); +} + +- (BOOL) isThisWeek +{ + return [self isSameWeekAsDate:[NSDate date]]; +} + +- (BOOL) isNextWeek +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_WEEK; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return [self isSameWeekAsDate:newDate]; +} + +- (BOOL) isLastWeek +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_WEEK; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return [self isSameWeekAsDate:newDate]; +} + +// Thanks, mspasov +- (BOOL) isSameMonthAsDate: (NSDate *) aDate +{ + NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:self]; + NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:aDate]; + return ((components1.month == components2.month) && + (components1.year == components2.year)); +} + +- (BOOL) isThisMonth +{ + return [self isSameMonthAsDate:[NSDate date]]; +} + +- (BOOL) isSameYearAsDate: (NSDate *) aDate +{ + NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; + NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:aDate]; + return (components1.year == components2.year); +} + +- (BOOL) isThisYear +{ + // Thanks, baspellis + return [self isSameYearAsDate:[NSDate date]]; +} + +- (BOOL) isNextYear +{ + NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; + NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:[NSDate date]]; + + return (components1.year == (components2.year + 1)); +} + +- (BOOL) isLastYear +{ + NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; + NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:[NSDate date]]; + + return (components1.year == (components2.year - 1)); +} + +- (BOOL) isEarlierThanDate: (NSDate *) aDate +{ + return ([self compare:aDate] == NSOrderedAscending); +} + +- (BOOL) isLaterThanDate: (NSDate *) aDate +{ + return ([self compare:aDate] == NSOrderedDescending); +} + +// Thanks, markrickert +- (BOOL) isInFuture +{ + return ([self isLaterThanDate:[NSDate date]]); +} + +// Thanks, markrickert +- (BOOL) isInPast +{ + return ([self isEarlierThanDate:[NSDate date]]); +} + + +#pragma mark Roles +- (BOOL) isTypicallyWeekend +{ + NSDateComponents *components = [CURRENT_CALENDAR components:NSWeekdayCalendarUnit fromDate:self]; + if ((components.weekday == 1) || + (components.weekday == 7)) + return YES; + return NO; +} + +- (BOOL) isTypicallyWorkday +{ + return ![self isTypicallyWeekend]; +} + +#pragma mark Adjusting Dates + +- (NSDate *) dateByAddingDays: (NSInteger) dDays +{ + NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_DAY * dDays; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + +- (NSDate *) dateBySubtractingDays: (NSInteger) dDays +{ + return [self dateByAddingDays: (dDays * -1)]; +} + +- (NSDate *) dateByAddingHours: (NSInteger) dHours +{ + NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_HOUR * dHours; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + +- (NSDate *) dateBySubtractingHours: (NSInteger) dHours +{ + return [self dateByAddingHours: (dHours * -1)]; +} + +- (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes +{ + NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + return newDate; +} + +- (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes +{ + return [self dateByAddingMinutes: (dMinutes * -1)]; +} + +- (NSDate *) dateAtStartOfDay +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + components.hour = 0; + components.minute = 0; + components.second = 0; + return [CURRENT_CALENDAR dateFromComponents:components]; +} + +- (NSDateComponents *) componentsWithOffsetFromDate: (NSDate *) aDate +{ + NSDateComponents *dTime = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate toDate:self options:0]; + return dTime; +} + +#pragma mark Retrieving Intervals + +- (NSInteger) minutesAfterDate: (NSDate *) aDate +{ + NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; + return (NSInteger) (ti / D_MINUTE); +} + +- (NSInteger) minutesBeforeDate: (NSDate *) aDate +{ + NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; + return (NSInteger) (ti / D_MINUTE); +} + +- (NSInteger) hoursAfterDate: (NSDate *) aDate +{ + NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; + return (NSInteger) (ti / D_HOUR); +} + +- (NSInteger) hoursBeforeDate: (NSDate *) aDate +{ + NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; + return (NSInteger) (ti / D_HOUR); +} + +- (NSInteger) daysAfterDate: (NSDate *) aDate +{ + NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; + return (NSInteger) (ti / D_DAY); +} + +- (NSInteger) daysBeforeDate: (NSDate *) aDate +{ + NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; + return (NSInteger) (ti / D_DAY); +} + +// Thanks, dmitrydims +// I have not yet thoroughly tested this +- (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate +{ + NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSDateComponents *components = [gregorianCalendar components:NSDayCalendarUnit fromDate:self toDate:anotherDate options:0]; + return components.day; +} + +#pragma mark Decomposing Dates + +- (NSInteger) nearestHour +{ + NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * 30; + NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; + NSDateComponents *components = [CURRENT_CALENDAR components:NSHourCalendarUnit fromDate:newDate]; + return components.hour; +} + +- (NSInteger) hour +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.hour; +} + +- (NSInteger) minute +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.minute; +} + +- (NSInteger) seconds +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.second; +} + +- (NSInteger) day +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.day; +} + +- (NSInteger) month +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.month; +} + +- (NSInteger) week +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.week; +} + +- (NSInteger) weekday +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.weekday; +} + +- (NSInteger) nthWeekday // e.g. 2nd Tuesday of the month is 2 +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.weekdayOrdinal; +} + +- (NSInteger) year +{ + NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; + return components.year; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/NSDateFormatter+Category.h b/Ash_AWord/ViewControllers/Chat/NSDateFormatter+Category.h new file mode 100644 index 0000000..a948738 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/NSDateFormatter+Category.h @@ -0,0 +1,22 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +@interface NSDateFormatter (Category) + ++ (id)dateFormatter; ++ (id)dateFormatterWithFormat:(NSString *)dateFormat; + ++ (id)defaultDateFormatter;/*yyyy-MM-dd HH:mm:ss*/ + +@end diff --git a/Ash_AWord/ViewControllers/Chat/NSDateFormatter+Category.m b/Ash_AWord/ViewControllers/Chat/NSDateFormatter+Category.m new file mode 100644 index 0000000..22262e7 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/NSDateFormatter+Category.m @@ -0,0 +1,34 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "NSDateFormatter+Category.h" + +@implementation NSDateFormatter (Category) + ++ (id)dateFormatter +{ + return [[self alloc] init]; +} + ++ (id)dateFormatterWithFormat:(NSString *)dateFormat +{ + NSDateFormatter *dateFormatter = [[self alloc] init]; + dateFormatter.dateFormat = dateFormat; + return dateFormatter; +} + ++ (id)defaultDateFormatter +{ + return [self dateFormatterWithFormat:@"yyyy-MM-dd HH:mm:ss"]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/THProgressView/THProgressView.h b/Ash_AWord/ViewControllers/Chat/THProgressView/THProgressView.h new file mode 100755 index 0000000..3aec7f3 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/THProgressView/THProgressView.h @@ -0,0 +1,18 @@ +// +// THProgressView.h +// +// Created by Tiago Henriques on 10/22/13. +// Copyright (c) 2013 Tiago Henriques. All rights reserved. +// + +#import + +@interface THProgressView : UIView + +@property (nonatomic, strong) UIColor* progressTintColor; +@property (nonatomic, strong) UIColor* borderTintColor; +@property (nonatomic) CGFloat progress; + +- (void)setProgress:(CGFloat)progress animated:(BOOL)animated; + +@end \ No newline at end of file diff --git a/Ash_AWord/ViewControllers/Chat/THProgressView/THProgressView.m b/Ash_AWord/ViewControllers/Chat/THProgressView/THProgressView.m new file mode 100755 index 0000000..809f995 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/THProgressView/THProgressView.m @@ -0,0 +1,165 @@ +// +// THProgressView.m +// +// Created by Tiago Henriques on 10/22/13. +// Copyright (c) 2013 Tiago Henriques. All rights reserved. +// + +#import "THProgressView.h" + +#import + + +static const CGFloat kBorderWidth = 2.0f; + + +#pragma mark - +#pragma mark THProgressLayer + +@interface THProgressLayer : CALayer +@property (nonatomic, strong) UIColor* progressTintColor; +@property (nonatomic, strong) UIColor* borderTintColor; +@property (nonatomic) CGFloat progress; +@end + +@implementation THProgressLayer + +@dynamic progressTintColor; +@dynamic borderTintColor; + ++ (BOOL)needsDisplayForKey:(NSString *)key +{ + return [key isEqualToString:@"progress"] ? YES : [super needsDisplayForKey:key]; +} + +- (void)drawInContext:(CGContextRef)context +{ + CGRect rect = CGRectInset(self.bounds, kBorderWidth, kBorderWidth); + CGFloat radius = CGRectGetHeight(rect) / 2.0f; + CGContextSetLineWidth(context, kBorderWidth); + CGContextSetStrokeColorWithColor(context, self.borderTintColor.CGColor); + [self drawRectangleInContext:context inRect:rect withRadius:radius]; + CGContextStrokePath(context); + + + CGContextSetFillColorWithColor(context, self.progressTintColor.CGColor); + CGRect progressRect = CGRectInset(rect, 2 * kBorderWidth, 2 * kBorderWidth); + CGFloat progressRadius = CGRectGetHeight(progressRect) / 2.0f; + progressRect.size.width = fmaxf(self.progress * progressRect.size.width, 2.0f * progressRadius); + [self drawRectangleInContext:context inRect:progressRect withRadius:progressRadius]; + CGContextFillPath(context); +} + +- (void)drawRectangleInContext:(CGContextRef)context inRect:(CGRect)rect withRadius:(CGFloat)radius +{ + CGContextMoveToPoint(context, rect.origin.x, rect.origin.y + radius); + CGContextAddLineToPoint(context, rect.origin.x, rect.origin.y + rect.size.height - radius); + CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI / 2, 1); + CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height); + CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI / 2, 0.0f, 1); + CGContextAddLineToPoint(context, rect.origin.x + rect.size.width, rect.origin.y + radius); + CGContextAddArc(context, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 0.0f, -M_PI / 2, 1); + CGContextAddLineToPoint(context, rect.origin.x + radius, rect.origin.y); + CGContextAddArc(context, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI / 2, M_PI, 1); +} + +@end + + +#pragma mark - +#pragma mark THProgressView + +@implementation THProgressView + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + [self initialize]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if (self = [super initWithCoder:aDecoder]) { + [self initialize]; + } + return self; +} + +- (void)initialize +{ + self.backgroundColor = [UIColor clearColor]; +} + +- (void)didMoveToWindow +{ + self.progressLayer.contentsScale = self.window.screen.scale; +} + ++ (Class)layerClass +{ + return [THProgressLayer class]; +} + +- (THProgressLayer *)progressLayer +{ + return (THProgressLayer *)self.layer; +} + + +#pragma mark Getters & Setters + +- (CGFloat)progress +{ + return self.progressLayer.progress; +} + +- (void)setProgress:(CGFloat)progress +{ + [self setProgress:progress animated:NO]; +} + +- (void)setProgress:(CGFloat)progress animated:(BOOL)animated +{ + [self.progressLayer removeAnimationForKey:@"progress"]; + CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); + + if (animated) { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"]; + animation.duration = fabsf(self.progress - pinnedProgress) + 0.1f; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + animation.fromValue = [NSNumber numberWithFloat:self.progress]; + animation.toValue = [NSNumber numberWithFloat:pinnedProgress]; + [self.progressLayer addAnimation:animation forKey:@"progress"]; + } + else { + [self.progressLayer setNeedsDisplay]; + } + + self.progressLayer.progress = pinnedProgress; +} + +- (UIColor *)progressTintColor +{ + return self.progressLayer.progressTintColor; +} + +- (void)setProgressTintColor:(UIColor *)progressTintColor +{ + self.progressLayer.progressTintColor = progressTintColor; + [self.progressLayer setNeedsDisplay]; +} + +- (UIColor *)borderTintColor +{ + return self.progressLayer.borderTintColor; +} + +- (void)setBorderTintColor:(UIColor *)borderTintColor +{ + self.progressLayer.borderTintColor = borderTintColor; + [self.progressLayer setNeedsDisplay]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/UIResponder+Router.h b/Ash_AWord/ViewControllers/Chat/UIResponder+Router.h new file mode 100644 index 0000000..78cf20d --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/UIResponder+Router.h @@ -0,0 +1,26 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +@interface UIResponder (Router) + +/** + * 发送一个路由器消息, 对eventName感兴趣的 UIResponsder 可以对消息进行处理 + * + * @param eventName 发生的事件名称 + * @param userInfo 传递消息时, 携带的数据, 数据传递过程中, 会有新的数据添加 + * + */ +- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/UIResponder+Router.m b/Ash_AWord/ViewControllers/Chat/UIResponder+Router.m new file mode 100644 index 0000000..41eba22 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/UIResponder+Router.m @@ -0,0 +1,22 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "UIResponder+Router.h" + +@implementation UIResponder (Router) + +- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo +{ + [[self nextResponder] routerEventWithName:eventName userInfo:userInfo]; +} + +@end diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/EMVoiceConverter.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/EMVoiceConverter.h new file mode 100755 index 0000000..6dabf3e --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/EMVoiceConverter.h @@ -0,0 +1,21 @@ +// +// VoiceConverter.h +// Jeans +// +// Created by Jeans Huang on 12-7-22. +// Copyright (c) 2012年 __MyCompanyName__. All rights reserved. +// + +#import + +@interface EMVoiceConverter : NSObject + ++ (int)isMP3File:(NSString *)filePath; + ++ (int)isAMRFile:(NSString *)filePath; + ++ (int)amrToWav:(NSString*)_amrPath wavSavePath:(NSString*)_savePath; + ++ (int)wavToAmr:(NSString*)_wavPath amrSavePath:(NSString*)_savePath; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/EMVoiceConverter.mm b/Ash_AWord/ViewControllers/Chat/VoiceConvert/EMVoiceConverter.mm new file mode 100755 index 0000000..3f35ab8 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/EMVoiceConverter.mm @@ -0,0 +1,46 @@ +// +// VoiceConverter.m +// Jeans +// +// Created by Jeans Huang on 12-7-22. +// Copyright (c) 2012年 __MyCompanyName__. All rights reserved. +// + +#import "EMVoiceConverter.h" +#import "wav.h" +#import "interf_dec.h" +#import "dec_if.h" +#import "interf_enc.h" +#import "amrFileCodec.h" + +@implementation EMVoiceConverter + + ++ (int)isMP3File:(NSString *)filePath{ + const char *_filePath = [filePath cStringUsingEncoding:NSASCIIStringEncoding]; + return isMP3File(_filePath); +} + ++ (int)isAMRFile:(NSString *)filePath{ + const char *_filePath = [filePath cStringUsingEncoding:NSASCIIStringEncoding]; + return isAMRFile(_filePath); +} + ++ (int)amrToWav:(NSString*)_amrPath wavSavePath:(NSString*)_savePath{ + + if (EM_DecodeAMRFileToWAVEFile([_amrPath cStringUsingEncoding:NSASCIIStringEncoding], [_savePath cStringUsingEncoding:NSASCIIStringEncoding])) + return 0; // success + + return 1; // failed +} + ++ (int)wavToAmr:(NSString*)_wavPath amrSavePath:(NSString*)_savePath{ + + if (EM_EncodeWAVEFileToAMRFile([_wavPath cStringUsingEncoding:NSASCIIStringEncoding], [_savePath cStringUsingEncoding:NSASCIIStringEncoding], 1, 16)) + return 0; // success + + return 1; // failed +} + + +@end diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/amrFileCodec.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/amrFileCodec.h new file mode 100755 index 0000000..9798bd7 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/amrFileCodec.h @@ -0,0 +1,81 @@ +// +// amrFileCodec.h +// amrDemoForiOS +// +// Created by Tang Xiaoping on 9/27/11. +// Copyright 2011 test. All rights reserved. +// +#ifndef amrFileCodec_h +#define amrFileCodec_h +#include +#include +#include +#include "interf_dec.h" +#include "interf_enc.h" + +#define AMR_MAGIC_NUMBER "#!AMR\n" +#define MP3_MAGIC_NUMBER "ID3" + +#define PCM_FRAME_SIZE 160 // 8khz 8000*0.02=160 +#define MAX_AMR_FRAME_SIZE 32 +#define AMR_FRAME_COUNT_PER_SECOND 50 + +typedef struct +{ + char chChunkID[4]; + int nChunkSize; +}EM_XCHUNKHEADER; + +typedef struct +{ + short nFormatTag; + short nChannels; + int nSamplesPerSec; + int nAvgBytesPerSec; + short nBlockAlign; + short nBitsPerSample; +}EM_WAVEFORMAT; + +typedef struct +{ + short nFormatTag; + short nChannels; + int nSamplesPerSec; + int nAvgBytesPerSec; + short nBlockAlign; + short nBitsPerSample; + short nExSize; +}EM_WAVEFORMATX; + +typedef struct +{ + char chRiffID[4]; + int nRiffSize; + char chRiffFormat[4]; +}EM_RIFFHEADER; + +typedef struct +{ + char chFmtID[4]; + int nFmtSize; + EM_WAVEFORMAT wf; +}EM_FMTBLOCK; + +// WAVE音频采样频率是8khz +// 音频样本单元数 = 8000*0.02 = 160 (由采样频率决定) +// 声道数 1 : 160 +// 2 : 160*2 = 320 +// bps决定样本(sample)大小 +// bps = 8 --> 8位 unsigned char +// 16 --> 16位 unsigned short +int EM_EncodeWAVEFileToAMRFile(const char* pchWAVEFilename, const char* pchAMRFileName, int nChannels, int nBitsPerSample); + +// 将AMR文件解码成WAVE文件 +int EM_DecodeAMRFileToWAVEFile(const char* pchAMRFileName, const char* pchWAVEFilename); + +//是否是 MP3文件 +int isMP3File(const char *filePath); + +//是否是AMR 文件 +int isAMRFile(const char *filePath); +#endif \ No newline at end of file diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/amrFileCodec.mm b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/amrFileCodec.mm new file mode 100755 index 0000000..a4318f4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/amrFileCodec.mm @@ -0,0 +1,414 @@ +// +// amrFileCodec.cpp +// amrDemoForiOS +// +// Created by Tang Xiaoping on 9/27/11. +// Copyright 2011 test. All rights reserved. +// + +#include "amrFileCodec.h" +static int amrEncodeMode[] = {4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200}; // amr 编码方式 +// 从WAVE文件中跳过WAVE文件头,直接到PCM音频数据 +static void SkipToPCMAudioData(FILE* fpwave) +{ + EM_RIFFHEADER riff; + EM_FMTBLOCK fmt; + EM_XCHUNKHEADER chunk; + EM_WAVEFORMATX wfx; + int bDataBlock = 0; + + // 1. 读RIFF头 + fread(&riff, 1, sizeof(EM_RIFFHEADER), fpwave); + + // 2. 读FMT块 - 如果 fmt.nFmtSize>16 说明需要还有一个附属大小没有读 + fread(&chunk, 1, sizeof(EM_XCHUNKHEADER), fpwave); + if ( chunk.nChunkSize>16 ) + { + fread(&wfx, 1, sizeof(EM_WAVEFORMATX), fpwave); + } + else + { + memcpy(fmt.chFmtID, chunk.chChunkID, 4); + fmt.nFmtSize = chunk.nChunkSize; + fread(&fmt.wf, 1, sizeof(EM_WAVEFORMAT), fpwave); + } + + // 3.转到data块 - 有些还有fact块等。 + while(!bDataBlock) + { + fread(&chunk, 1, sizeof(EM_XCHUNKHEADER), fpwave); + if ( !memcmp(chunk.chChunkID, "data", 4) ) + { + bDataBlock = 1; + break; + } + // 因为这个不是data块,就跳过块数据 + fseek(fpwave, chunk.nChunkSize, SEEK_CUR); + } +} + +// 从WAVE文件读一个完整的PCM音频帧 +// 返回值: 0-错误 >0: 完整帧大小 +static size_t ReadPCMFrame(short speech[], FILE* fpwave, int nChannels, int nBitsPerSample) +{ + size_t nRead = 0; + int x = 0, y=0; +// unsigned short ush1=0, ush2=0, ush=0; + + // 原始PCM音频帧数据 + unsigned char pcmFrame_8b1[PCM_FRAME_SIZE]; + unsigned char pcmFrame_8b2[PCM_FRAME_SIZE<<1]; + unsigned short pcmFrame_16b1[PCM_FRAME_SIZE]; + unsigned short pcmFrame_16b2[PCM_FRAME_SIZE<<1]; + + if (nBitsPerSample==8 && nChannels==1) + { + nRead = fread(pcmFrame_8b1, (nBitsPerSample/8), PCM_FRAME_SIZE*nChannels, fpwave); + for(x=0; x> 1; + //speech[y] = (short)((short)ush << 7); + } + } + else + if (nBitsPerSample==16 && nChannels==1) + { + nRead = fread(pcmFrame_16b1, (nBitsPerSample/8), PCM_FRAME_SIZE*nChannels, fpwave); + for(x=0; x> 1; + } + } + + // 如果读到的数据不是一个完整的PCM帧, 就返回0 + if (nRead 8位 unsigned char +// 16 --> 16位 unsigned short +int EM_EncodeWAVEFileToAMRFile(const char* pchWAVEFilename, const char* pchAMRFileName, int nChannels, int nBitsPerSample) +{ + FILE* fpwave; + FILE* fpamr; + + /* input speech vector */ + short speech[160]; + + /* counters */ + int byte_counter, frames = 0; + size_t bytes = 0; + + /* pointer to encoder state structure */ + void *enstate; + + /* requested mode */ + enum Mode req_mode = MR122; + int dtx = 0; + + /* bitstream filetype */ + unsigned char amrFrame[MAX_AMR_FRAME_SIZE]; + + fpwave = fopen(pchWAVEFilename, "rb"); + if (fpwave == NULL) + { + return 0; + } + + // 创建并初始化amr文件 + fpamr = fopen(pchAMRFileName, "wb"); + if (fpamr == NULL) + { + fclose(fpwave); + return 0; + } + /* write magic number to indicate single channel AMR file storage format */ + bytes = fwrite(AMR_MAGIC_NUMBER, sizeof(char), strlen(AMR_MAGIC_NUMBER), fpamr); + + /* skip to pcm audio data*/ + SkipToPCMAudioData(fpwave); + + enstate = Encoder_Interface_init(dtx); + + while(1) + { + // read one pcm frame + if (!ReadPCMFrame(speech, fpwave, nChannels, nBitsPerSample)) break; + + frames++; + + /* call encoder */ + byte_counter = Encoder_Interface_Encode(enstate, req_mode, speech, amrFrame, 0); + + bytes += byte_counter; + fwrite(amrFrame, sizeof (unsigned char), byte_counter, fpamr ); + } + + Encoder_Interface_exit(enstate); + + fclose(fpamr); + fclose(fpwave); + + return frames; +} + + + + +#pragma mark - Decode +//decode +static void WriteWAVEFileHeader(FILE* fpwave, int nFrame) +{ + char tag[10] = ""; + + // 1. 写RIFF头 + EM_RIFFHEADER riff; + strcpy(tag, "RIFF"); + memcpy(riff.chRiffID, tag, 4); + riff.nRiffSize = 4 // WAVE + + sizeof(EM_XCHUNKHEADER) // fmt + + sizeof(EM_WAVEFORMATX) // EM_WAVEFORMATX + + sizeof(EM_XCHUNKHEADER) // DATA + + nFrame*160*sizeof(short); // + strcpy(tag, "WAVE"); + memcpy(riff.chRiffFormat, tag, 4); + fwrite(&riff, 1, sizeof(EM_RIFFHEADER), fpwave); + + // 2. 写FMT块 + EM_XCHUNKHEADER chunk; + EM_WAVEFORMATX wfx; + strcpy(tag, "fmt "); + memcpy(chunk.chChunkID, tag, 4); + chunk.nChunkSize = sizeof(EM_WAVEFORMATX); + fwrite(&chunk, 1, sizeof(EM_XCHUNKHEADER), fpwave); + memset(&wfx, 0, sizeof(EM_WAVEFORMATX)); + wfx.nFormatTag = 1; + wfx.nChannels = 1; // 单声道 + wfx.nSamplesPerSec = 8000; // 8khz + wfx.nAvgBytesPerSec = 16000; + wfx.nBlockAlign = 2; + wfx.nBitsPerSample = 16; // 16位 + fwrite(&wfx, 1, sizeof(EM_WAVEFORMATX), fpwave); + + // 3. 写data块头 + strcpy(tag, "data"); + memcpy(chunk.chChunkID, tag, 4); + chunk.nChunkSize = nFrame*160*sizeof(short); + fwrite(&chunk, 1, sizeof(EM_XCHUNKHEADER), fpwave); +} + +static const int myround(const double x) +{ + return((int)(x+0.5)); +} + +// 根据帧头计算当前帧大小 +static int caclAMRFrameSize(unsigned char frameHeader) +{ + int mode; + int temp1 = 0; + int temp2 = 0; + int frameSize; + + temp1 = frameHeader; + + // 编码方式编号 = 帧头的3-6位 + temp1 &= 0x78; // 0111-1000 + temp1 >>= 3; + + mode = amrEncodeMode[temp1]; + + // 计算amr音频数据帧大小 + // 原理: amr 一帧对应20ms,那么一秒有50帧的音频数据 + temp2 = myround((double)(((double)mode / (double)AMR_FRAME_COUNT_PER_SECOND) / (double)8)); + + frameSize = myround((double)temp2 + 0.5); + return frameSize; +} + +// 读第一个帧 - (参考帧) +// 返回值: 0-出错; 1-正确 +static int ReadAMRFrameFirst(FILE* fpamr, unsigned char frameBuffer[], int* stdFrameSize, unsigned char* stdFrameHeader) +{ + //memset(frameBuffer, 0, sizeof(frameBuffer)); + + // 先读帧头 + fread(stdFrameHeader, 1, sizeof(unsigned char), fpamr); + if (feof(fpamr)) return 0; + + // 根据帧头计算帧大小 + *stdFrameSize = caclAMRFrameSize(*stdFrameHeader); + + // 读首帧 + frameBuffer[0] = *stdFrameHeader; + fread(&(frameBuffer[1]), 1, (*stdFrameSize-1)*sizeof(unsigned char), fpamr); + if (feof(fpamr)) return 0; + + return 1; +} + +// 返回值: 0-出错; 1-正确 +static int ReadAMRFrame(FILE* fpamr, unsigned char frameBuffer[], int stdFrameSize, unsigned char stdFrameHeader) +{ + size_t bytes = 0; + unsigned char frameHeader; // 帧头 + + //memset(frameBuffer, 0, sizeof(frameBuffer)); + + // 读帧头 + // 如果是坏帧(不是标准帧头),则继续读下一个字节,直到读到标准帧头 + while(1) + { + bytes = fread(&frameHeader, 1, sizeof(unsigned char), fpamr); + if (feof(fpamr)) return 0; + if (frameHeader == stdFrameHeader) break; + } + + // 读该帧的语音数据(帧头已经读过) + frameBuffer[0] = frameHeader; + bytes = fread(&(frameBuffer[1]), 1, (stdFrameSize-1)*sizeof(unsigned char), fpamr); + if (feof(fpamr)) return 0; + + return 1; +} + +// 将AMR文件解码成WAVE文件 +int EM_DecodeAMRFileToWAVEFile(const char* pchAMRFileName, const char* pchWAVEFilename) +{ + + + FILE* fpamr = NULL; + FILE* fpwave = NULL; + char magic[8]; + void * destate; + int nFrameCount = 0; + int stdFrameSize; + unsigned char stdFrameHeader; + + unsigned char amrFrame[MAX_AMR_FRAME_SIZE]; + short pcmFrame[PCM_FRAME_SIZE]; + + fpamr = fopen(pchAMRFileName, "rb"); + + if ( fpamr==NULL ) return 0; + + // 检查amr文件头 + fread(magic, sizeof(char), strlen(AMR_MAGIC_NUMBER), fpamr); + if (strncmp(magic, AMR_MAGIC_NUMBER, strlen(AMR_MAGIC_NUMBER))) + { + fclose(fpamr); + return 0; + } + + // 创建并初始化WAVE文件 +// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); +// NSString *documentPath = [paths objectAtIndex:0]; +// NSString *docFilePath = [documentPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%s", pchWAVEFilename]]; +// NSLog(@"documentPath=%@", documentPath); +// +// fpwave = fopen([docFilePath cStringUsingEncoding:NSASCIIStringEncoding], "wb"); + fpwave = fopen(pchWAVEFilename,"wb"); + + WriteWAVEFileHeader(fpwave, nFrameCount); + + /* init decoder */ + destate = Decoder_Interface_init(); + + // 读第一帧 - 作为参考帧 + memset(amrFrame, 0, MAX_AMR_FRAME_SIZE); + memset(pcmFrame, 0, PCM_FRAME_SIZE); + ReadAMRFrameFirst(fpamr, amrFrame, &stdFrameSize, &stdFrameHeader); + + // 解码一个AMR音频帧成PCM数据 + Decoder_Interface_Decode(destate, amrFrame, pcmFrame, 0); + nFrameCount++; + fwrite(pcmFrame, sizeof(short), PCM_FRAME_SIZE, fpwave); + + // 逐帧解码AMR并写到WAVE文件里 + while(1) + { + memset(amrFrame, 0, MAX_AMR_FRAME_SIZE); + memset(pcmFrame, 0, PCM_FRAME_SIZE); + if (!ReadAMRFrame(fpamr, amrFrame, stdFrameSize, stdFrameHeader)) break; + + // 解码一个AMR音频帧成PCM数据 (8k-16b-单声道) + Decoder_Interface_Decode(destate, amrFrame, pcmFrame, 0); + nFrameCount++; + fwrite(pcmFrame, sizeof(short), PCM_FRAME_SIZE, fpwave); + } + //NSLog(@"frame = %d", nFrameCount); + Decoder_Interface_exit(destate); + + fclose(fpwave); + + // 重写WAVE文件头 +// fpwave = fopen([docFilePath cStringUsingEncoding:NSASCIIStringEncoding], "r+"); + fpwave = fopen(pchWAVEFilename, "r+"); + WriteWAVEFileHeader(fpwave, nFrameCount); + fclose(fpwave); + + return nFrameCount; +} + +int isMP3File(const char *filePath){ + FILE* fpamr = NULL; + char magic[8]; + fpamr = fopen(filePath, "rb"); + if (fpamr==NULL) return 0; + int isMp3 = 0; + fread(magic, sizeof(char), strlen(MP3_MAGIC_NUMBER), fpamr); + if (!strncmp(magic, MP3_MAGIC_NUMBER, strlen(MP3_MAGIC_NUMBER))) + { + isMp3 = 1; + } + fclose(fpamr); + return isMp3; +} + + +int isAMRFile(const char *filePath){ + FILE* fpamr = NULL; + char magic[8]; + fpamr = fopen(filePath, "rb"); + if (fpamr==NULL) return 0; + int isAmr = 0; + fread(magic, sizeof(char), strlen(AMR_MAGIC_NUMBER), fpamr); + if (!strncmp(magic, AMR_MAGIC_NUMBER, strlen(AMR_MAGIC_NUMBER))) + { + isAmr = 1; + } + fclose(fpamr); + return isAmr; +} diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/wav.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/wav.h new file mode 100755 index 0000000..ae77383 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/wav.h @@ -0,0 +1,47 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef WAV_H +#define WAV_H + +#include + +class WavWriter { +public: + WavWriter(const char *filename, int sampleRate, int bitsPerSample, int channels); + ~WavWriter(); + + void writeData(const unsigned char* data, int length); + +private: + void writeString(const char *str); + void writeInt32(int value); + void writeInt16(int value); + + void writeHeader(int length); + + FILE *wav; + int dataLength; + + int sampleRate; + int bitsPerSample; + int channels; +}; + +#endif + diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/wav.mm b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/wav.mm new file mode 100755 index 0000000..794b75b --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/amrwapper/wav.mm @@ -0,0 +1,97 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#import +#include "wav.h" + +void WavWriter::writeString(const char *str) { + fputc(str[0], wav); + fputc(str[1], wav); + fputc(str[2], wav); + fputc(str[3], wav); +} + +void WavWriter::writeInt32(int value) { + fputc((value >> 0) & 0xff, wav); + fputc((value >> 8) & 0xff, wav); + fputc((value >> 16) & 0xff, wav); + fputc((value >> 24) & 0xff, wav); +} + +void WavWriter::writeInt16(int value) { + fputc((value >> 0) & 0xff, wav); + fputc((value >> 8) & 0xff, wav); +} + +void WavWriter::writeHeader(int length) { + writeString("RIFF"); + writeInt32(4 + 8 + 20 + 8 + length); //将16改为20 + writeString("WAVE"); + + writeString("fmt "); + writeInt32(20); + + int bytesPerFrame = bitsPerSample/8*channels; + int bytesPerSec = bytesPerFrame*sampleRate; + writeInt16(1); // Format + writeInt16(channels); // Channels + writeInt32(sampleRate); // Samplerate + writeInt32(bytesPerSec); // Bytes per sec + writeInt16(bytesPerFrame); // Bytes per frame + writeInt16(bitsPerSample); // Bits per sample + + writeInt32(0); //这儿需要字节对齐 nExSize + + writeString("data"); + writeInt32(length); +} + +WavWriter::WavWriter(const char *filename, int sampleRate, int bitsPerSample, int channels) +{ + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentPath = [paths objectAtIndex:0]; + NSString *docFilePath = [documentPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%s", filename]]; + //NSLog(@"documentPath=%@", documentPath); + + wav = fopen([docFilePath cStringUsingEncoding:NSASCIIStringEncoding], "wb"); + if (wav == NULL) + return; + dataLength = 0; + this->sampleRate = sampleRate; + this->bitsPerSample = bitsPerSample; + this->channels = channels; + + writeHeader(dataLength); +} + +WavWriter::~WavWriter() { + if (wav == NULL) + return; + fseek(wav, 0, SEEK_SET); + writeHeader(dataLength); + fclose(wav); +} + +void WavWriter::writeData(const unsigned char* data, int length) { + if (wav == NULL) + return; + fwrite(data, length, 1, wav); + dataLength += length; +} + diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/interf_dec.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/interf_dec.h new file mode 100755 index 0000000..98051f4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/interf_dec.h @@ -0,0 +1,34 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef OPENCORE_AMRNB_INTERF_DEC_H +#define OPENCORE_AMRNB_INTERF_DEC_H + +#ifdef __cplusplus +extern "C" { +#endif + +void* Decoder_Interface_init(void); +void Decoder_Interface_exit(void* state); +void Decoder_Interface_Decode(void* state, const unsigned char* in, short* out, int bfi); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/interf_enc.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/interf_enc.h new file mode 100755 index 0000000..42b0df4 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/interf_enc.h @@ -0,0 +1,50 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef OPENCORE_AMRNB_INTERF_ENC_H +#define OPENCORE_AMRNB_INTERF_ENC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AMRNB_WRAPPER_INTERNAL +/* Copied from enc/src/gsmamr_enc.h */ +enum Mode { + MR475 = 0,/* 4.75 kbps */ + MR515, /* 5.15 kbps */ + MR59, /* 5.90 kbps */ + MR67, /* 6.70 kbps */ + MR74, /* 7.40 kbps */ + MR795, /* 7.95 kbps */ + MR102, /* 10.2 kbps */ + MR122, /* 12.2 kbps */ + MRDTX, /* DTX */ + N_MODES /* Not Used */ +}; +#endif + +void* Encoder_Interface_init(int dtx); +void Encoder_Interface_exit(void* state); +int Encoder_Interface_Encode(void* state, enum Mode mode, const short* speech, unsigned char* out, int forceSpeech); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/libopencore-amrnb.a b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/libopencore-amrnb.a new file mode 100644 index 0000000..88d73a2 Binary files /dev/null and b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrnb/libopencore-amrnb.a differ diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/dec_if.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/dec_if.h new file mode 100755 index 0000000..56acdaa --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/dec_if.h @@ -0,0 +1,36 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef OPENCORE_AMRWB_DEC_IF_H +#define OPENCORE_AMRWB_DEC_IF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define _good_frame 0 + +void* D_IF_init(void); +void D_IF_decode(void* state, const unsigned char* bits, short* synth, int bfi); +void D_IF_exit(void* state); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/if_rom.h b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/if_rom.h new file mode 100755 index 0000000..8977e03 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/if_rom.h @@ -0,0 +1,33 @@ +/* ------------------------------------------------------------------ + * Copyright (C) 2009 Martin Storsjo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. + * See the License for the specific language governing permissions + * and limitations under the License. + * ------------------------------------------------------------------- + */ + +#ifndef OPENCORE_AMRWB_IF_ROM_H +#define OPENCORE_AMRWB_IF_ROM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +typedef int16_t Word16; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/libopencore-amrwb.a b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/libopencore-amrwb.a new file mode 100644 index 0000000..e93892b Binary files /dev/null and b/Ash_AWord/ViewControllers/Chat/VoiceConvert/opencore-amrwb/libopencore-amrwb.a differ diff --git a/Ash_AWord/ViewControllers/Chat/XHMessageTextView.h b/Ash_AWord/ViewControllers/Chat/XHMessageTextView.h new file mode 100644 index 0000000..860c6d9 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/XHMessageTextView.h @@ -0,0 +1,57 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import + +typedef NS_ENUM(NSUInteger, XHTextViewInputViewType) { + XHTextViewNormalInputType = 0, + XHTextViewTextInputType, + XHTextViewFaceInputType, + XHTextViewShareMenuInputType, +}; + +@interface XHMessageTextView : UITextView + +/** + * 提示用户输入的标语 + */ +@property (nonatomic, copy) NSString *placeHolder; + +/** + * 标语文本的颜色 + */ +@property (nonatomic, strong) UIColor *placeHolderTextColor; + +/** + * 获取自身文本占据有多少行 + * + * @return 返回行数 + */ +- (NSUInteger)numberOfLinesOfText; + +/** + * 获取每行的高度 + * + * @return 根据iPhone或者iPad来获取每行字体的高度 + */ ++ (NSUInteger)maxCharactersPerLine; + +/** + * 获取某个文本占据自身适应宽带的行数 + * + * @param text 目标文本 + * + * @return 返回占据行数 + */ ++ (NSUInteger)numberOfLinesForMessage:(NSString *)text; + +@end diff --git a/Ash_AWord/ViewControllers/Chat/XHMessageTextView.m b/Ash_AWord/ViewControllers/Chat/XHMessageTextView.m new file mode 100644 index 0000000..d379229 --- /dev/null +++ b/Ash_AWord/ViewControllers/Chat/XHMessageTextView.m @@ -0,0 +1,164 @@ +/************************************************************ + * * EaseMob CONFIDENTIAL + * __________________ + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. + * + * NOTICE: All information contained herein is, and remains + * the property of EaseMob Technologies. + * Dissemination of this information or reproduction of this material + * is strictly forbidden unless prior written permission is obtained + * from EaseMob Technologies. + */ + +#import "XHMessageTextView.h" + +@implementation XHMessageTextView + +#pragma mark - Setters + +- (void)setPlaceHolder:(NSString *)placeHolder { + if([placeHolder isEqualToString:_placeHolder]) { + return; + } + + NSUInteger maxChars = [XHMessageTextView maxCharactersPerLine]; + if([placeHolder length] > maxChars) { + placeHolder = [placeHolder substringToIndex:maxChars - 8]; + placeHolder = [[placeHolder stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] stringByAppendingFormat:@"..."]; + } + + _placeHolder = placeHolder; + [self setNeedsDisplay]; +} + +- (void)setPlaceHolderTextColor:(UIColor *)placeHolderTextColor { + if([placeHolderTextColor isEqual:_placeHolderTextColor]) { + return; + } + + _placeHolderTextColor = placeHolderTextColor; + [self setNeedsDisplay]; +} + +#pragma mark - Message text view + +- (NSUInteger)numberOfLinesOfText { + return [XHMessageTextView numberOfLinesForMessage:self.text]; +} + ++ (NSUInteger)maxCharactersPerLine { + return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) ? 33 : 109; +} + ++ (NSUInteger)numberOfLinesForMessage:(NSString *)text { + return (text.length / [XHMessageTextView maxCharactersPerLine]) + 1; +} + +#pragma mark - Text view overrides + +- (void)setText:(NSString *)text { + [super setText:text]; + [self setNeedsDisplay]; +} + +- (void)setAttributedText:(NSAttributedString *)attributedText { + [super setAttributedText:attributedText]; + [self setNeedsDisplay]; +} + +//- (void)setContentInset:(UIEdgeInsets)contentInset { +// [super setContentInset:contentInset]; +// [self setNeedsDisplay]; +//} + +- (void)setFont:(UIFont *)font { + [super setFont:font]; + [self setNeedsDisplay]; +} + +- (void)setTextAlignment:(NSTextAlignment)textAlignment { + [super setTextAlignment:textAlignment]; + [self setNeedsDisplay]; +} + +#pragma mark - Notifications + +- (void)didReceiveTextDidChangeNotification:(NSNotification *)notification { + [self setNeedsDisplay]; +} + +#pragma mark - Life cycle + +- (void)setup { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveTextDidChangeNotification:) + name:UITextViewTextDidChangeNotification + object:self]; + + _placeHolderTextColor = [UIColor lightGrayColor]; + + self.autoresizingMask = UIViewAutoresizingFlexibleWidth; + self.scrollIndicatorInsets = UIEdgeInsetsMake(10.0f, 0.0f, 10.0f, 8.0f); + self.contentInset = UIEdgeInsetsZero; + self.scrollEnabled = YES; + self.scrollsToTop = NO; + self.userInteractionEnabled = YES; + self.font = [UIFont systemFontOfSize:16.0f]; + self.textColor = [UIColor blackColor]; + self.backgroundColor = [UIColor whiteColor]; + self.keyboardAppearance = UIKeyboardAppearanceDefault; + self.keyboardType = UIKeyboardTypeDefault; + self.returnKeyType = UIReturnKeyDefault; + self.textAlignment = NSTextAlignmentLeft; +} + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + [self setup]; + } + return self; +} + +- (void)dealloc { + _placeHolder = nil; + _placeHolderTextColor = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextViewTextDidChangeNotification object:self]; +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + + if([self.text length] == 0 && self.placeHolder) { + CGRect placeHolderRect = CGRectMake(10.0f, + 7.0f, + rect.size.width, + rect.size.height); + + [self.placeHolderTextColor set]; + + if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_0) { + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail; + paragraphStyle.alignment = self.textAlignment; + + [self.placeHolder drawInRect:placeHolderRect + withAttributes:@{ NSFontAttributeName : self.font, + NSForegroundColorAttributeName : self.placeHolderTextColor, + NSParagraphStyleAttributeName : paragraphStyle }]; + } + else { + [self.placeHolder drawInRect:placeHolderRect + withFont:self.font + lineBreakMode:NSLineBreakByTruncatingTail + alignment:self.textAlignment]; + } + } +} + +@end diff --git a/Ash_AWord/ViewControllers/Common/BaseRefreshViewController.h b/Ash_AWord/ViewControllers/Common/BaseRefreshViewController.h index 6c8404e..bb0d876 100644 --- a/Ash_AWord/ViewControllers/Common/BaseRefreshViewController.h +++ b/Ash_AWord/ViewControllers/Common/BaseRefreshViewController.h @@ -11,7 +11,6 @@ @interface BaseRefreshViewController : ViewController @property (weak, nonatomic) IBOutlet UITableView *tableView; - - (void)headerRereshing; - (void)footerRereshing; - (void)headerBeginRefreshing; diff --git a/Ash_AWord/ViewControllers/Login/LoginViewController.m b/Ash_AWord/ViewControllers/Login/LoginViewController.m index 1f6af50..f76cfe3 100644 --- a/Ash_AWord/ViewControllers/Login/LoginViewController.m +++ b/Ash_AWord/ViewControllers/Login/LoginViewController.m @@ -14,6 +14,7 @@ #import "WXApi.h" #import "RegistAccountViewController.h" #import "OurLoginViewController.h" +#import "EaseMob.h" @interface LoginViewController () @end @@ -156,9 +157,9 @@ [RequireEngine requireWithProperty:loginViewModel completionBlock:^(id viewModel) { LoginViewModel* loginViewModel = (LoginViewModel*)viewModel; [MBProgressHUD hideAllHUDsForView:self.view animated:YES]; - + if ([loginViewModel success]) { - + [Ash_UIUtil EaseMobLoginWithUserName:loginViewModel.uId]; [AWordUser sharedInstance].isLogin = YES; [AWordUser sharedInstance].loginType = 0; [AWordUser sharedInstance].uid = loginViewModel.uId; diff --git a/Ash_AWord/ViewControllers/Login/OurLoginViewController.m b/Ash_AWord/ViewControllers/Login/OurLoginViewController.m index b84f782..3b7be95 100644 --- a/Ash_AWord/ViewControllers/Login/OurLoginViewController.m +++ b/Ash_AWord/ViewControllers/Login/OurLoginViewController.m @@ -8,6 +8,7 @@ #import "OurLoginViewController.h" #import "LoginViewModel.h" +#import "EaseMob.h" @interface OurLoginViewController () @end @@ -98,7 +99,7 @@ [MBProgressHUD hideAllHUDsForView:self.view animated:YES]; if ([loginViewModel success]) { - + [Ash_UIUtil EaseMobLoginWithUserName:loginViewModel.uId]; [AWordUser sharedInstance].isLogin = YES; [AWordUser sharedInstance].loginType = 1; [AWordUser sharedInstance].uid = loginViewModel.uId; diff --git a/Ash_AWord/ViewControllers/Main/MainViewController.m b/Ash_AWord/ViewControllers/Main/MainViewController.m index 6d8edf5..4d678fc 100644 --- a/Ash_AWord/ViewControllers/Main/MainViewController.m +++ b/Ash_AWord/ViewControllers/Main/MainViewController.m @@ -66,6 +66,8 @@ [[UINavigationBar appearance] setTintColor:[UIColor blackColor]]; + + } - (void)didReceiveMemoryWarning diff --git a/Ash_AWord/ViewControllers/My/PersonalInfoViewController.m b/Ash_AWord/ViewControllers/My/PersonalInfoViewController.m index 528518b..cb3cb91 100644 --- a/Ash_AWord/ViewControllers/My/PersonalInfoViewController.m +++ b/Ash_AWord/ViewControllers/My/PersonalInfoViewController.m @@ -14,6 +14,7 @@ #import "MessageTableViewCell.h" #import "MessageViewModel.h" #import "UserViewModel.h" +#import "ChatMainViewController.h" @interface PersonalInfoViewController () { CExpandHeader *_header; @@ -324,5 +325,9 @@ */ - (IBAction)chatBtnClick:(id)sender { + ChatMainViewController* chatMainViewController = [[ChatMainViewController alloc] init]; + chatMainViewController.otherUserAvatar = _userViewModel.userInfo.figureurl; + chatMainViewController.otherUserName = _userViewModel.userInfo.name; + [self.navigationController pushViewController:chatMainViewController animated:YES]; } @end diff --git a/Ash_AWord/ViewControllers/Note/NoteCommentViewController.h b/Ash_AWord/ViewControllers/Note/NoteCommentViewController.h index 310a50b..bd15f67 100644 --- a/Ash_AWord/ViewControllers/Note/NoteCommentViewController.h +++ b/Ash_AWord/ViewControllers/Note/NoteCommentViewController.h @@ -10,10 +10,12 @@ #import "BaseRefreshViewController.h" @class Text_Image; @interface NoteCommentViewController : BaseRefreshViewController + @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UIView *lineView; - (IBAction)commentBtnClick:(id)sender; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *lineHeight; @property (weak, nonatomic) IBOutlet UIButton *commentBtn; @property (strong, nonatomic)Text_Image* text_image; + @end diff --git a/Ash_AWord/Views/Message/MessageTableViewCell.m b/Ash_AWord/Views/Message/MessageTableViewCell.m index fa0db15..246e1c5 100644 --- a/Ash_AWord/Views/Message/MessageTableViewCell.m +++ b/Ash_AWord/Views/Message/MessageTableViewCell.m @@ -289,11 +289,11 @@ } - (IBAction)avatarBtnClick:(id)sender { - if (![_text_voice.ownerId isEqualToString:[AWordUser sharedInstance].uid] ) { PersonalInfoViewController* personalInfoViewController = [[PersonalInfoViewController alloc] initWithNibName:@"NoteCommentViewController" bundle:nil]; - personalInfoViewController.hidesBottomBarWhenPushed = YES; - personalInfoViewController.otherUserId = _text_voice.ownerId; - [[AppDelegate visibleViewController].navigationController pushViewController:personalInfoViewController animated:YES]; - } + PersonalInfoViewController* personalInfoViewController = [[PersonalInfoViewController alloc] initWithNibName:@"PersonalInfoViewController" bundle:nil]; + personalInfoViewController.hidesBottomBarWhenPushed = YES; + personalInfoViewController.otherUserId = _text_voice.ownerId; + [[AppDelegate visibleViewController].navigationController pushViewController:personalInfoViewController animated:YES]; + } - (IBAction)closeBtnClick:(id)sender { }