├── .gitignore
├── LICENSE
├── README.md
├── TestIMDemo.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
└── TestIMDemo
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
├── AppIcon.appiconset
│ └── Contents.json
├── Contents.json
├── chatListCell
│ ├── Contents.json
│ └── chatListCellHead.imageset
│ │ ├── Contents.json
│ │ ├── chatListCellHead.png
│ │ └── chatListCellHead@2x.png
├── chatUI
│ ├── Contents.json
│ ├── VoiceSearchFeedback001.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback001@2x.png
│ ├── VoiceSearchFeedback002.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback002@2x.png
│ ├── VoiceSearchFeedback003.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback003@2x.png
│ ├── VoiceSearchFeedback004.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback004@2x.png
│ ├── VoiceSearchFeedback005.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback005@2x.png
│ ├── VoiceSearchFeedback006.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback006@2x.png
│ ├── VoiceSearchFeedback007.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback007@2x.png
│ ├── VoiceSearchFeedback008.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback008@2x.png
│ ├── VoiceSearchFeedback009.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback009@2x.png
│ ├── VoiceSearchFeedback010.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback010@2x.png
│ ├── VoiceSearchFeedback011.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback011@2x.png
│ ├── VoiceSearchFeedback012.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback012@2x.png
│ ├── VoiceSearchFeedback013.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback013@2x.png
│ ├── VoiceSearchFeedback014.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback014@2x.png
│ ├── VoiceSearchFeedback015.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback015@2x.png
│ ├── VoiceSearchFeedback016.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback016@2x.png
│ ├── VoiceSearchFeedback017.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback017@2x.png
│ ├── VoiceSearchFeedback018.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback018@2x.png
│ ├── VoiceSearchFeedback019.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback019@2x.png
│ ├── VoiceSearchFeedback020.imageset
│ │ ├── Contents.json
│ │ └── VoiceSearchFeedback020@2x.png
│ ├── arrow.imageset
│ │ ├── Contents.json
│ │ └── arrow@2x.png
│ ├── back.imageset
│ │ ├── Contents.json
│ │ └── back@2x.png
│ ├── chatBar_colorMore_audioCall.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_audioCall@2x.png
│ ├── chatBar_colorMore_audioCallSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_audioCallSelected@2x.png
│ ├── chatBar_colorMore_camera.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_camera@2x.png
│ ├── chatBar_colorMore_cameraSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_cameraSelected@2x.png
│ ├── chatBar_colorMore_location.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_location@2x.png
│ ├── chatBar_colorMore_locationSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_locationSelected@2x.png
│ ├── chatBar_colorMore_photo.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_photo@2x.png
│ ├── chatBar_colorMore_photoSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_photoSelected@2x.png
│ ├── chatBar_colorMore_video.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_video@2x.png
│ ├── chatBar_colorMore_videoCall.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_videoCall@2x.png
│ ├── chatBar_colorMore_videoCallSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_videoCallSelected@2x.png
│ ├── chatBar_colorMore_videoSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_colorMore_videoSelected@2x.png
│ ├── chatBar_face.imageset
│ │ ├── Contents.json
│ │ └── chatBar_face@2x.png
│ ├── chatBar_faceSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_faceSelected@2x.png
│ ├── chatBar_keyboard.imageset
│ │ ├── Contents.json
│ │ └── chatBar_keyboard@2x.png
│ ├── chatBar_keyboardSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_keyboardSelected@2x.png
│ ├── chatBar_more.imageset
│ │ ├── Contents.json
│ │ └── chatBar_more@2x.png
│ ├── chatBar_moreSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_moreSelected@2x.png
│ ├── chatBar_record.imageset
│ │ ├── Contents.json
│ │ └── chatBar_record@2x.png
│ ├── chatBar_recordBg.imageset
│ │ ├── Contents.json
│ │ └── chatBar_recordBg@2x.png
│ ├── chatBar_recordSelected.imageset
│ │ ├── Contents.json
│ │ └── chatBar_recordSelected@2x.png
│ ├── chatBar_recordSelectedBg.imageset
│ │ ├── Contents.json
│ │ └── chatBar_recordSelectedBg@2x.png
│ ├── chat_item_file.imageset
│ │ ├── Contents.json
│ │ └── chat_item_file@2x.png
│ ├── chat_location_preview.imageset
│ │ ├── Contents.json
│ │ └── chat_location_preview@2x.png
│ ├── chat_receiver_audio_playing000.imageset
│ │ ├── Contents.json
│ │ └── chat_receiver_audio_playing000@2x.png
│ ├── chat_receiver_audio_playing001.imageset
│ │ ├── Contents.json
│ │ └── chat_receiver_audio_playing001@2x.png
│ ├── chat_receiver_audio_playing002.imageset
│ │ ├── Contents.json
│ │ └── chat_receiver_audio_playing002@2x.png
│ ├── chat_receiver_audio_playing003.imageset
│ │ ├── Contents.json
│ │ └── chat_receiver_audio_playing003@2x.png
│ ├── chat_receiver_audio_playing_full.imageset
│ │ ├── Contents.json
│ │ └── chat_receiver_audio_playing_full@2x.png
│ ├── chat_receiver_bg.imageset
│ │ ├── Contents.json
│ │ └── chat_receiver_bg@2x.png
│ ├── chat_sender_audio_playing_000.imageset
│ │ ├── Contents.json
│ │ └── chat_sender_audio_playing_000@2x.png
│ ├── chat_sender_audio_playing_001.imageset
│ │ ├── Contents.json
│ │ └── chat_sender_audio_playing_001@2x.png
│ ├── chat_sender_audio_playing_002.imageset
│ │ ├── Contents.json
│ │ └── chat_sender_audio_playing_002@2x.png
│ ├── chat_sender_audio_playing_003.imageset
│ │ ├── Contents.json
│ │ └── chat_sender_audio_playing_003@2x.png
│ ├── chat_sender_audio_playing_full.imageset
│ │ ├── Contents.json
│ │ └── chat_sender_audio_playing_full@2x.png
│ ├── chat_sender_bg.imageset
│ │ ├── Contents.json
│ │ └── chat_sender_bg@2x.png
│ ├── faceDelete.imageset
│ │ ├── Contents.json
│ │ └── faceDelete@2x.png
│ ├── group.imageset
│ │ ├── Contents.json
│ │ └── group@2x.png
│ ├── imageDownloadFail.imageset
│ │ ├── Contents.json
│ │ └── imageDownloadFail@2x.png
│ ├── messageSendFail.imageset
│ │ ├── Contents.json
│ │ └── messageSendFail@2x.png
│ ├── messageToolbarBg.imageset
│ │ ├── Contents.json
│ │ └── messageToolbarBg@2x.png
│ ├── messageVideo.imageset
│ │ ├── Contents.json
│ │ └── messageVideo@2x.png
│ └── user.imageset
│ │ ├── Contents.json
│ │ └── user@2x.png
└── tabbar
│ ├── Contents.json
│ ├── tabbar_chats.imageset
│ ├── Contents.json
│ ├── tabbar_chats.png
│ └── tabbar_chats@2x.png
│ ├── tabbar_chatsHL.imageset
│ ├── Contents.json
│ ├── tabbar_chatsHL.png
│ └── tabbar_chatsHL@2x.png
│ ├── tabbar_contacts.imageset
│ ├── Contents.json
│ ├── tabbar_contacts.png
│ └── tabbar_contacts@2x.png
│ ├── tabbar_contactsHL.imageset
│ ├── Contents.json
│ ├── tabbar_contactsHL.png
│ └── tabbar_contactsHL@2x.png
│ ├── tabbar_setting.imageset
│ ├── Contents.json
│ ├── tabbar_setting.png
│ └── tabbar_setting@2x.png
│ └── tabbar_settingHL.imageset
│ ├── Contents.json
│ ├── tabbar_settingHL.png
│ └── tabbar_settingHL@2x.png
├── Base.lproj
├── LaunchScreen.storyboard
└── Main.storyboard
├── Classes
├── AddressBook
│ └── ViewController
│ │ ├── BRAddFriendViewController.h
│ │ ├── BRAddFriendViewController.m
│ │ ├── BRAddressBookController.h
│ │ └── BRAddressBookController.m
├── Chat
│ ├── Model
│ │ ├── BRAttributedText.h
│ │ └── BRAttributedText.m
│ ├── View
│ │ ├── BRChatCell.h
│ │ ├── BRChatCell.m
│ │ ├── BRTimeCell.h
│ │ └── BRTimeCell.m
│ └── ViewController
│ │ ├── BRChatViewController.h
│ │ └── BRChatViewController.m
├── Conversation
│ └── ViewController
│ │ ├── BRConversationController.h
│ │ └── BRConversationController.m
├── Login
│ └── ViewController
│ │ ├── BRLoginViewController.h
│ │ └── BRLoginViewController.m
├── Resource
│ ├── default.png
│ ├── en.lproj
│ │ └── Localizable.strings
│ ├── in.caf
│ └── zh-Hans.lproj
│ │ └── Localizable.strings
├── Setting
│ └── ViewController
│ │ ├── BRSettingController.h
│ │ └── BRSettingController.m
├── Utils
│ ├── Category
│ │ ├── CALayer+LayerColor.h
│ │ ├── CALayer+LayerColor.m
│ │ ├── NSDate+BRAdd.h
│ │ ├── NSDate+BRAdd.m
│ │ ├── UIViewController+Alert.h
│ │ └── UIViewController+Alert.m
│ └── Tools
│ │ ├── BRVoicePlayTool.h
│ │ └── BRVoicePlayTool.m
├── Vendor
│ └── DeviceHelper
│ │ ├── SDWebImage
│ │ ├── MKAnnotationView+WebCache.h
│ │ ├── MKAnnotationView+WebCache.m
│ │ ├── NSData+ImageContentType.h
│ │ ├── NSData+ImageContentType.m
│ │ ├── NSImage+WebCache.h
│ │ ├── NSImage+WebCache.m
│ │ ├── SDImageCache.h
│ │ ├── SDImageCache.m
│ │ ├── SDImageCacheConfig.h
│ │ ├── SDImageCacheConfig.m
│ │ ├── SDWebImageCompat.h
│ │ ├── SDWebImageCompat.m
│ │ ├── SDWebImageDecoder.h
│ │ ├── SDWebImageDecoder.m
│ │ ├── SDWebImageDownloader.h
│ │ ├── SDWebImageDownloader.m
│ │ ├── SDWebImageDownloaderOperation.h
│ │ ├── SDWebImageDownloaderOperation.m
│ │ ├── SDWebImageManager.h
│ │ ├── SDWebImageManager.m
│ │ ├── SDWebImageOperation.h
│ │ ├── SDWebImagePrefetcher.h
│ │ ├── SDWebImagePrefetcher.m
│ │ ├── UIButton+WebCache.h
│ │ ├── UIButton+WebCache.m
│ │ ├── UIImage+GIF.h
│ │ ├── UIImage+GIF.m
│ │ ├── UIImage+MultiFormat.h
│ │ ├── UIImage+MultiFormat.m
│ │ ├── UIImage+WebP.h
│ │ ├── UIImage+WebP.m
│ │ ├── UIImageView+HighlightedWebCache.h
│ │ ├── UIImageView+HighlightedWebCache.m
│ │ ├── UIImageView+WebCache.h
│ │ ├── UIImageView+WebCache.m
│ │ ├── UIView+WebCache.h
│ │ ├── UIView+WebCache.m
│ │ ├── UIView+WebCacheOperation.h
│ │ └── UIView+WebCacheOperation.m
│ │ ├── VoiceConvert
│ │ ├── EMVoiceConverter.h
│ │ ├── EMVoiceConverter.mm
│ │ ├── amrwapper
│ │ │ ├── amrFileCodec.h
│ │ │ ├── amrFileCodec.mm
│ │ │ ├── wav.h
│ │ │ └── wav.mm
│ │ ├── opencore-amrnb
│ │ │ ├── interf_dec.h
│ │ │ ├── interf_enc.h
│ │ │ └── libopencore-amrnb.a
│ │ └── opencore-amrwb
│ │ │ ├── dec_if.h
│ │ │ ├── if_rom.h
│ │ │ └── libopencore-amrwb.a
│ │ ├── delegates
│ │ ├── EMCDDeviceManagerDelegate.h
│ │ └── EMCDDeviceManagerProximitySensorDelegate.h
│ │ └── internal
│ │ ├── DemoErrorCode.h
│ │ ├── EMAudioPlayerUtil.h
│ │ ├── EMAudioPlayerUtil.m
│ │ ├── EMAudioRecorderUtil.h
│ │ ├── EMAudioRecorderUtil.m
│ │ ├── EMCDDeviceManager+Media.h
│ │ ├── EMCDDeviceManager+Media.m
│ │ ├── EMCDDeviceManager+Microphone.h
│ │ ├── EMCDDeviceManager+Microphone.m
│ │ ├── EMCDDeviceManager+ProximitySensor.h
│ │ ├── EMCDDeviceManager+ProximitySensor.m
│ │ ├── EMCDDeviceManager+Remind.h
│ │ ├── EMCDDeviceManager+Remind.m
│ │ ├── EMCDDeviceManager.h
│ │ ├── EMCDDeviceManagerBase.h
│ │ └── EMCDDeviceManagerBase.m
└── Xib
│ └── Login.storyboard
├── Info.plist
├── PrefixHeader.pch
└── main.m
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | # CocoaPods
32 | #
33 | # We recommend against adding the Pods directory to your .gitignore. However
34 | # you should judge for yourself, the pros and cons are mentioned at:
35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36 | #
37 | # Pods/
38 |
39 | # Carthage
40 | #
41 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
42 | # Carthage/Checkouts
43 |
44 | Carthage/Build
45 |
46 | # fastlane
47 | #
48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
49 | # screenshots whenever they are needed.
50 | # For more information about the recommended setup visit:
51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
52 |
53 | fastlane/report.xml
54 | fastlane/Preview.html
55 | fastlane/screenshots
56 | fastlane/test_output
57 |
58 | # Code Injection
59 | #
60 | # After new code Injection tools there's a generated folder /iOSInjectionProject
61 | # https://github.com/johnno1962/injectionforxcode
62 |
63 | iOSInjectionProject/
64 | # 忽略环信SDK,内存较大,需另行下载
65 | TestIMDemo/Classes/Vendor/HyphenateFullSDK
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TestIMDemo
2 | 测试环信SDK的集成
3 |
--------------------------------------------------------------------------------
/TestIMDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TestIMDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/20.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/TestIMDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/20.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // 1.初始化环信SDK
20 | EMOptions *options = [EMOptions optionsWithAppkey:EaseMobAppKey]; // 注册的AppKey
21 | //options.apnsCertName = @"push_cer"; // 推送证书名(不需要加后缀)
22 | [[EMClient sharedClient] initializeSDKWithOptions:options];
23 |
24 | // 2.设置自动登录
25 | // 设置EMClient的代理(添加回调监听代理),监听自动登录的状态
26 | [[EMClient sharedClient] addDelegate:self delegateQueue:nil];
27 | // 如果登录过,直接进入主界面
28 | if ([EMClient sharedClient].isAutoLogin) {
29 | // 进入主界面(拿到 Main.storyboard 箭头所指的控制器,即 tabBarController)
30 | self.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateInitialViewController];
31 | }
32 |
33 | return YES;
34 | }
35 |
36 | #pragma mark - EMClientDelegate 自动登录的回调(这个代理方法可以知道自动登录是否成功!)
37 | - (void)autoLoginDidCompleteWithError:(EMError *)aError {
38 | if (!aError) {
39 | NSLog(@"自动登录成功!");
40 | } else {
41 | NSLog(@"自动登录失败:%@", aError);
42 | }
43 | }
44 |
45 |
46 | - (void)applicationWillResignActive:(UIApplication *)application {
47 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
48 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
49 | }
50 |
51 | // APP进入后台
52 | - (void)applicationDidEnterBackground:(UIApplication *)application {
53 | [[EMClient sharedClient] applicationDidEnterBackground:application];
54 | }
55 |
56 | // APP将要从后台返回
57 | - (void)applicationWillEnterForeground:(UIApplication *)application {
58 | [[EMClient sharedClient] applicationWillEnterForeground:application];
59 | }
60 |
61 |
62 | - (void)applicationDidBecomeActive:(UIApplication *)application {
63 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
64 | }
65 |
66 |
67 | - (void)applicationWillTerminate:(UIApplication *)application {
68 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
69 | }
70 |
71 | - (void)dealloc {
72 | // 移除代理(有添加就有移除)
73 | [[EMClient sharedClient] removeDelegate:self];
74 | }
75 |
76 |
77 | @end
78 |
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatListCell/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatListCell/chatListCellHead.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "chatListCellHead.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "chatListCellHead@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatListCell/chatListCellHead.imageset/chatListCellHead.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatListCell/chatListCellHead.imageset/chatListCellHead.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatListCell/chatListCellHead.imageset/chatListCellHead@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatListCell/chatListCellHead.imageset/chatListCellHead@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback001.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback001@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback001.imageset/VoiceSearchFeedback001@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback001.imageset/VoiceSearchFeedback001@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback002.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback002@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback002.imageset/VoiceSearchFeedback002@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback002.imageset/VoiceSearchFeedback002@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback003.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback003@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback003.imageset/VoiceSearchFeedback003@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback003.imageset/VoiceSearchFeedback003@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback004.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback004@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback004.imageset/VoiceSearchFeedback004@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback004.imageset/VoiceSearchFeedback004@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback005.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback005@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback005.imageset/VoiceSearchFeedback005@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback005.imageset/VoiceSearchFeedback005@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback006.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback006@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback006.imageset/VoiceSearchFeedback006@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback006.imageset/VoiceSearchFeedback006@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback007.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback007@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback007.imageset/VoiceSearchFeedback007@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback007.imageset/VoiceSearchFeedback007@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback008.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback008@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback008.imageset/VoiceSearchFeedback008@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback008.imageset/VoiceSearchFeedback008@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback009.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback009@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback009.imageset/VoiceSearchFeedback009@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback009.imageset/VoiceSearchFeedback009@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback010.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback010@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback010.imageset/VoiceSearchFeedback010@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback010.imageset/VoiceSearchFeedback010@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback011.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback011@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback011.imageset/VoiceSearchFeedback011@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback011.imageset/VoiceSearchFeedback011@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback012.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback012@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback012.imageset/VoiceSearchFeedback012@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback012.imageset/VoiceSearchFeedback012@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback013.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback013@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback013.imageset/VoiceSearchFeedback013@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback013.imageset/VoiceSearchFeedback013@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback014.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback014@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback014.imageset/VoiceSearchFeedback014@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback014.imageset/VoiceSearchFeedback014@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback015.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback015@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback015.imageset/VoiceSearchFeedback015@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback015.imageset/VoiceSearchFeedback015@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback016.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback016@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback016.imageset/VoiceSearchFeedback016@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback016.imageset/VoiceSearchFeedback016@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback017.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback017@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback017.imageset/VoiceSearchFeedback017@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback017.imageset/VoiceSearchFeedback017@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback018.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback018@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback018.imageset/VoiceSearchFeedback018@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback018.imageset/VoiceSearchFeedback018@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback019.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback019@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback019.imageset/VoiceSearchFeedback019@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback019.imageset/VoiceSearchFeedback019@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback020.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "VoiceSearchFeedback020@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback020.imageset/VoiceSearchFeedback020@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/VoiceSearchFeedback020.imageset/VoiceSearchFeedback020@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/arrow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "arrow@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/arrow.imageset/arrow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/arrow.imageset/arrow@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/back.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "back@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/back.imageset/back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/back.imageset/back@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_audioCall.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_audioCall@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_audioCall.imageset/chatBar_colorMore_audioCall@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_audioCall.imageset/chatBar_colorMore_audioCall@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_audioCallSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_audioCallSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_audioCallSelected.imageset/chatBar_colorMore_audioCallSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_audioCallSelected.imageset/chatBar_colorMore_audioCallSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_camera.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_camera@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_camera.imageset/chatBar_colorMore_camera@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_camera.imageset/chatBar_colorMore_camera@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_cameraSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_cameraSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_cameraSelected.imageset/chatBar_colorMore_cameraSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_cameraSelected.imageset/chatBar_colorMore_cameraSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_location.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_location@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_location.imageset/chatBar_colorMore_location@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_location.imageset/chatBar_colorMore_location@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_locationSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_locationSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_locationSelected.imageset/chatBar_colorMore_locationSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_locationSelected.imageset/chatBar_colorMore_locationSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_photo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_photo@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_photo.imageset/chatBar_colorMore_photo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_photo.imageset/chatBar_colorMore_photo@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_photoSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_photoSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_photoSelected.imageset/chatBar_colorMore_photoSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_photoSelected.imageset/chatBar_colorMore_photoSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_video.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_video@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_video.imageset/chatBar_colorMore_video@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_video.imageset/chatBar_colorMore_video@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoCall.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_videoCall@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoCall.imageset/chatBar_colorMore_videoCall@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoCall.imageset/chatBar_colorMore_videoCall@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoCallSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_videoCallSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoCallSelected.imageset/chatBar_colorMore_videoCallSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoCallSelected.imageset/chatBar_colorMore_videoCallSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_colorMore_videoSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoSelected.imageset/chatBar_colorMore_videoSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_colorMore_videoSelected.imageset/chatBar_colorMore_videoSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_face.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_face@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_face.imageset/chatBar_face@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_face.imageset/chatBar_face@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_faceSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_faceSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_faceSelected.imageset/chatBar_faceSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_faceSelected.imageset/chatBar_faceSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_keyboard.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_keyboard@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_keyboard.imageset/chatBar_keyboard@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_keyboard.imageset/chatBar_keyboard@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_keyboardSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_keyboardSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_keyboardSelected.imageset/chatBar_keyboardSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_keyboardSelected.imageset/chatBar_keyboardSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_more.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_more@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_more.imageset/chatBar_more@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_more.imageset/chatBar_more@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_moreSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_moreSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_moreSelected.imageset/chatBar_moreSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_moreSelected.imageset/chatBar_moreSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_record.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_record@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_record.imageset/chatBar_record@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_record.imageset/chatBar_record@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordBg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_recordBg@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordBg.imageset/chatBar_recordBg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordBg.imageset/chatBar_recordBg@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordSelected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_recordSelected@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordSelected.imageset/chatBar_recordSelected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordSelected.imageset/chatBar_recordSelected@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordSelectedBg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chatBar_recordSelectedBg@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordSelectedBg.imageset/chatBar_recordSelectedBg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chatBar_recordSelectedBg.imageset/chatBar_recordSelectedBg@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_item_file.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_item_file@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_item_file.imageset/chat_item_file@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_item_file.imageset/chat_item_file@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_location_preview.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_location_preview@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_location_preview.imageset/chat_location_preview@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_location_preview.imageset/chat_location_preview@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing000.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_receiver_audio_playing000@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing000.imageset/chat_receiver_audio_playing000@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing000.imageset/chat_receiver_audio_playing000@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing001.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_receiver_audio_playing001@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing001.imageset/chat_receiver_audio_playing001@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing001.imageset/chat_receiver_audio_playing001@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing002.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_receiver_audio_playing002@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing002.imageset/chat_receiver_audio_playing002@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing002.imageset/chat_receiver_audio_playing002@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing003.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_receiver_audio_playing003@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing003.imageset/chat_receiver_audio_playing003@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing003.imageset/chat_receiver_audio_playing003@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing_full.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_receiver_audio_playing_full@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing_full.imageset/chat_receiver_audio_playing_full@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_audio_playing_full.imageset/chat_receiver_audio_playing_full@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_bg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_receiver_bg@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_bg.imageset/chat_receiver_bg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_receiver_bg.imageset/chat_receiver_bg@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_000.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_sender_audio_playing_000@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_000.imageset/chat_sender_audio_playing_000@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_000.imageset/chat_sender_audio_playing_000@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_001.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_sender_audio_playing_001@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_001.imageset/chat_sender_audio_playing_001@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_001.imageset/chat_sender_audio_playing_001@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_002.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_sender_audio_playing_002@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_002.imageset/chat_sender_audio_playing_002@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_002.imageset/chat_sender_audio_playing_002@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_003.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_sender_audio_playing_003@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_003.imageset/chat_sender_audio_playing_003@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_003.imageset/chat_sender_audio_playing_003@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_full.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_sender_audio_playing_full@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_full.imageset/chat_sender_audio_playing_full@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_sender_audio_playing_full.imageset/chat_sender_audio_playing_full@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_bg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "chat_sender_bg@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/chat_sender_bg.imageset/chat_sender_bg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/chat_sender_bg.imageset/chat_sender_bg@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/faceDelete.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "faceDelete@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/faceDelete.imageset/faceDelete@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/faceDelete.imageset/faceDelete@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/group.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "group@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/group.imageset/group@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/group.imageset/group@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/imageDownloadFail.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "imageDownloadFail@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/imageDownloadFail.imageset/imageDownloadFail@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/imageDownloadFail.imageset/imageDownloadFail@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/messageSendFail.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "messageSendFail@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/messageSendFail.imageset/messageSendFail@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/messageSendFail.imageset/messageSendFail@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/messageToolbarBg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "messageToolbarBg@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/messageToolbarBg.imageset/messageToolbarBg@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/messageToolbarBg.imageset/messageToolbarBg@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/messageVideo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "messageVideo@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/messageVideo.imageset/messageVideo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/messageVideo.imageset/messageVideo@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/user.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "user@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/chatUI/user.imageset/user@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/chatUI/user.imageset/user@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_chats.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tabbar_chats.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tabbar_chats@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_chats.imageset/tabbar_chats.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_chats.imageset/tabbar_chats.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_chats.imageset/tabbar_chats@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_chats.imageset/tabbar_chats@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_chatsHL.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tabbar_chatsHL.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tabbar_chatsHL@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_chatsHL.imageset/tabbar_chatsHL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_chatsHL.imageset/tabbar_chatsHL.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_chatsHL.imageset/tabbar_chatsHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_chatsHL.imageset/tabbar_chatsHL@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_contacts.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tabbar_contacts.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tabbar_contacts@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_contacts.imageset/tabbar_contacts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_contacts.imageset/tabbar_contacts.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_contacts.imageset/tabbar_contacts@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_contacts.imageset/tabbar_contacts@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_contactsHL.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tabbar_contactsHL.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tabbar_contactsHL@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_contactsHL.imageset/tabbar_contactsHL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_contactsHL.imageset/tabbar_contactsHL.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_contactsHL.imageset/tabbar_contactsHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_contactsHL.imageset/tabbar_contactsHL@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_setting.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tabbar_setting.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tabbar_setting@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_setting.imageset/tabbar_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_setting.imageset/tabbar_setting.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_setting.imageset/tabbar_setting@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_setting.imageset/tabbar_setting@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_settingHL.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tabbar_settingHL.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tabbar_settingHL@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_settingHL.imageset/tabbar_settingHL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_settingHL.imageset/tabbar_settingHL.png
--------------------------------------------------------------------------------
/TestIMDemo/Assets.xcassets/tabbar/tabbar_settingHL.imageset/tabbar_settingHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Assets.xcassets/tabbar/tabbar_settingHL.imageset/tabbar_settingHL@2x.png
--------------------------------------------------------------------------------
/TestIMDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/AddressBook/ViewController/BRAddFriendViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRAddFriendViewController.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/24.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRAddFriendViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/AddressBook/ViewController/BRAddFriendViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRAddFriendViewController.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/24.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRAddFriendViewController.h"
10 |
11 | @interface BRAddFriendViewController ()
12 | @property (weak, nonatomic) IBOutlet UITextField *textField;
13 |
14 | @end
15 |
16 | @implementation BRAddFriendViewController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 |
21 | }
22 |
23 | // 搜索按钮,添加朋友
24 | - (IBAction)clickAddFriendBtn:(id)sender {
25 | NSString *friendName = self.textField.text;
26 | NSString *message = [NSString stringWithFormat:@"我是%@", [EMClient sharedClient].currentUsername];
27 | // 添加好友请求
28 | [[EMClient sharedClient].contactManager addContact:friendName message:message completion:^(NSString *aUsername, EMError *aError) {
29 | if (!aError) {
30 | NSLog(@"邀请发送成功!");
31 | } else {
32 | NSLog(@"邀请发送失败:%@", aError);
33 | }
34 | }];
35 | }
36 |
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/AddressBook/ViewController/BRAddressBookController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRAddressBookController.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/24.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRAddressBookController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/AddressBook/ViewController/BRAddressBookController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRAddressBookController.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/24.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRAddressBookController.h"
10 | #import "BRChatViewController.h"
11 |
12 | @interface BRAddressBookController ()
13 | @property (nonatomic, strong) NSArray *contactArr;
14 |
15 | @end
16 |
17 | @implementation BRAddressBookController
18 |
19 | - (void)viewDidLoad {
20 | [super viewDidLoad];
21 |
22 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:@"updateContactList" object:nil];
23 |
24 | [self loadData];
25 | }
26 |
27 | // 收到 updateContactList 通知之后执行的事件
28 | - (void)receiveNotification:(NSNotification *)sender {
29 | // 更新好友列表
30 | [self loadData];
31 | }
32 |
33 |
34 | // 获取好友列表的数据
35 | - (void)loadData {
36 | // // 方法1:从本地数据库获取所有的好友(通常是没有网络的情况下用这个)
37 | // self.contactArr = [[EMClient sharedClient].contactManager getContacts];
38 | // [self.tableView reloadData];
39 |
40 | // 方法2:从服务器获取所有的好友 <异步方法>
41 | [[EMClient sharedClient].contactManager getContactsFromServerWithCompletion:^(NSArray *aList, EMError *aError) {
42 | if (!aError) {
43 | NSLog(@"获取好友列表成功:%@", aList);
44 | self.contactArr = aList;
45 | [self.tableView reloadData];
46 | } else {
47 | NSLog(@"获取好友失败:%@", aError);
48 | }
49 | }];
50 | }
51 |
52 | #pragma mark - Table view data source
53 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
54 | return 1;
55 | }
56 |
57 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
58 | return self.contactArr.count;
59 | }
60 |
61 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
62 | static NSString *cellID = @"AddressBookCell";
63 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
64 | cell.imageView.image = [UIImage imageNamed:@"chatListCellHead"];
65 | cell.textLabel.text = self.contactArr[indexPath.row];
66 |
67 | return cell;
68 | }
69 |
70 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
71 |
72 | }
73 |
74 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
75 | if (editingStyle == UITableViewCellEditingStyleDelete) {
76 | NSLog(@"删除好友");
77 | // 删除好友请求
78 | [[EMClient sharedClient].contactManager deleteContact:self.contactArr[indexPath.row] isDeleteConversation:YES completion:^(NSString *aUsername, EMError *aError) {
79 | if (!aError) {
80 | NSLog(@"删除好友操作成功!");
81 | // 重新从服务器获取好友列表数据
82 | [self loadData];
83 | }
84 | }];
85 | }
86 | }
87 |
88 | - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
89 | return @"删除";
90 | }
91 |
92 | #pragma mark - 连线跳转传值(目的:将好友的用户名传到聊天界面)
93 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
94 | // 获取目标控制器
95 | id nextVC = segue.destinationViewController;
96 | if ([nextVC isKindOfClass:[BRChatViewController class]]) {
97 | // 获取当前点击(选中)的cell
98 | NSInteger selectedRow = [self.tableView indexPathForSelectedRow].row;
99 | BRChatViewController *chatVC = nextVC;
100 | // 给下一个页面传值
101 | chatVC.contactUsername = self.contactArr[selectedRow];
102 | }
103 | }
104 |
105 | - (NSArray *)contactArr {
106 | if (!_contactArr) {
107 | _contactArr = [NSArray array];
108 | }
109 | return _contactArr;
110 | }
111 |
112 | - (void)dealloc {
113 | // 移除当前对象监听的事件
114 | [[NSNotificationCenter defaultCenter] removeObserver:self];
115 | }
116 |
117 | @end
118 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/Model/BRAttributedText.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRAttributedText.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/31.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRAttributedText : NSObject
12 | /** 返回语音的富文本 */
13 | + (NSAttributedString *)voiceAttrText:(EMMessage *)message isPlaying:(BOOL)isPlaying;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/Model/BRAttributedText.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRAttributedText.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/31.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRAttributedText.h"
10 |
11 | @implementation BRAttributedText
12 | #pragma mark - 返回语音的富文本
13 | + (NSAttributedString *)voiceAttrText:(EMMessage *)message isPlaying:(BOOL)isPlaying {
14 | EMVoiceMessageBody *voiceMsgBody = (EMVoiceMessageBody *)message.body;
15 | int duration = voiceMsgBody.duration;
16 | // 空格个数,控制语音消息的显示长度
17 | NSString *spacingText = @"";
18 | NSInteger length = MIN(duration, 50) / 2;
19 | for (NSInteger i = 0; i < length; i++) {
20 | spacingText = [spacingText stringByAppendingString:@" "];
21 | }
22 |
23 | // 1.创建一个可变的富文本
24 | NSMutableAttributedString *voiceAttr = [[NSMutableAttributedString alloc]init];
25 | if (message.direction == EMMessageDirectionReceive) {
26 | // 接收方(左边):富文本 = 图片 + 时间
27 | // 创建图片附件
28 | NSTextAttachment *imageAttachment = [[NSTextAttachment alloc]init];
29 | if (!isPlaying) {
30 | imageAttachment.image = [UIImage imageNamed:@"chat_receiver_audio_playing_full"];
31 | }
32 | // y 为负数,把文字往上调
33 | imageAttachment.bounds = CGRectMake(0, -6, 20, 20);
34 | // 1.1 创建图片富文本
35 | NSAttributedString *imageAttr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
36 | [voiceAttr appendAttributedString:imageAttr];
37 |
38 | // 1.2 创建时间富文本
39 | NSString *timeStr = [NSString stringWithFormat:@"%@ %d'", spacingText, duration];
40 | NSMutableAttributedString *timeAttr = [[NSMutableAttributedString alloc]initWithString:timeStr];
41 | //富文本样式
42 | [timeAttr addAttribute:NSForegroundColorAttributeName value:[UIColor darkGrayColor] range:NSMakeRange(0, timeStr.length)];
43 | [timeAttr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:NSMakeRange(0, timeStr.length)];
44 |
45 | [voiceAttr appendAttributedString:timeAttr];
46 |
47 | } else {
48 | // 发送方(右边):富文本 = 时间 + 图片
49 | // 2.1 创建时间富文本
50 | NSString *timeStr = [NSString stringWithFormat:@"%d' %@", duration, spacingText];
51 | NSMutableAttributedString *timeAttr = [[NSMutableAttributedString alloc]initWithString:timeStr];
52 | [timeAttr addAttribute:NSForegroundColorAttributeName value:[UIColor darkGrayColor] range:NSMakeRange(0, timeStr.length)];
53 | [timeAttr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:NSMakeRange(0, timeStr.length)];
54 | [voiceAttr appendAttributedString:timeAttr];
55 | // 创建图片附件
56 | NSTextAttachment *imageAttachment = [[NSTextAttachment alloc]init];
57 | if (!isPlaying) {
58 | imageAttachment.image = [UIImage imageNamed:@"chat_sender_audio_playing_full"];
59 | }
60 | imageAttachment.bounds = CGRectMake(0, -6, 20, 20);
61 | // 2.2 创建图片富文本
62 | NSAttributedString *imageAttr = [NSAttributedString attributedStringWithAttachment:imageAttachment];
63 | [voiceAttr appendAttributedString:imageAttr];
64 | }
65 |
66 | return [voiceAttr copy];
67 | }
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/View/BRChatCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRChatCell.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRChatCell : UITableViewCell
12 | @property (weak, nonatomic) IBOutlet UILabel *messageLabel;
13 | /** 消息模型 */
14 | @property (nonatomic, strong) EMMessage *messageModel;
15 |
16 | /** 计算cell的高度 */
17 | - (CGFloat)cellHeight;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/View/BRChatCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRChatCell.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRChatCell.h"
10 | #import "BRVoicePlayTool.h"
11 | #import "BRAttributedText.h"
12 | #import "UIImageView+WebCache.h"
13 |
14 | @interface BRChatCell ()
15 | @property (nonatomic, strong) UIImageView *chatImageView;
16 |
17 | @end
18 |
19 | @implementation BRChatCell
20 |
21 | #pragma mark - 在此方法中做一些初始化操作
22 | - (void)awakeFromNib {
23 | [super awakeFromNib];
24 | // 给label添加tap手势
25 | UITapGestureRecognizer *myTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didTapMessageLabel:)];
26 | [self.messageLabel addGestureRecognizer:myTap];
27 | }
28 |
29 | #pragma mark - label的点击事件
30 | - (void)didTapMessageLabel:(UITapGestureRecognizer *)sender {
31 | EMMessageBody *voiceBody = self.messageModel.body;
32 | if (voiceBody.type == EMMessageBodyTypeVoice) {
33 | NSLog(@"播放语音");
34 | [BRVoicePlayTool playWithMessage:self.messageModel msgLabel:self.messageLabel];
35 | }
36 | }
37 |
38 | - (void)setMessageModel:(EMMessage *)messageModel {
39 | _messageModel = messageModel;
40 |
41 | // 重用时,把聊天图片控件移除
42 | [self.chatImageView removeFromSuperview];
43 |
44 | // 解析普通消息
45 | EMMessageBody *msgBody = messageModel.body;
46 | switch (msgBody.type) {
47 | case EMMessageBodyTypeText:
48 | {
49 | // 文字消息
50 | EMTextMessageBody *textMsgBody = (EMTextMessageBody *)msgBody;
51 | self.messageLabel.text = textMsgBody.text;
52 | }
53 | break;
54 | case EMMessageBodyTypeImage:
55 | {
56 | // 图片消息
57 | EMImageMessageBody *imageMsgBody = (EMImageMessageBody *)msgBody;
58 | [self showImage:imageMsgBody];
59 | }
60 | break;
61 | case EMMessageBodyTypeVoice:
62 | {
63 | // 音频消息
64 | EMVoiceMessageBody *voiceMsgBody = (EMVoiceMessageBody *)msgBody;
65 | self.messageLabel.attributedText = [BRAttributedText voiceAttrText:messageModel isPlaying:NO];
66 | }
67 | break;
68 | case EMMessageBodyTypeVideo:
69 | {
70 | // 视频消息
71 | EMVideoMessageBody *videoMsgBody = (EMVideoMessageBody *)msgBody;
72 | self.messageLabel.text = @"【视频消息】";
73 | }
74 | break;
75 | case EMMessageBodyTypeLocation:
76 | {
77 | // 位置消息
78 | EMLocationMessageBody *locationMsgBody = (EMLocationMessageBody *)msgBody;
79 | self.messageLabel.text = @"【位置消息】";
80 | }
81 | break;
82 | case EMMessageBodyTypeFile:
83 | {
84 | // 文件消息
85 | EMFileMessageBody *fileMsgBody = (EMFileMessageBody *)msgBody;
86 | self.messageLabel.text = @"【文件消息】";
87 | }
88 | break;
89 |
90 | default:
91 | break;
92 | }
93 | }
94 |
95 | #pragma mark - 显示图片
96 | - (void)showImage:(EMImageMessageBody *)imageMsgBody {
97 | CGRect thumbFrame = (CGRect){0, 0, imageMsgBody.thumbnailSize};
98 | // 设置label的尺寸足够显示UIImageView
99 | // 图片附件
100 | NSTextAttachment *imageAttachment = [[NSTextAttachment alloc]init];
101 | imageAttachment.bounds = thumbFrame;
102 | NSAttributedString *attributedString = [NSAttributedString attributedStringWithAttachment:imageAttachment];
103 | self.messageLabel.attributedText = attributedString;
104 |
105 | // 1. 在cell的Label上添加UIImageView
106 | [self.messageLabel addSubview:self.chatImageView];
107 | self.chatImageView.frame = thumbFrame;
108 |
109 | // 下载图片
110 | NSLog(@"缩略图remote路径:%@", imageMsgBody.thumbnailRemotePath);
111 | NSLog(@"缩略图local路径:%@", imageMsgBody.thumbnailLocalPath);
112 |
113 | NSFileManager *manager = [NSFileManager defaultManager];
114 | // 如果本地图片存在,直接从本地显示图片
115 | if ([manager fileExistsAtPath:imageMsgBody.thumbnailLocalPath]) {
116 | [self.chatImageView sd_setImageWithURL:[NSURL fileURLWithPath:imageMsgBody.thumbnailLocalPath] placeholderImage:[UIImage imageNamed:@"default.png"]];
117 | } else {
118 | [self.chatImageView sd_setImageWithURL:[NSURL URLWithString:imageMsgBody.thumbnailRemotePath] placeholderImage:[UIImage imageNamed:@"default.png"]];
119 | }
120 | }
121 |
122 | - (CGFloat)cellHeight {
123 | // 刷新布局,重新布局子控件
124 | [self layoutIfNeeded];
125 | return 15 + self.messageLabel.bounds.size.height + 15;
126 | }
127 |
128 | - (UIImageView *)chatImageView {
129 | if (!_chatImageView) {
130 | _chatImageView = [[UIImageView alloc]init];
131 | _chatImageView.backgroundColor = [UIColor redColor];
132 | }
133 | return _chatImageView;
134 | }
135 |
136 | @end
137 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/View/BRTimeCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRTimeCell.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/8/1.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRTimeCell : UITableViewCell
12 | /** 时间label */
13 | @property (weak, nonatomic) IBOutlet UILabel *timeLabel;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/View/BRTimeCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRTimeCell.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/8/1.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRTimeCell.h"
10 |
11 | @implementation BRTimeCell
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Chat/ViewController/BRChatViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRChatViewController.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRChatViewController : UIViewController
12 | /** 好友 用户名 */
13 | @property (nonatomic, strong) NSString *contactUsername;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Conversation/ViewController/BRConversationController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRConversationController.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/21.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRConversationController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Login/ViewController/BRLoginViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRLoginViewController.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/20.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRLoginViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Login/ViewController/BRLoginViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRLoginViewController.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/20.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRLoginViewController.h"
10 |
11 | @interface BRLoginViewController ()
12 | @property (weak, nonatomic) IBOutlet UITextField *usernameTF;
13 | @property (weak, nonatomic) IBOutlet UITextField *pwdTF;
14 |
15 | @end
16 |
17 | @implementation BRLoginViewController
18 |
19 | - (void)viewDidLoad {
20 | [super viewDidLoad];
21 | // Do any additional setup after loading the view.
22 | }
23 |
24 | #pragma mark - 登录
25 | - (IBAction)clickLoginBtn:(id)sender {
26 | NSString *username = self.usernameTF.text;
27 | NSString *password = self.pwdTF.text;
28 | if (username.length == 0 || password.length == 0) {
29 | NSLog(@"请输入用户名或密码");
30 | return;
31 | }
32 |
33 | // // 判断是否设置了自动登录
34 | // BOOL isAutoLogin = [EMClient sharedClient].options.isAutoLogin;
35 | // if (!isAutoLogin) {
36 | //
37 | // }
38 |
39 | // 异步登录方法
40 | [[EMClient sharedClient] loginWithUsername:username password:password completion:^(NSString *aUsername, EMError *aError) {
41 | if (!aError) {
42 | NSLog(@"登录成功:%@", aUsername);
43 | NSLog(@"沙盒路径:%@", NSHomeDirectory());
44 | // 开启自动登录
45 | [[EMClient sharedClient].options setIsAutoLogin:YES];
46 | // 进入主界面(拿到 Main.storyboard 箭头所指的控制器,即 tabBarController)
47 | self.view.window.rootViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateInitialViewController];
48 | } else {
49 | NSLog(@"登录失败:%@", aError);
50 | }
51 | }];
52 | }
53 |
54 | #pragma mark - 注册
55 | - (IBAction)clickRegisterBtn:(id)sender {
56 | NSString *username = self.usernameTF.text;
57 | NSString *password = self.pwdTF.text;
58 | if (username.length == 0 || password.length == 0) {
59 | NSLog(@"请输入用户名或密码");
60 | return;
61 | }
62 | // 异步注册方法
63 | [[EMClient sharedClient] registerWithUsername:username password:password completion:^(NSString *aUsername, EMError *aError) {
64 | if (!aError) {
65 | NSLog(@"注册成功:%@", aUsername);
66 | } else {
67 | NSLog(@"注册失败:%@", aError);
68 | }
69 | }];
70 | }
71 |
72 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
73 | [self.view endEditing:YES];
74 | }
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Resource/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Classes/Resource/default.png
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Resource/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Classes/Resource/en.lproj/Localizable.strings
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Resource/in.caf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Classes/Resource/in.caf
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Resource/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Classes/Resource/zh-Hans.lproj/Localizable.strings
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Setting/ViewController/BRSettingController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRSettingController.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRSettingController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Setting/ViewController/BRSettingController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRSettingController.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRSettingController.h"
10 |
11 | @interface BRSettingController ()
12 | @property (weak, nonatomic) IBOutlet UIButton *logoutBtn;
13 |
14 | @end
15 |
16 | @implementation BRSettingController
17 |
18 | - (void)viewDidLoad {
19 | [super viewDidLoad];
20 | NSString *title = [NSString stringWithFormat:@"退出登录(%@)", [EMClient sharedClient].currentUsername];
21 | [self.logoutBtn setTitle:title forState:UIControlStateNormal];
22 | }
23 |
24 | #pragma mark - 退出登录
25 | - (IBAction)clickLogoutBtn:(id)sender {
26 | NSLog(@"退出登录");
27 | [[EMClient sharedClient] logout:YES completion:^(EMError *aError) {
28 | if (!aError) {
29 | NSLog(@"退出登录成功!");
30 | self.view.window.rootViewController = [[UIStoryboard storyboardWithName:@"Login" bundle:nil] instantiateInitialViewController];
31 | } else {
32 | NSLog(@"退出登录失败:%@", aError);
33 | }
34 | }];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Category/CALayer+LayerColor.h:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+LayerColor.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/26.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CALayer (LayerColor)
12 |
13 | - (void)setBorderColorFromUIColor:(UIColor *)color;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Category/CALayer+LayerColor.m:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+LayerColor.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/26.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "CALayer+LayerColor.h"
10 |
11 | @implementation CALayer (LayerColor)
12 |
13 | - (void)setBorderColorFromUIColor:(UIColor *)color {
14 | self.borderColor = color.CGColor;
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Category/NSDate+BRAdd.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+BRAdd.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/28.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSDate (BRAdd)
12 | /** 获取系统当前的时间戳,即当前时间距1970的秒数(以毫秒为单位) */
13 | + (NSString *)currentTimestamp;
14 |
15 |
16 | /** 获取当前的时间 */
17 | + (NSString *)currentDateString;
18 |
19 |
20 | /**
21 | * 按指定格式获取当前的时间
22 | *
23 | * @param formatterStr 设置格式:yyyy-MM-dd HH:mm:ss
24 | */
25 | + (NSString *)currentDateStringWithFormat:(NSString *)formatterStr;
26 |
27 | /**
28 | * 获取聊天消息的时间
29 | * 时间格式如下:
30 | * 今天:【HH:mm】
31 | * 昨天:【昨天 HH:mm】
32 | * 昨天之前:【yyyy-MM-dd HH:mm】
33 | */
34 | + (NSString *)chatTime:(long long)timestamp;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Category/NSDate+BRAdd.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+BRAdd.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/28.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "NSDate+BRAdd.h"
10 |
11 | @implementation NSDate (BRAdd)
12 | #pragma mark - 获取系统当前的时间戳,即当前时间距1970的秒数(以毫秒为单位)
13 | + (NSString *)currentTimestamp {
14 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
15 | /** 当前时间距1970的秒数。*1000 是精确到毫秒,不乘就是精确到秒 */
16 | NSTimeInterval interval = [date timeIntervalSince1970] * 1000;
17 | NSString *timeString = [NSString stringWithFormat:@"%0.f", interval];
18 |
19 | return timeString;
20 | }
21 |
22 | #pragma mark - 获取当前的时间
23 | + (NSString *)currentDateString {
24 | return [self currentDateStringWithFormat:@"yyyy-MM-dd HH:mm:ss"];
25 | }
26 |
27 | #pragma mark - 按指定格式获取当前的时间
28 | + (NSString *)currentDateStringWithFormat:(NSString *)formatterStr {
29 | // 获取系统当前时间
30 | NSDate *currentDate = [NSDate date];
31 | // 用于格式化NSDate对象
32 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
33 | // 设置格式:yyyy-MM-dd HH:mm:ss
34 | formatter.dateFormat = formatterStr;
35 | // 将 NSDate 按 formatter格式 转成 NSString
36 | NSString *currentDateStr = [formatter stringFromDate:currentDate];
37 | // 输出currentDateStr
38 | return currentDateStr;
39 | }
40 |
41 | #pragma mark - 获取聊天消息时间
42 | + (NSString *)chatTime:(long long)timestamp {
43 | NSCalendar *calendar = [NSCalendar currentCalendar];
44 | // 1.获取当前时间的年、月、日
45 | NSDate *currentData = [NSDate date];
46 | NSDateComponents *currentComponents = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:currentData];
47 | NSInteger currentYear = currentComponents.year;
48 | NSInteger currentMonth = currentComponents.month;
49 | NSInteger currentDay = currentComponents.day;
50 |
51 | // 2.获取消息发送时间的年、月、日
52 | NSDate *msgData = [NSDate dateWithTimeIntervalSince1970:timestamp / 1000.0];
53 | NSDateComponents *msgComponents = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:msgData];
54 | NSInteger msgYear = msgComponents.year;
55 | NSInteger msgMonth = msgComponents.month;
56 | NSInteger msgDay = msgComponents.day;
57 | // 格式化
58 | NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
59 | if (currentYear == msgYear && currentMonth == msgMonth && currentDay == msgDay) { //今天
60 | formatter.dateFormat = @" HH:mm ";
61 | } else if (currentYear == msgYear && currentMonth == msgMonth && (currentDay - 1) == msgDay) { //昨天
62 | formatter.dateFormat = @" 昨天 HH:mm ";
63 | } else { //昨天以前
64 | formatter.dateFormat = @" yyyy年M月dd日 HH:mm ";
65 | }
66 |
67 | return [formatter stringFromDate:msgData];
68 | }
69 |
70 | @end
71 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Category/UIViewController+Alert.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Alert.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIViewController (Alert)
12 | /** 提示弹窗 */
13 | - (void)showAlertWithTitle:(NSString *)title buttonTitle:(NSArray *)titleArr sureHandler:(void (^)())sureHandler cancelHandler:(void (^)())cancelHandler;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Category/UIViewController+Alert.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Alert.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/25.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+Alert.h"
10 |
11 | @implementation UIViewController (Alert)
12 | #pragma mark - 提示弹窗
13 | - (void)showAlertWithTitle:(NSString *)title buttonTitle:(NSArray *)titleArr sureHandler:(void (^)())sureHandler cancelHandler:(void (^)())cancelHandler {
14 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
15 | UIAlertAction *sureAction = [UIAlertAction actionWithTitle:titleArr[0] style:UIAlertActionStyleDefault handler:sureHandler];
16 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:titleArr[1] style:UIAlertActionStyleDefault handler:cancelHandler];
17 | [alertController addAction:sureAction];
18 | [alertController addAction:cancelAction];
19 |
20 | [self presentViewController:alertController animated:YES completion:nil];
21 | }
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Tools/BRVoicePlayTool.h:
--------------------------------------------------------------------------------
1 | //
2 | // BRVoicePlayTool.h
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/28.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BRVoicePlayTool : NSObject
12 | /** 播放语音 */
13 | + (void)playWithMessage:(EMMessage *)message msgLabel:(UILabel *)msgLabel;
14 |
15 | /** 停止播放语音 */
16 | + (void)stopPlaying;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Utils/Tools/BRVoicePlayTool.m:
--------------------------------------------------------------------------------
1 | //
2 | // BRVoicePlayTool.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/28.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import "BRVoicePlayTool.h"
10 | #import "EMCDDeviceManager.h"
11 | #import "BRAttributedText.h"
12 |
13 | /** 正在执行动画的ImageView */
14 | static UIImageView *animatingImageView;
15 |
16 | @implementation BRVoicePlayTool
17 |
18 | #pragma mark - 播放语音
19 | + (void)playWithMessage:(EMMessage *)message msgLabel:(UILabel *)msgLabel {
20 | // 进入这个方法前,先把以前的播放动画移除
21 | // 移除ImageView动画
22 | [animatingImageView stopAnimating];
23 | [animatingImageView removeFromSuperview];
24 |
25 | msgLabel.attributedText = [BRAttributedText voiceAttrText:message isPlaying:YES];
26 |
27 | // 1.播放语音
28 | EMVoiceMessageBody *voiceBody = (EMVoiceMessageBody *)message.body;
29 | // 1.1 本地语音文件路径
30 | NSString *voicePath = voiceBody.localPath;
31 | // 1.2 如果本地语音文件不存在,就使用服务的语音
32 | NSFileManager *manager = [NSFileManager defaultManager];
33 | if (![manager fileExistsAtPath:voicePath]) {
34 | voicePath = voiceBody.remotePath;
35 | }
36 | [[EMCDDeviceManager sharedInstance] asyncPlayingWithPath:voicePath completion:^(NSError *error) {
37 | if (!error) {
38 | NSLog(@"语音播放完成!");
39 | // 移除ImageView动画
40 | [animatingImageView stopAnimating];
41 | [animatingImageView removeFromSuperview];
42 |
43 | msgLabel.attributedText = [BRAttributedText voiceAttrText:message isPlaying:NO];
44 | } else {
45 | NSLog(@"语音播放失败:%@", error);
46 | }
47 | }];
48 |
49 | // 2.添加播放动画
50 | // 2.1 创建一个imageView添加到label上
51 | UIImageView *imageView = [[UIImageView alloc]init];
52 | [msgLabel addSubview:imageView];
53 | // 2.2 给imageView添加动画图片
54 | if (message.direction == EMMessageDirectionReceive) { // 接收方(对方、左边的消息)
55 | imageView.frame = CGRectMake(0, 0, 20, 20);
56 | imageView.animationImages = @[[UIImage imageNamed:@"chat_receiver_audio_playing000"],
57 | [UIImage imageNamed:@"chat_receiver_audio_playing001"],
58 | [UIImage imageNamed:@"chat_receiver_audio_playing002"],
59 | [UIImage imageNamed:@"chat_receiver_audio_playing003"]];
60 | } else { // 发送方(自己、右边的消息)
61 | imageView.frame = CGRectMake(msgLabel.bounds.size.width - 20, 0, 20, 20);
62 | imageView.animationImages = @[[UIImage imageNamed:@"chat_sender_audio_playing_000"],
63 | [UIImage imageNamed:@"chat_sender_audio_playing_001"],
64 | [UIImage imageNamed:@"chat_sender_audio_playing_002"],
65 | [UIImage imageNamed:@"chat_sender_audio_playing_003"]];
66 | }
67 | // 动画时间
68 | imageView.animationDuration = 1.5;
69 | // 执行动画
70 | [imageView startAnimating];
71 | animatingImageView = imageView;
72 |
73 | }
74 |
75 | #pragma mark - 停止播放语音
76 | + (void)stopPlaying {
77 | // 停止播放语音
78 | [[EMCDDeviceManager sharedInstance] stopPlaying];
79 | // 移除ImageView动画
80 | [animatingImageView stopAnimating];
81 | [animatingImageView removeFromSuperview];
82 | }
83 |
84 |
85 | @end
86 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/MKAnnotationView+WebCache.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 |
11 | #if SD_UIKIT || SD_MAC
12 |
13 | #import
14 | #import "SDWebImageManager.h"
15 |
16 | /**
17 | * Integrates SDWebImage async downloading and caching of remote images with MKAnnotationView.
18 | */
19 | @interface MKAnnotationView (WebCache)
20 |
21 | /**
22 | * Set the imageView `image` with an `url`.
23 | *
24 | * The download is asynchronous and cached.
25 | *
26 | * @param url The url for the image.
27 | */
28 | - (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
29 |
30 | /**
31 | * Set the imageView `image` with an `url` and a placeholder.
32 | *
33 | * The download is asynchronous and cached.
34 | *
35 | * @param url The url for the image.
36 | * @param placeholder The image to be set initially, until the image request finishes.
37 | * @see sd_setImageWithURL:placeholderImage:options:
38 | */
39 | - (void)sd_setImageWithURL:(nullable NSURL *)url
40 | placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT;
41 |
42 | /**
43 | * Set the imageView `image` with an `url`, placeholder and custom options.
44 | *
45 | * The download is asynchronous and cached.
46 | *
47 | * @param url The url for the image.
48 | * @param placeholder The image to be set initially, until the image request finishes.
49 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
50 | */
51 |
52 | - (void)sd_setImageWithURL:(nullable NSURL *)url
53 | placeholderImage:(nullable UIImage *)placeholder
54 | options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
55 |
56 | /**
57 | * Set the imageView `image` with an `url`.
58 | *
59 | * The download is asynchronous and cached.
60 | *
61 | * @param url The url for the image.
62 | * @param completedBlock A block called when operation has been completed. This block has no return value
63 | * and takes the requested UIImage as first parameter. In case of error the image parameter
64 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
65 | * indicating if the image was retrieved from the local cache or from the network.
66 | * The fourth parameter is the original image url.
67 | */
68 | - (void)sd_setImageWithURL:(nullable NSURL *)url
69 | completed:(nullable SDExternalCompletionBlock)completedBlock;
70 |
71 | /**
72 | * Set the imageView `image` with an `url`, placeholder.
73 | *
74 | * The download is asynchronous and cached.
75 | *
76 | * @param url The url for the image.
77 | * @param placeholder The image to be set initially, until the image request finishes.
78 | * @param completedBlock A block called when operation has been completed. This block has no return value
79 | * and takes the requested UIImage as first parameter. In case of error the image parameter
80 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
81 | * indicating if the image was retrieved from the local cache or from the network.
82 | * The fourth parameter is the original image url.
83 | */
84 | - (void)sd_setImageWithURL:(nullable NSURL *)url
85 | placeholderImage:(nullable UIImage *)placeholder
86 | completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
87 |
88 | /**
89 | * Set the imageView `image` with an `url`, placeholder and custom options.
90 | *
91 | * The download is asynchronous and cached.
92 | *
93 | * @param url The url for the image.
94 | * @param placeholder The image to be set initially, until the image request finishes.
95 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
96 | * @param completedBlock A block called when operation has been completed. This block has no return value
97 | * and takes the requested UIImage as first parameter. In case of error the image parameter
98 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
99 | * indicating if the image was retrieved from the local cache or from the network.
100 | * The fourth parameter is the original image url.
101 | */
102 | - (void)sd_setImageWithURL:(nullable NSURL *)url
103 | placeholderImage:(nullable UIImage *)placeholder
104 | options:(SDWebImageOptions)options
105 | completed:(nullable SDExternalCompletionBlock)completedBlock;
106 |
107 | @end
108 |
109 | #endif
110 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/MKAnnotationView+WebCache.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "MKAnnotationView+WebCache.h"
10 |
11 | #if SD_UIKIT || SD_MAC
12 |
13 | #import "objc/runtime.h"
14 | #import "UIView+WebCacheOperation.h"
15 | #import "UIView+WebCache.h"
16 |
17 | @implementation MKAnnotationView (WebCache)
18 |
19 | - (void)sd_setImageWithURL:(nullable NSURL *)url {
20 | [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:nil];
21 | }
22 |
23 | - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder {
24 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:nil];
25 | }
26 |
27 | - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options {
28 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:nil];
29 | }
30 |
31 | - (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
32 | [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock];
33 | }
34 |
35 | - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock {
36 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock];
37 | }
38 |
39 | - (void)sd_setImageWithURL:(nullable NSURL *)url
40 | placeholderImage:(nullable UIImage *)placeholder
41 | options:(SDWebImageOptions)options
42 | completed:(nullable SDExternalCompletionBlock)completedBlock {
43 | __weak typeof(self)weakSelf = self;
44 | [self sd_internalSetImageWithURL:url
45 | placeholderImage:placeholder
46 | options:options
47 | operationKey:nil
48 | setImageBlock:^(UIImage *image, NSData *imageData) {
49 | weakSelf.image = image;
50 | }
51 | progress:nil
52 | completed:completedBlock];
53 | }
54 |
55 | @end
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/NSData+ImageContentType.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | * (c) Fabrice Aneche
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | #import
11 | #import "SDWebImageCompat.h"
12 |
13 | typedef NS_ENUM(NSInteger, SDImageFormat) {
14 | SDImageFormatUndefined = -1,
15 | SDImageFormatJPEG = 0,
16 | SDImageFormatPNG,
17 | SDImageFormatGIF,
18 | SDImageFormatTIFF,
19 | SDImageFormatWebP
20 | };
21 |
22 | @interface NSData (ImageContentType)
23 |
24 | /**
25 | * Return image format
26 | *
27 | * @param data the input image data
28 | *
29 | * @return the image format as `SDImageFormat` (enum)
30 | */
31 | + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/NSData+ImageContentType.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | * (c) Fabrice Aneche
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | #import "NSData+ImageContentType.h"
11 |
12 |
13 | @implementation NSData (ImageContentType)
14 |
15 | + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
16 | if (!data) {
17 | return SDImageFormatUndefined;
18 | }
19 |
20 | uint8_t c;
21 | [data getBytes:&c length:1];
22 | switch (c) {
23 | case 0xFF:
24 | return SDImageFormatJPEG;
25 | case 0x89:
26 | return SDImageFormatPNG;
27 | case 0x47:
28 | return SDImageFormatGIF;
29 | case 0x49:
30 | case 0x4D:
31 | return SDImageFormatTIFF;
32 | case 0x52:
33 | // R as RIFF for WEBP
34 | if (data.length < 12) {
35 | return SDImageFormatUndefined;
36 | }
37 |
38 | NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
39 | if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
40 | return SDImageFormatWebP;
41 | }
42 | }
43 | return SDImageFormatUndefined;
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/NSImage+WebCache.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 |
11 | #if SD_MAC
12 |
13 | #import
14 |
15 | @interface NSImage (WebCache)
16 |
17 | - (CGImageRef)CGImage;
18 | - (NSArray *)images;
19 | - (BOOL)isGIF;
20 |
21 | @end
22 |
23 | #endif
24 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/NSImage+WebCache.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "NSImage+WebCache.h"
10 |
11 | #if SD_MAC
12 |
13 | @implementation NSImage (WebCache)
14 |
15 | - (CGImageRef)CGImage {
16 | NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height);
17 | CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil];
18 | return cgImage;
19 | }
20 |
21 | - (NSArray *)images {
22 | return nil;
23 | }
24 |
25 | - (BOOL)isGIF {
26 | return NO;
27 | }
28 |
29 | @end
30 |
31 | #endif
32 |
33 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDImageCacheConfig.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import
10 | #import "SDWebImageCompat.h"
11 |
12 | @interface SDImageCacheConfig : NSObject
13 |
14 | /**
15 | * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory.
16 | * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
17 | */
18 | @property (assign, nonatomic) BOOL shouldDecompressImages;
19 |
20 | /**
21 | * disable iCloud backup [defaults to YES]
22 | */
23 | @property (assign, nonatomic) BOOL shouldDisableiCloud;
24 |
25 | /**
26 | * use memory cache [defaults to YES]
27 | */
28 | @property (assign, nonatomic) BOOL shouldCacheImagesInMemory;
29 |
30 | /**
31 | * The maximum length of time to keep an image in the cache, in seconds
32 | */
33 | @property (assign, nonatomic) NSInteger maxCacheAge;
34 |
35 | /**
36 | * The maximum size of the cache, in bytes.
37 | */
38 | @property (assign, nonatomic) NSUInteger maxCacheSize;
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDImageCacheConfig.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDImageCacheConfig.h"
10 |
11 | static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week
12 |
13 | @implementation SDImageCacheConfig
14 |
15 | - (instancetype)init {
16 | if (self = [super init]) {
17 | _shouldDecompressImages = YES;
18 | _shouldDisableiCloud = YES;
19 | _shouldCacheImagesInMemory = YES;
20 | _maxCacheAge = kDefaultCacheMaxCacheAge;
21 | _maxCacheSize = 0;
22 | }
23 | return self;
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImageCompat.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | * (c) Jamie Pinkham
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | #import
11 |
12 | #ifdef __OBJC_GC__
13 | #error SDWebImage does not support Objective-C Garbage Collection
14 | #endif
15 |
16 | // Apple's defines from TargetConditionals.h are a bit weird.
17 | // Seems like TARGET_OS_MAC is always defined (on all platforms).
18 | // To determine if we are running on OSX, we can only rely on TARGET_OS_IPHONE=0 and all the other platforms
19 | #if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH
20 | #define SD_MAC 1
21 | #else
22 | #define SD_MAC 0
23 | #endif
24 |
25 | // iOS and tvOS are very similar, UIKit exists on both platforms
26 | // Note: watchOS also has UIKit, but it's very limited
27 | #if TARGET_OS_IOS || TARGET_OS_TV
28 | #define SD_UIKIT 1
29 | #else
30 | #define SD_UIKIT 0
31 | #endif
32 |
33 | #if TARGET_OS_IOS
34 | #define SD_IOS 1
35 | #else
36 | #define SD_IOS 0
37 | #endif
38 |
39 | #if TARGET_OS_TV
40 | #define SD_TV 1
41 | #else
42 | #define SD_TV 0
43 | #endif
44 |
45 | #if TARGET_OS_WATCH
46 | #define SD_WATCH 1
47 | #else
48 | #define SD_WATCH 0
49 | #endif
50 |
51 |
52 | #if SD_MAC
53 | #import
54 | #ifndef UIImage
55 | #define UIImage NSImage
56 | #endif
57 | #ifndef UIImageView
58 | #define UIImageView NSImageView
59 | #endif
60 | #ifndef UIView
61 | #define UIView NSView
62 | #endif
63 | #else
64 | #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
65 | #error SDWebImage doesn't support Deployment Target version < 5.0
66 | #endif
67 |
68 | #if SD_UIKIT
69 | #import
70 | #endif
71 | #if SD_WATCH
72 | #import
73 | #endif
74 | #endif
75 |
76 | #ifndef NS_ENUM
77 | #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
78 | #endif
79 |
80 | #ifndef NS_OPTIONS
81 | #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
82 | #endif
83 |
84 | #if OS_OBJECT_USE_OBJC
85 | #undef SDDispatchQueueRelease
86 | #undef SDDispatchQueueSetterSementics
87 | #define SDDispatchQueueRelease(q)
88 | #define SDDispatchQueueSetterSementics strong
89 | #else
90 | #undef SDDispatchQueueRelease
91 | #undef SDDispatchQueueSetterSementics
92 | #define SDDispatchQueueRelease(q) (dispatch_release(q))
93 | #define SDDispatchQueueSetterSementics assign
94 | #endif
95 |
96 | extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image);
97 |
98 | typedef void(^SDWebImageNoParamsBlock)();
99 |
100 | extern NSString *const SDWebImageErrorDomain;
101 |
102 | #ifndef dispatch_main_async_safe
103 | #define dispatch_main_async_safe(block)\
104 | if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
105 | block();\
106 | } else {\
107 | dispatch_async(dispatch_get_main_queue(), block);\
108 | }
109 | #endif
110 |
111 | static int64_t kAsyncTestTimeout = 5;
112 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImageCompat.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 |
11 | #import "objc/runtime.h"
12 |
13 | #if !__has_feature(objc_arc)
14 | #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
15 | #endif
16 |
17 | inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
18 | if (!image) {
19 | return nil;
20 | }
21 |
22 | #if SD_MAC
23 | return image;
24 | #elif SD_UIKIT || SD_WATCH
25 | if ((image.images).count > 0) {
26 | NSMutableArray *scaledImages = [NSMutableArray array];
27 |
28 | for (UIImage *tempImage in image.images) {
29 | [scaledImages addObject:SDScaledImageForKey(key, tempImage)];
30 | }
31 |
32 | UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration];
33 | #ifdef SD_WEBP
34 | if (animatedImage) {
35 | SEL sd_webpLoopCount = NSSelectorFromString(@"sd_webpLoopCount");
36 | NSNumber *value = objc_getAssociatedObject(image, sd_webpLoopCount);
37 | NSInteger loopCount = value.integerValue;
38 | if (loopCount) {
39 | objc_setAssociatedObject(animatedImage, sd_webpLoopCount, @(loopCount), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
40 | }
41 | }
42 | #endif
43 | return animatedImage;
44 | } else {
45 | #if SD_WATCH
46 | if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
47 | #elif SD_UIKIT
48 | if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
49 | #endif
50 | CGFloat scale = 1;
51 | if (key.length >= 8) {
52 | NSRange range = [key rangeOfString:@"@2x."];
53 | if (range.location != NSNotFound) {
54 | scale = 2.0;
55 | }
56 |
57 | range = [key rangeOfString:@"@3x."];
58 | if (range.location != NSNotFound) {
59 | scale = 3.0;
60 | }
61 | }
62 |
63 | UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
64 | image = scaledImage;
65 | }
66 | return image;
67 | }
68 | #endif
69 | }
70 |
71 | NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain";
72 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImageDecoder.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | * (c) james
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | #import
11 | #import "SDWebImageCompat.h"
12 |
13 | @interface UIImage (ForceDecode)
14 |
15 | + (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image;
16 |
17 | + (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImageDownloaderOperation.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import
10 | #import "SDWebImageDownloader.h"
11 | #import "SDWebImageOperation.h"
12 |
13 | extern NSString * _Nonnull const SDWebImageDownloadStartNotification;
14 | extern NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification;
15 | extern NSString * _Nonnull const SDWebImageDownloadStopNotification;
16 | extern NSString * _Nonnull const SDWebImageDownloadFinishNotification;
17 |
18 |
19 |
20 | /**
21 | Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol
22 | */
23 | @protocol SDWebImageDownloaderOperationInterface
24 |
25 | - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
26 | inSession:(nullable NSURLSession *)session
27 | options:(SDWebImageDownloaderOptions)options;
28 |
29 | - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
30 | completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
31 |
32 | - (BOOL)shouldDecompressImages;
33 | - (void)setShouldDecompressImages:(BOOL)value;
34 |
35 | - (nullable NSURLCredential *)credential;
36 | - (void)setCredential:(nullable NSURLCredential *)value;
37 |
38 | @end
39 |
40 |
41 | @interface SDWebImageDownloaderOperation : NSOperation
42 |
43 | /**
44 | * The request used by the operation's task.
45 | */
46 | @property (strong, nonatomic, readonly, nullable) NSURLRequest *request;
47 |
48 | /**
49 | * The operation's task
50 | */
51 | @property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask;
52 |
53 |
54 | @property (assign, nonatomic) BOOL shouldDecompressImages;
55 |
56 | /**
57 | * Was used to determine whether the URL connection should consult the credential storage for authenticating the connection.
58 | * @deprecated Not used for a couple of versions
59 | */
60 | @property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility");
61 |
62 | /**
63 | * The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`.
64 | *
65 | * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present.
66 | */
67 | @property (nonatomic, strong, nullable) NSURLCredential *credential;
68 |
69 | /**
70 | * The SDWebImageDownloaderOptions for the receiver.
71 | */
72 | @property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options;
73 |
74 | /**
75 | * The expected size of data.
76 | */
77 | @property (assign, nonatomic) NSInteger expectedSize;
78 |
79 | /**
80 | * The response returned by the operation's connection.
81 | */
82 | @property (strong, nonatomic, nullable) NSURLResponse *response;
83 |
84 | /**
85 | * Initializes a `SDWebImageDownloaderOperation` object
86 | *
87 | * @see SDWebImageDownloaderOperation
88 | *
89 | * @param request the URL request
90 | * @param session the URL session in which this operation will run
91 | * @param options downloader options
92 | *
93 | * @return the initialized instance
94 | */
95 | - (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request
96 | inSession:(nullable NSURLSession *)session
97 | options:(SDWebImageDownloaderOptions)options NS_DESIGNATED_INITIALIZER;
98 |
99 | /**
100 | * Adds handlers for progress and completion. Returns a tokent that can be passed to -cancel: to cancel this set of
101 | * callbacks.
102 | *
103 | * @param progressBlock the block executed when a new chunk of data arrives.
104 | * @note the progress block is executed on a background queue
105 | * @param completedBlock the block executed when the download is done.
106 | * @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue
107 | *
108 | * @return the token to use to cancel this set of handlers
109 | */
110 | - (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
111 | completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock;
112 |
113 | /**
114 | * Cancels a set of callbacks. Once all callbacks are canceled, the operation is cancelled.
115 | *
116 | * @param token the token representing a set of callbacks to cancel
117 | *
118 | * @return YES if the operation was stopped because this was the last token to be canceled. NO otherwise.
119 | */
120 | - (BOOL)cancel:(nullable id)token;
121 |
122 | @end
123 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImageOperation.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import
10 |
11 | @protocol SDWebImageOperation
12 |
13 | - (void)cancel;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImagePrefetcher.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import
10 | #import "SDWebImageManager.h"
11 |
12 | @class SDWebImagePrefetcher;
13 |
14 | @protocol SDWebImagePrefetcherDelegate
15 |
16 | @optional
17 |
18 | /**
19 | * Called when an image was prefetched.
20 | *
21 | * @param imagePrefetcher The current image prefetcher
22 | * @param imageURL The image url that was prefetched
23 | * @param finishedCount The total number of images that were prefetched (successful or not)
24 | * @param totalCount The total number of images that were to be prefetched
25 | */
26 | - (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(nullable NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount;
27 |
28 | /**
29 | * Called when all images are prefetched.
30 | * @param imagePrefetcher The current image prefetcher
31 | * @param totalCount The total number of images that were prefetched (whether successful or not)
32 | * @param skippedCount The total number of images that were skipped
33 | */
34 | - (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount;
35 |
36 | @end
37 |
38 | typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls);
39 | typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls);
40 |
41 | /**
42 | * Prefetch some URLs in the cache for future use. Images are downloaded in low priority.
43 | */
44 | @interface SDWebImagePrefetcher : NSObject
45 |
46 | /**
47 | * The web image manager
48 | */
49 | @property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager;
50 |
51 | /**
52 | * Maximum number of URLs to prefetch at the same time. Defaults to 3.
53 | */
54 | @property (nonatomic, assign) NSUInteger maxConcurrentDownloads;
55 |
56 | /**
57 | * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority.
58 | */
59 | @property (nonatomic, assign) SDWebImageOptions options;
60 |
61 | /**
62 | * Queue options for Prefetcher. Defaults to Main Queue.
63 | */
64 | @property (SDDispatchQueueSetterSementics, nonatomic, nonnull) dispatch_queue_t prefetcherQueue;
65 |
66 | @property (weak, nonatomic, nullable) id delegate;
67 |
68 | /**
69 | * Return the global image prefetcher instance.
70 | */
71 | + (nonnull instancetype)sharedImagePrefetcher;
72 |
73 | /**
74 | * Allows you to instantiate a prefetcher with any arbitrary image manager.
75 | */
76 | - (nonnull instancetype)initWithImageManager:(nonnull SDWebImageManager *)manager NS_DESIGNATED_INITIALIZER;
77 |
78 | /**
79 | * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching,
80 | * currently one image is downloaded at a time,
81 | * and skips images for failed downloads and proceed to the next image in the list.
82 | * Any previously-running prefetch operations are canceled.
83 | *
84 | * @param urls list of URLs to prefetch
85 | */
86 | - (void)prefetchURLs:(nullable NSArray *)urls;
87 |
88 | /**
89 | * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching,
90 | * currently one image is downloaded at a time,
91 | * and skips images for failed downloads and proceed to the next image in the list.
92 | * Any previously-running prefetch operations are canceled.
93 | *
94 | * @param urls list of URLs to prefetch
95 | * @param progressBlock block to be called when progress updates;
96 | * first parameter is the number of completed (successful or not) requests,
97 | * second parameter is the total number of images originally requested to be prefetched
98 | * @param completionBlock block to be called when prefetching is completed
99 | * first param is the number of completed (successful or not) requests,
100 | * second parameter is the number of skipped requests
101 | */
102 | - (void)prefetchURLs:(nullable NSArray *)urls
103 | progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock
104 | completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock;
105 |
106 | /**
107 | * Remove and cancel queued list
108 | */
109 | - (void)cancelPrefetching;
110 |
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/SDWebImagePrefetcher.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImagePrefetcher.h"
10 |
11 | @interface SDWebImagePrefetcher ()
12 |
13 | @property (strong, nonatomic, nonnull) SDWebImageManager *manager;
14 | @property (strong, nonatomic, nullable) NSArray *prefetchURLs;
15 | @property (assign, nonatomic) NSUInteger requestedCount;
16 | @property (assign, nonatomic) NSUInteger skippedCount;
17 | @property (assign, nonatomic) NSUInteger finishedCount;
18 | @property (assign, nonatomic) NSTimeInterval startedTime;
19 | @property (copy, nonatomic, nullable) SDWebImagePrefetcherCompletionBlock completionBlock;
20 | @property (copy, nonatomic, nullable) SDWebImagePrefetcherProgressBlock progressBlock;
21 |
22 | @end
23 |
24 | @implementation SDWebImagePrefetcher
25 |
26 | + (nonnull instancetype)sharedImagePrefetcher {
27 | static dispatch_once_t once;
28 | static id instance;
29 | dispatch_once(&once, ^{
30 | instance = [self new];
31 | });
32 | return instance;
33 | }
34 |
35 | - (nonnull instancetype)init {
36 | return [self initWithImageManager:[SDWebImageManager new]];
37 | }
38 |
39 | - (nonnull instancetype)initWithImageManager:(SDWebImageManager *)manager {
40 | if ((self = [super init])) {
41 | _manager = manager;
42 | _options = SDWebImageLowPriority;
43 | _prefetcherQueue = dispatch_get_main_queue();
44 | self.maxConcurrentDownloads = 3;
45 | }
46 | return self;
47 | }
48 |
49 | - (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads {
50 | self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads;
51 | }
52 |
53 | - (NSUInteger)maxConcurrentDownloads {
54 | return self.manager.imageDownloader.maxConcurrentDownloads;
55 | }
56 |
57 | - (void)startPrefetchingAtIndex:(NSUInteger)index {
58 | if (index >= self.prefetchURLs.count) return;
59 | self.requestedCount++;
60 | [self.manager loadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
61 | if (!finished) return;
62 | self.finishedCount++;
63 |
64 | if (image) {
65 | if (self.progressBlock) {
66 | self.progressBlock(self.finishedCount,(self.prefetchURLs).count);
67 | }
68 | }
69 | else {
70 | if (self.progressBlock) {
71 | self.progressBlock(self.finishedCount,(self.prefetchURLs).count);
72 | }
73 | // Add last failed
74 | self.skippedCount++;
75 | }
76 | if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) {
77 | [self.delegate imagePrefetcher:self
78 | didPrefetchURL:self.prefetchURLs[index]
79 | finishedCount:self.finishedCount
80 | totalCount:self.prefetchURLs.count
81 | ];
82 | }
83 | if (self.prefetchURLs.count > self.requestedCount) {
84 | dispatch_async(self.prefetcherQueue, ^{
85 | [self startPrefetchingAtIndex:self.requestedCount];
86 | });
87 | } else if (self.finishedCount == self.requestedCount) {
88 | [self reportStatus];
89 | if (self.completionBlock) {
90 | self.completionBlock(self.finishedCount, self.skippedCount);
91 | self.completionBlock = nil;
92 | }
93 | self.progressBlock = nil;
94 | }
95 | }];
96 | }
97 |
98 | - (void)reportStatus {
99 | NSUInteger total = (self.prefetchURLs).count;
100 | if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) {
101 | [self.delegate imagePrefetcher:self
102 | didFinishWithTotalCount:(total - self.skippedCount)
103 | skippedCount:self.skippedCount
104 | ];
105 | }
106 | }
107 |
108 | - (void)prefetchURLs:(nullable NSArray *)urls {
109 | [self prefetchURLs:urls progress:nil completed:nil];
110 | }
111 |
112 | - (void)prefetchURLs:(nullable NSArray *)urls
113 | progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock
114 | completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock {
115 | [self cancelPrefetching]; // Prevent duplicate prefetch request
116 | self.startedTime = CFAbsoluteTimeGetCurrent();
117 | self.prefetchURLs = urls;
118 | self.completionBlock = completionBlock;
119 | self.progressBlock = progressBlock;
120 |
121 | if (urls.count == 0) {
122 | if (completionBlock) {
123 | completionBlock(0,0);
124 | }
125 | } else {
126 | // Starts prefetching from the very first image on the list with the max allowed concurrency
127 | NSUInteger listCount = self.prefetchURLs.count;
128 | for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) {
129 | [self startPrefetchingAtIndex:i];
130 | }
131 | }
132 | }
133 |
134 | - (void)cancelPrefetching {
135 | self.prefetchURLs = nil;
136 | self.skippedCount = 0;
137 | self.requestedCount = 0;
138 | self.finishedCount = 0;
139 | [self.manager cancelAll];
140 | }
141 |
142 | @end
143 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImage+GIF.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | * (c) Laurin Brandner
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | #import "SDWebImageCompat.h"
11 |
12 | @interface UIImage (GIF)
13 |
14 | /**
15 | * Compatibility method - creates an animated UIImage from an NSData, it will only contain the 1st frame image
16 | */
17 | + (UIImage *)sd_animatedGIFWithData:(NSData *)data;
18 |
19 | /**
20 | * Checks if an UIImage instance is a GIF. Will use the `images` array
21 | */
22 | - (BOOL)isGIF;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImage+GIF.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | * (c) Laurin Brandner
5 | *
6 | * For the full copyright and license information, please view the LICENSE
7 | * file that was distributed with this source code.
8 | */
9 |
10 | #import "UIImage+GIF.h"
11 | #import
12 | #import "objc/runtime.h"
13 | #import "NSImage+WebCache.h"
14 |
15 | @implementation UIImage (GIF)
16 |
17 | + (UIImage *)sd_animatedGIFWithData:(NSData *)data {
18 | if (!data) {
19 | return nil;
20 | }
21 |
22 | #if SD_MAC
23 | return [[UIImage alloc] initWithData:data];
24 | #endif
25 |
26 | CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
27 |
28 | size_t count = CGImageSourceGetCount(source);
29 |
30 | UIImage *staticImage;
31 |
32 | if (count <= 1) {
33 | staticImage = [[UIImage alloc] initWithData:data];
34 | } else {
35 | // we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category.
36 | // this here is only code to allow drawing animated images as static ones
37 | #if SD_WATCH
38 | CGFloat scale = 1;
39 | scale = [WKInterfaceDevice currentDevice].screenScale;
40 | #elif SD_UIKIT
41 | CGFloat scale = 1;
42 | scale = [UIScreen mainScreen].scale;
43 | #endif
44 |
45 | CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
46 | #if SD_UIKIT || SD_WATCH
47 | UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp];
48 | staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f];
49 | #endif
50 | CGImageRelease(CGImage);
51 | }
52 |
53 | CFRelease(source);
54 |
55 | return staticImage;
56 | }
57 |
58 | - (BOOL)isGIF {
59 | return (self.images != nil);
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImage+MultiFormat.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 | #import "NSData+ImageContentType.h"
11 |
12 | @interface UIImage (MultiFormat)
13 |
14 | + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data;
15 | - (nullable NSData *)sd_imageData;
16 | - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImage+MultiFormat.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "UIImage+MultiFormat.h"
10 | #import "UIImage+GIF.h"
11 | #import "NSData+ImageContentType.h"
12 | #import
13 |
14 | #ifdef SD_WEBP
15 | #import "UIImage+WebP.h"
16 | #endif
17 |
18 | @implementation UIImage (MultiFormat)
19 |
20 | + (nullable UIImage *)sd_imageWithData:(nullable NSData *)data {
21 | if (!data) {
22 | return nil;
23 | }
24 |
25 | UIImage *image;
26 | SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data];
27 | if (imageFormat == SDImageFormatGIF) {
28 | image = [UIImage sd_animatedGIFWithData:data];
29 | }
30 | #ifdef SD_WEBP
31 | else if (imageFormat == SDImageFormatWebP)
32 | {
33 | image = [UIImage sd_imageWithWebPData:data];
34 | }
35 | #endif
36 | else {
37 | image = [[UIImage alloc] initWithData:data];
38 | #if SD_UIKIT || SD_WATCH
39 | UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data];
40 | if (orientation != UIImageOrientationUp) {
41 | image = [UIImage imageWithCGImage:image.CGImage
42 | scale:image.scale
43 | orientation:orientation];
44 | }
45 | #endif
46 | }
47 |
48 |
49 | return image;
50 | }
51 |
52 | #if SD_UIKIT || SD_WATCH
53 | +(UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData {
54 | UIImageOrientation result = UIImageOrientationUp;
55 | CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
56 | if (imageSource) {
57 | CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
58 | if (properties) {
59 | CFTypeRef val;
60 | int exifOrientation;
61 | val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
62 | if (val) {
63 | CFNumberGetValue(val, kCFNumberIntType, &exifOrientation);
64 | result = [self sd_exifOrientationToiOSOrientation:exifOrientation];
65 | } // else - if it's not set it remains at up
66 | CFRelease((CFTypeRef) properties);
67 | } else {
68 | //NSLog(@"NO PROPERTIES, FAIL");
69 | }
70 | CFRelease(imageSource);
71 | }
72 | return result;
73 | }
74 |
75 | #pragma mark EXIF orientation tag converter
76 | // Convert an EXIF image orientation to an iOS one.
77 | // reference see here: http://sylvana.net/jpegcrop/exif_orientation.html
78 | + (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation {
79 | UIImageOrientation orientation = UIImageOrientationUp;
80 | switch (exifOrientation) {
81 | case 1:
82 | orientation = UIImageOrientationUp;
83 | break;
84 |
85 | case 3:
86 | orientation = UIImageOrientationDown;
87 | break;
88 |
89 | case 8:
90 | orientation = UIImageOrientationLeft;
91 | break;
92 |
93 | case 6:
94 | orientation = UIImageOrientationRight;
95 | break;
96 |
97 | case 2:
98 | orientation = UIImageOrientationUpMirrored;
99 | break;
100 |
101 | case 4:
102 | orientation = UIImageOrientationDownMirrored;
103 | break;
104 |
105 | case 5:
106 | orientation = UIImageOrientationLeftMirrored;
107 | break;
108 |
109 | case 7:
110 | orientation = UIImageOrientationRightMirrored;
111 | break;
112 | default:
113 | break;
114 | }
115 | return orientation;
116 | }
117 | #endif
118 |
119 | - (nullable NSData *)sd_imageData {
120 | return [self sd_imageDataAsFormat:SDImageFormatUndefined];
121 | }
122 |
123 | - (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat {
124 | NSData *imageData = nil;
125 | if (self) {
126 | #if SD_UIKIT || SD_WATCH
127 | int alphaInfo = CGImageGetAlphaInfo(self.CGImage);
128 | BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
129 | alphaInfo == kCGImageAlphaNoneSkipFirst ||
130 | alphaInfo == kCGImageAlphaNoneSkipLast);
131 |
132 | BOOL usePNG = hasAlpha;
133 |
134 | // the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel
135 | if (imageFormat != SDImageFormatUndefined) {
136 | usePNG = (imageFormat == SDImageFormatPNG);
137 | }
138 |
139 | if (usePNG) {
140 | imageData = UIImagePNGRepresentation(self);
141 | } else {
142 | imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0);
143 | }
144 | #else
145 | NSBitmapImageFileType imageFileType = NSJPEGFileType;
146 | if (imageFormat == SDImageFormatGIF) {
147 | imageFileType = NSGIFFileType;
148 | } else if (imageFormat == SDImageFormatPNG) {
149 | imageFileType = NSPNGFileType;
150 | }
151 |
152 | imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations
153 | usingType:imageFileType
154 | properties:@{}];
155 | #endif
156 | }
157 | return imageData;
158 | }
159 |
160 |
161 | @end
162 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImage+WebP.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #ifdef SD_WEBP
10 |
11 | #import "SDWebImageCompat.h"
12 |
13 | @interface UIImage (WebP)
14 |
15 | /**
16 | * Get the current WebP image loop count, the default value is 0.
17 | * For static WebP image, the value is 0.
18 | * For animated WebP image, 0 means repeat the animation indefinitely.
19 | * Note that because of the limitations of categories this property can get out of sync
20 | * if you create another instance with CGImage or other methods.
21 | * @return WebP image loop count
22 | */
23 | - (NSInteger)sd_webpLoopCount;
24 |
25 | + (nullable UIImage *)sd_imageWithWebPData:(nullable NSData *)data;
26 |
27 | @end
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImageView+HighlightedWebCache.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 |
11 | #if SD_UIKIT
12 |
13 | #import "SDWebImageManager.h"
14 |
15 | /**
16 | * Integrates SDWebImage async downloading and caching of remote images with UIImageView for highlighted state.
17 | */
18 | @interface UIImageView (HighlightedWebCache)
19 |
20 | /**
21 | * Set the imageView `highlightedImage` with an `url`.
22 | *
23 | * The download is asynchronous and cached.
24 | *
25 | * @param url The url for the image.
26 | */
27 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT;
28 |
29 | /**
30 | * Set the imageView `highlightedImage` with an `url` and custom options.
31 | *
32 | * The download is asynchronous and cached.
33 | *
34 | * @param url The url for the image.
35 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
36 | */
37 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
38 | options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT;
39 |
40 | /**
41 | * Set the imageView `highlightedImage` with an `url`.
42 | *
43 | * The download is asynchronous and cached.
44 | *
45 | * @param url The url for the image.
46 | * @param completedBlock A block called when operation has been completed. This block has no return value
47 | * and takes the requested UIImage as first parameter. In case of error the image parameter
48 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
49 | * indicating if the image was retrieved from the local cache or from the network.
50 | * The fourth parameter is the original image url.
51 | */
52 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
53 | completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT;
54 |
55 | /**
56 | * Set the imageView `highlightedImage` with an `url` and custom options.
57 | *
58 | * The download is asynchronous and cached.
59 | *
60 | * @param url The url for the image.
61 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
62 | * @param completedBlock A block called when operation has been completed. This block has no return value
63 | * and takes the requested UIImage as first parameter. In case of error the image parameter
64 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
65 | * indicating if the image was retrieved from the local cache or from the network.
66 | * The fourth parameter is the original image url.
67 | */
68 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
69 | options:(SDWebImageOptions)options
70 | completed:(nullable SDExternalCompletionBlock)completedBlock;
71 |
72 | /**
73 | * Set the imageView `highlightedImage` with an `url` and custom options.
74 | *
75 | * The download is asynchronous and cached.
76 | *
77 | * @param url The url for the image.
78 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
79 | * @param progressBlock A block called while image is downloading
80 | * @note the progress block is executed on a background queue
81 | * @param completedBlock A block called when operation has been completed. This block has no return value
82 | * and takes the requested UIImage as first parameter. In case of error the image parameter
83 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
84 | * indicating if the image was retrieved from the local cache or from the network.
85 | * The fourth parameter is the original image url.
86 | */
87 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
88 | options:(SDWebImageOptions)options
89 | progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
90 | completed:(nullable SDExternalCompletionBlock)completedBlock;
91 |
92 | @end
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIImageView+HighlightedWebCache.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "UIImageView+HighlightedWebCache.h"
10 |
11 | #if SD_UIKIT
12 |
13 | #import "UIView+WebCacheOperation.h"
14 | #import "UIView+WebCache.h"
15 |
16 | @implementation UIImageView (HighlightedWebCache)
17 |
18 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url {
19 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil];
20 | }
21 |
22 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options {
23 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil];
24 | }
25 |
26 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock {
27 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock];
28 | }
29 |
30 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock {
31 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock];
32 | }
33 |
34 | - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url
35 | options:(SDWebImageOptions)options
36 | progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
37 | completed:(nullable SDExternalCompletionBlock)completedBlock {
38 | __weak typeof(self)weakSelf = self;
39 | [self sd_internalSetImageWithURL:url
40 | placeholderImage:nil
41 | options:options
42 | operationKey:@"UIImageViewImageOperationHighlighted"
43 | setImageBlock:^(UIImage *image, NSData *imageData) {
44 | weakSelf.highlightedImage = image;
45 | }
46 | progress:progressBlock
47 | completed:completedBlock];
48 | }
49 |
50 | @end
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIView+WebCache.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 |
11 | #if SD_UIKIT || SD_MAC
12 |
13 | #import "SDWebImageManager.h"
14 |
15 | typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData);
16 |
17 | @interface UIView (WebCache)
18 |
19 | /**
20 | * Get the current image URL.
21 | *
22 | * Note that because of the limitations of categories this property can get out of sync
23 | * if you use setImage: directly.
24 | */
25 | - (nullable NSURL *)sd_imageURL;
26 |
27 | /**
28 | * Set the imageView `image` with an `url` and optionally a placeholder image.
29 | *
30 | * The download is asynchronous and cached.
31 | *
32 | * @param url The url for the image.
33 | * @param placeholder The image to be set initially, until the image request finishes.
34 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
35 | * @param operationKey A string to be used as the operation key. If nil, will use the class name
36 | * @param setImageBlock Block used for custom set image code
37 | * @param progressBlock A block called while image is downloading
38 | * @note the progress block is executed on a background queue
39 | * @param completedBlock A block called when operation has been completed. This block has no return value
40 | * and takes the requested UIImage as first parameter. In case of error the image parameter
41 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean
42 | * indicating if the image was retrieved from the local cache or from the network.
43 | * The fourth parameter is the original image url.
44 | */
45 | - (void)sd_internalSetImageWithURL:(nullable NSURL *)url
46 | placeholderImage:(nullable UIImage *)placeholder
47 | options:(SDWebImageOptions)options
48 | operationKey:(nullable NSString *)operationKey
49 | setImageBlock:(nullable SDSetImageBlock)setImageBlock
50 | progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock
51 | completed:(nullable SDExternalCompletionBlock)completedBlock;
52 |
53 | /**
54 | * Cancel the current download
55 | */
56 | - (void)sd_cancelCurrentImageLoad;
57 |
58 | #if SD_UIKIT
59 |
60 | #pragma mark - Activity indicator
61 |
62 | /**
63 | * Show activity UIActivityIndicatorView
64 | */
65 | - (void)sd_setShowActivityIndicatorView:(BOOL)show;
66 |
67 | /**
68 | * set desired UIActivityIndicatorViewStyle
69 | *
70 | * @param style The style of the UIActivityIndicatorView
71 | */
72 | - (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style;
73 |
74 | - (BOOL)sd_showActivityIndicatorView;
75 | - (void)sd_addActivityIndicator;
76 | - (void)sd_removeActivityIndicator;
77 |
78 | #endif
79 |
80 | @end
81 |
82 | #endif
83 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIView+WebCacheOperation.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "SDWebImageCompat.h"
10 |
11 | #if SD_UIKIT || SD_MAC
12 |
13 | #import "SDWebImageManager.h"
14 |
15 | @interface UIView (WebCacheOperation)
16 |
17 | /**
18 | * Set the image load operation (storage in a UIView based dictionary)
19 | *
20 | * @param operation the operation
21 | * @param key key for storing the operation
22 | */
23 | - (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key;
24 |
25 | /**
26 | * Cancel all operations for the current UIView and key
27 | *
28 | * @param key key for identifying the operations
29 | */
30 | - (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key;
31 |
32 | /**
33 | * Just remove the operations corresponding to the current UIView and key without cancelling them
34 | *
35 | * @param key key for identifying the operations
36 | */
37 | - (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key;
38 |
39 | @end
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/SDWebImage/UIView+WebCacheOperation.m:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the SDWebImage package.
3 | * (c) Olivier Poitrey
4 | *
5 | * For the full copyright and license information, please view the LICENSE
6 | * file that was distributed with this source code.
7 | */
8 |
9 | #import "UIView+WebCacheOperation.h"
10 |
11 | #if SD_UIKIT || SD_MAC
12 |
13 | #import "objc/runtime.h"
14 |
15 | static char loadOperationKey;
16 |
17 | typedef NSMutableDictionary SDOperationsDictionary;
18 |
19 | @implementation UIView (WebCacheOperation)
20 |
21 | - (SDOperationsDictionary *)operationDictionary {
22 | SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey);
23 | if (operations) {
24 | return operations;
25 | }
26 | operations = [NSMutableDictionary dictionary];
27 | objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
28 | return operations;
29 | }
30 |
31 | - (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key {
32 | if (key) {
33 | [self sd_cancelImageLoadOperationWithKey:key];
34 | if (operation) {
35 | SDOperationsDictionary *operationDictionary = [self operationDictionary];
36 | operationDictionary[key] = operation;
37 | }
38 | }
39 | }
40 |
41 | - (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
42 | // Cancel in progress downloader from queue
43 | SDOperationsDictionary *operationDictionary = [self operationDictionary];
44 | id operations = operationDictionary[key];
45 | if (operations) {
46 | if ([operations isKindOfClass:[NSArray class]]) {
47 | for (id operation in operations) {
48 | if (operation) {
49 | [operation cancel];
50 | }
51 | }
52 | } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){
53 | [(id) operations cancel];
54 | }
55 | [operationDictionary removeObjectForKey:key];
56 | }
57 | }
58 |
59 | - (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key {
60 | if (key) {
61 | SDOperationsDictionary *operationDictionary = [self operationDictionary];
62 | [operationDictionary removeObjectForKey:key];
63 | }
64 | }
65 |
66 | @end
67 |
68 | #endif
69 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/EMVoiceConverter.h:
--------------------------------------------------------------------------------
1 | //
2 | // VoiceConverter.h
3 | // Jeans
4 | //
5 | // Created by Jeans Huang on 12-7-22.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface EMVoiceConverter : NSObject
12 |
13 | + (int)isMP3File:(NSString *)filePath;
14 |
15 | + (int)isAMRFile:(NSString *)filePath;
16 |
17 | + (int)amrToWav:(NSString*)_amrPath wavSavePath:(NSString*)_savePath;
18 |
19 | + (int)wavToAmr:(NSString*)_wavPath amrSavePath:(NSString*)_savePath;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/EMVoiceConverter.mm:
--------------------------------------------------------------------------------
1 | //
2 | // VoiceConverter.m
3 | // Jeans
4 | //
5 | // Created by Jeans Huang on 12-7-22.
6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "EMVoiceConverter.h"
10 | #import "wav.h"
11 | #import "interf_dec.h"
12 | #import "dec_if.h"
13 | #import "interf_enc.h"
14 | #import "amrFileCodec.h"
15 |
16 | @implementation EMVoiceConverter
17 |
18 |
19 | + (int)isMP3File:(NSString *)filePath{
20 | const char *_filePath = [filePath cStringUsingEncoding:NSASCIIStringEncoding];
21 | return isMP3File(_filePath);
22 | }
23 |
24 | + (int)isAMRFile:(NSString *)filePath{
25 | const char *_filePath = [filePath cStringUsingEncoding:NSASCIIStringEncoding];
26 | return isAMRFile(_filePath);
27 | }
28 |
29 | + (int)amrToWav:(NSString*)_amrPath wavSavePath:(NSString*)_savePath{
30 |
31 | if (EM_DecodeAMRFileToWAVEFile([_amrPath cStringUsingEncoding:NSASCIIStringEncoding], [_savePath cStringUsingEncoding:NSASCIIStringEncoding]))
32 | return 0; // success
33 |
34 | return 1; // failed
35 | }
36 |
37 | + (int)wavToAmr:(NSString*)_wavPath amrSavePath:(NSString*)_savePath{
38 |
39 | if (EM_EncodeWAVEFileToAMRFile([_wavPath cStringUsingEncoding:NSASCIIStringEncoding], [_savePath cStringUsingEncoding:NSASCIIStringEncoding], 1, 16))
40 | return 0; // success
41 |
42 | return 1; // failed
43 | }
44 |
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/amrwapper/amrFileCodec.h:
--------------------------------------------------------------------------------
1 | //
2 | // amrFileCodec.h
3 | // amrDemoForiOS
4 | //
5 | // Created by Tang Xiaoping on 9/27/11.
6 | // Copyright 2011 test. All rights reserved.
7 | //
8 | #ifndef amrFileCodec_h
9 | #define amrFileCodec_h
10 | #include
11 | #include
12 | #include
13 | #include "interf_dec.h"
14 | #include "interf_enc.h"
15 |
16 | #define AMR_MAGIC_NUMBER "#!AMR\n"
17 | #define MP3_MAGIC_NUMBER "ID3"
18 |
19 | #define PCM_FRAME_SIZE 160 // 8khz 8000*0.02=160
20 | #define MAX_AMR_FRAME_SIZE 32
21 | #define AMR_FRAME_COUNT_PER_SECOND 50
22 |
23 | typedef struct
24 | {
25 | char chChunkID[4];
26 | int nChunkSize;
27 | }EM_XCHUNKHEADER;
28 |
29 | typedef struct
30 | {
31 | short nFormatTag;
32 | short nChannels;
33 | int nSamplesPerSec;
34 | int nAvgBytesPerSec;
35 | short nBlockAlign;
36 | short nBitsPerSample;
37 | }EM_WAVEFORMAT;
38 |
39 | typedef struct
40 | {
41 | short nFormatTag;
42 | short nChannels;
43 | int nSamplesPerSec;
44 | int nAvgBytesPerSec;
45 | short nBlockAlign;
46 | short nBitsPerSample;
47 | short nExSize;
48 | }EM_WAVEFORMATX;
49 |
50 | typedef struct
51 | {
52 | char chRiffID[4];
53 | int nRiffSize;
54 | char chRiffFormat[4];
55 | }EM_RIFFHEADER;
56 |
57 | typedef struct
58 | {
59 | char chFmtID[4];
60 | int nFmtSize;
61 | EM_WAVEFORMAT wf;
62 | }EM_FMTBLOCK;
63 |
64 | // WAVE audio processing frequency is 8khz
65 | // audio processing unit = 8000*0.02 = 160 (decided by audio processing frequency)
66 | // audio channels 1 : 160
67 | // 2 : 160*2 = 320
68 | // bps decides the size of processing sample
69 | // bps = 8 --> 8 bits
70 | // 16 --> 16 bit
71 | int EM_EncodeWAVEFileToAMRFile(const char* pchWAVEFilename, const char* pchAMRFileName, int nChannels, int nBitsPerSample);
72 |
73 | int EM_DecodeAMRFileToWAVEFile(const char* pchAMRFileName, const char* pchWAVEFilename);
74 |
75 | int isMP3File(const char *filePath);
76 |
77 | int isAMRFile(const char *filePath);
78 | #endif
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/amrwapper/wav.h:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------
2 | * Copyright (C) 2009 Martin Storsjo
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 | * express or implied.
14 | * See the License for the specific language governing permissions
15 | * and limitations under the License.
16 | * -------------------------------------------------------------------
17 | */
18 |
19 | #ifndef WAV_H
20 | #define WAV_H
21 |
22 | #include
23 |
24 | class WavWriter {
25 | public:
26 | WavWriter(const char *filename, int sampleRate, int bitsPerSample, int channels);
27 | ~WavWriter();
28 |
29 | void writeData(const unsigned char* data, int length);
30 |
31 | private:
32 | void writeString(const char *str);
33 | void writeInt32(int value);
34 | void writeInt16(int value);
35 |
36 | void writeHeader(int length);
37 |
38 | FILE *wav;
39 | int dataLength;
40 |
41 | int sampleRate;
42 | int bitsPerSample;
43 | int channels;
44 | };
45 |
46 | #endif
47 |
48 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/amrwapper/wav.mm:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------
2 | * Copyright (C) 2009 Martin Storsjo
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 | * express or implied.
14 | * See the License for the specific language governing permissions
15 | * and limitations under the License.
16 | * -------------------------------------------------------------------
17 | */
18 |
19 | #import
20 | #include "wav.h"
21 |
22 | void WavWriter::writeString(const char *str) {
23 | fputc(str[0], wav);
24 | fputc(str[1], wav);
25 | fputc(str[2], wav);
26 | fputc(str[3], wav);
27 | }
28 |
29 | void WavWriter::writeInt32(int value) {
30 | fputc((value >> 0) & 0xff, wav);
31 | fputc((value >> 8) & 0xff, wav);
32 | fputc((value >> 16) & 0xff, wav);
33 | fputc((value >> 24) & 0xff, wav);
34 | }
35 |
36 | void WavWriter::writeInt16(int value) {
37 | fputc((value >> 0) & 0xff, wav);
38 | fputc((value >> 8) & 0xff, wav);
39 | }
40 |
41 | void WavWriter::writeHeader(int length) {
42 | writeString("RIFF");
43 | writeInt32(4 + 8 + 20 + 8 + length); //将16改为20
44 | writeString("WAVE");
45 |
46 | writeString("fmt ");
47 | writeInt32(20);
48 |
49 | int bytesPerFrame = bitsPerSample/8*channels;
50 | int bytesPerSec = bytesPerFrame*sampleRate;
51 | writeInt16(1); // Format
52 | writeInt16(channels); // Channels
53 | writeInt32(sampleRate); // Samplerate
54 | writeInt32(bytesPerSec); // Bytes per sec
55 | writeInt16(bytesPerFrame); // Bytes per frame
56 | writeInt16(bitsPerSample); // Bits per sample
57 |
58 | writeInt32(0); //这儿需要字节对齐 nExSize
59 |
60 | writeString("data");
61 | writeInt32(length);
62 | }
63 |
64 | WavWriter::WavWriter(const char *filename, int sampleRate, int bitsPerSample, int channels)
65 | {
66 |
67 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
68 | NSString *documentPath = [paths objectAtIndex:0];
69 | NSString *docFilePath = [documentPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%s", filename]];
70 | //NSLog(@"documentPath=%@", documentPath);
71 |
72 | wav = fopen([docFilePath cStringUsingEncoding:NSASCIIStringEncoding], "wb");
73 | if (wav == NULL)
74 | return;
75 | dataLength = 0;
76 | this->sampleRate = sampleRate;
77 | this->bitsPerSample = bitsPerSample;
78 | this->channels = channels;
79 |
80 | writeHeader(dataLength);
81 | }
82 |
83 | WavWriter::~WavWriter() {
84 | if (wav == NULL)
85 | return;
86 | fseek(wav, 0, SEEK_SET);
87 | writeHeader(dataLength);
88 | fclose(wav);
89 | }
90 |
91 | void WavWriter::writeData(const unsigned char* data, int length) {
92 | if (wav == NULL)
93 | return;
94 | fwrite(data, length, 1, wav);
95 | dataLength += length;
96 | }
97 |
98 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrnb/interf_dec.h:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------
2 | * Copyright (C) 2009 Martin Storsjo
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 | * express or implied.
14 | * See the License for the specific language governing permissions
15 | * and limitations under the License.
16 | * -------------------------------------------------------------------
17 | */
18 |
19 | #ifndef OPENCORE_AMRNB_INTERF_DEC_H
20 | #define OPENCORE_AMRNB_INTERF_DEC_H
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 |
26 | void* Decoder_Interface_init(void);
27 | void Decoder_Interface_exit(void* state);
28 | void Decoder_Interface_Decode(void* state, const unsigned char* in, short* out, int bfi);
29 |
30 | #ifdef __cplusplus
31 | }
32 | #endif
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrnb/interf_enc.h:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------
2 | * Copyright (C) 2009 Martin Storsjo
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 | * express or implied.
14 | * See the License for the specific language governing permissions
15 | * and limitations under the License.
16 | * -------------------------------------------------------------------
17 | */
18 |
19 | #ifndef OPENCORE_AMRNB_INTERF_ENC_H
20 | #define OPENCORE_AMRNB_INTERF_ENC_H
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 |
26 | #ifndef AMRNB_WRAPPER_INTERNAL
27 | /* Copied from enc/src/gsmamr_enc.h */
28 | enum Mode {
29 | MR475 = 0,/* 4.75 kbps */
30 | MR515, /* 5.15 kbps */
31 | MR59, /* 5.90 kbps */
32 | MR67, /* 6.70 kbps */
33 | MR74, /* 7.40 kbps */
34 | MR795, /* 7.95 kbps */
35 | MR102, /* 10.2 kbps */
36 | MR122, /* 12.2 kbps */
37 | MRDTX, /* DTX */
38 | N_MODES /* Not Used */
39 | };
40 | #endif
41 |
42 | void* Encoder_Interface_init(int dtx);
43 | void Encoder_Interface_exit(void* state);
44 | int Encoder_Interface_Encode(void* state, enum Mode mode, const short* speech, unsigned char* out, int forceSpeech);
45 |
46 | #ifdef __cplusplus
47 | }
48 | #endif
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrnb/libopencore-amrnb.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrnb/libopencore-amrnb.a
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrwb/dec_if.h:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------
2 | * Copyright (C) 2009 Martin Storsjo
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 | * express or implied.
14 | * See the License for the specific language governing permissions
15 | * and limitations under the License.
16 | * -------------------------------------------------------------------
17 | */
18 |
19 | #ifndef OPENCORE_AMRWB_DEC_IF_H
20 | #define OPENCORE_AMRWB_DEC_IF_H
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 |
26 | #define _good_frame 0
27 |
28 | void* D_IF_init(void);
29 | void D_IF_decode(void* state, const unsigned char* bits, short* synth, int bfi);
30 | void D_IF_exit(void* state);
31 |
32 | #ifdef __cplusplus
33 | }
34 | #endif
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrwb/if_rom.h:
--------------------------------------------------------------------------------
1 | /* ------------------------------------------------------------------
2 | * Copyright (C) 2009 Martin Storsjo
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 | * express or implied.
14 | * See the License for the specific language governing permissions
15 | * and limitations under the License.
16 | * -------------------------------------------------------------------
17 | */
18 |
19 | #ifndef OPENCORE_AMRWB_IF_ROM_H
20 | #define OPENCORE_AMRWB_IF_ROM_H
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 |
26 | #include
27 | typedef int16_t Word16;
28 |
29 | #ifdef __cplusplus
30 | }
31 | #endif
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrwb/libopencore-amrwb.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agiapp/TestIMDemo/3f49aa5e6f7ba12cc347bdc92fc1ba6762246839/TestIMDemo/Classes/Vendor/DeviceHelper/VoiceConvert/opencore-amrwb/libopencore-amrwb.a
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/delegates/EMCDDeviceManagerDelegate.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 | #import "EMCDDeviceManagerProximitySensorDelegate.h"
15 |
16 | @protocol EMCDDeviceManagerDelegate
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/delegates/EMCDDeviceManagerProximitySensorDelegate.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 |
15 | @protocol EMCDDeviceManagerProximitySensorDelegate
16 |
17 | /*!
18 | @method
19 | @brief Posted when the state of the proximity sensor changes.
20 | @param isCloseToUser indicates whether the proximity sensor is close to the user (YES) or not (NO).
21 | @discussion
22 | @result
23 | */
24 | - (void)proximitySensorChanged:(BOOL)isCloseToUser;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/DemoErrorCode.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #ifndef ChatDemo_UI2_0_DemoErrorCode_h
14 | #define ChatDemo_UI2_0_DemoErrorCode_h
15 |
16 | #define EMErrorAudioRecordDurationTooShort -100
17 | #define EMErrorFileTypeConvertionFailure -101
18 | #define EMErrorAudioRecordStoping -102
19 | #define EMErrorAudioRecordNotStarted -103
20 |
21 | #endif
22 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMAudioPlayerUtil.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 |
15 | @interface EMAudioPlayerUtil : NSObject
16 |
17 | + (BOOL)isPlaying;
18 |
19 | // Get the path of what is currently being played
20 | + (NSString *)playingFilePath;
21 |
22 | // Play the audio(wav)from the path
23 | + (void)asyncPlayingWithPath:(NSString *)aFilePath
24 | completion:(void(^)(NSError *error))completon;
25 |
26 | + (void)stopCurrentPlaying;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMAudioPlayerUtil.m:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMAudioPlayerUtil.h"
14 | #import
15 |
16 | static EMAudioPlayerUtil *audioPlayerUtil = nil;
17 |
18 | @interface EMAudioPlayerUtil () {
19 | AVAudioPlayer *_player;
20 | void (^playFinish)(NSError *error);
21 | }
22 |
23 | @end
24 |
25 | @implementation EMAudioPlayerUtil
26 |
27 | #pragma mark - public
28 | + (BOOL)isPlaying{
29 | return [[EMAudioPlayerUtil sharedInstance] isPlaying];
30 | }
31 |
32 | + (NSString *)playingFilePath{
33 | return [[EMAudioPlayerUtil sharedInstance] playingFilePath];
34 | }
35 |
36 | + (void)asyncPlayingWithPath:(NSString *)aFilePath
37 | completion:(void(^)(NSError *error))completon{
38 | [[EMAudioPlayerUtil sharedInstance] asyncPlayingWithPath:aFilePath
39 | completion:completon];
40 | }
41 |
42 | + (void)stopCurrentPlaying{
43 | [[EMAudioPlayerUtil sharedInstance] stopCurrentPlaying];
44 | }
45 |
46 |
47 | #pragma mark - private
48 | + (EMAudioPlayerUtil *)sharedInstance{
49 | static dispatch_once_t onceToken;
50 | dispatch_once(&onceToken, ^{
51 | audioPlayerUtil = [[self alloc] init];
52 | });
53 |
54 | return audioPlayerUtil;
55 | }
56 |
57 | - (BOOL)isPlaying
58 | {
59 | return !!_player;
60 | }
61 |
62 | // Get the path of what is currently being played
63 | - (NSString *)playingFilePath
64 | {
65 | NSString *path = nil;
66 | if (_player && _player.isPlaying) {
67 | path = _player.url.path;
68 | }
69 |
70 | return path;
71 | }
72 |
73 | - (void)asyncPlayingWithPath:(NSString *)aFilePath
74 | completion:(void(^)(NSError *error))completon{
75 | playFinish = completon;
76 | NSError *error = nil;
77 | NSFileManager *fm = [NSFileManager defaultManager];
78 | if (![fm fileExistsAtPath:aFilePath]) {
79 | error = [NSError errorWithDomain:@"File path not exist"
80 | code:-1
81 | userInfo:nil];
82 | if (playFinish) {
83 | playFinish(error);
84 | }
85 | playFinish = nil;
86 |
87 | return;
88 | }
89 |
90 | NSURL *wavUrl = [[NSURL alloc] initFileURLWithPath:aFilePath];
91 | _player = [[AVAudioPlayer alloc] initWithContentsOfURL:wavUrl error:&error];
92 | if (error || !_player) {
93 | _player = nil;
94 | error = [NSError errorWithDomain:@"Failed to initialize AVAudioPlayer"
95 | code:-1
96 | userInfo:nil];
97 | if (playFinish) {
98 | playFinish(error);
99 | }
100 | playFinish = nil;
101 | return;
102 | }
103 |
104 | _player.delegate = self;
105 | [_player prepareToPlay];
106 | [_player play];
107 | }
108 |
109 | - (void)stopCurrentPlaying{
110 | if(_player){
111 | _player.delegate = nil;
112 | [_player stop];
113 | _player = nil;
114 | }
115 | if (playFinish) {
116 | playFinish = nil;
117 | }
118 | }
119 |
120 | - (void)dealloc{
121 | if (_player) {
122 | _player.delegate = nil;
123 | [_player stop];
124 | _player = nil;
125 | }
126 | playFinish = nil;
127 | }
128 |
129 | #pragma mark - AVAudioPlayerDelegate
130 | - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
131 | successfully:(BOOL)flag{
132 | if (playFinish) {
133 | playFinish(nil);
134 | }
135 | if (_player) {
136 | _player.delegate = nil;
137 | _player = nil;
138 | }
139 | playFinish = nil;
140 | }
141 |
142 | - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player
143 | error:(NSError *)error{
144 | if (playFinish) {
145 | NSError *error = [NSError errorWithDomain:@"Play failure"
146 | code:-1
147 | userInfo:nil];
148 | playFinish(error);
149 | }
150 | if (_player) {
151 | _player.delegate = nil;
152 | _player = nil;
153 | }
154 | }
155 |
156 | @end
157 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMAudioRecorderUtil.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 | #import
15 | @interface EMAudioRecorderUtil : NSObject
16 |
17 | +(BOOL)isRecording;
18 |
19 | // Start recording
20 | + (void)asyncStartRecordingWithPreparePath:(NSString *)aFilePath
21 | completion:(void(^)(NSError *error))completion;
22 | // Stop recording
23 | +(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath))completion;
24 |
25 | // Cancel recording
26 | +(void)cancelCurrentRecording;
27 |
28 | // Current recorder
29 | +(AVAudioRecorder *)recorder;
30 | @end
31 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+Media.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMCDDeviceManagerBase.h"
14 |
15 | @interface EMCDDeviceManager (Media)
16 |
17 | #pragma mark - AudioPlayer
18 | // Play the audio
19 | - (void)asyncPlayingWithPath:(NSString *)aFilePath
20 | completion:(void(^)(NSError *error))completon;
21 | // Stop playing
22 | - (void)stopPlaying;
23 |
24 | - (void)stopPlayingWithChangeCategory:(BOOL)isChange;
25 |
26 | -(BOOL)isPlaying;
27 |
28 | #pragma mark - AudioRecorder
29 | // Start recording
30 | - (void)asyncStartRecordingWithFileName:(NSString *)fileName
31 | completion:(void(^)(NSError *error))completion;
32 |
33 | // Stop recording
34 | -(void)asyncStopRecordingWithCompletion:(void(^)(NSString *recordPath,
35 | NSInteger aDuration,
36 | NSError *error))completion;
37 | // Cancel recording
38 | -(void)cancelCurrentRecording;
39 |
40 | -(BOOL)isRecording;
41 |
42 | // Get the saved data path
43 | + (NSString*)dataPath;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+Microphone.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMCDDeviceManager.h"
14 |
15 | @interface EMCDDeviceManager (Microphone)
16 |
17 | // Check the availability for microphone
18 | - (BOOL)emCheckMicrophoneAvailability;
19 |
20 | // Get the audio volumn (0~1)
21 | - (double)emPeekRecorderVoiceMeter;
22 | @end
23 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+Microphone.m:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMCDDeviceManager+Microphone.h"
14 | #import "EMAudioRecorderUtil.h"
15 |
16 | @implementation EMCDDeviceManager (Microphone)
17 |
18 | // Check the availability for microphone
19 | - (BOOL)emCheckMicrophoneAvailability{
20 | __block BOOL ret = NO;
21 | AVAudioSession *session = [AVAudioSession sharedInstance];
22 | if ([session respondsToSelector:@selector(requestRecordPermission:)]) {
23 | [session performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
24 | ret = granted;
25 | }];
26 | } else {
27 | ret = YES;
28 | }
29 |
30 | return ret;
31 | }
32 |
33 | // Get the audio volumn (0~1)
34 | - (double)emPeekRecorderVoiceMeter{
35 | double ret = 0.0;
36 | if ([EMAudioRecorderUtil recorder].isRecording) {
37 | [[EMAudioRecorderUtil recorder] updateMeters];
38 | //Average volumn [recorder averagePowerForChannel:0];
39 | //Maximum volumn [recorder peakPowerForChannel:0];
40 | double lowPassResults = pow(10, (0.05 * [[EMAudioRecorderUtil recorder] peakPowerForChannel:0]));
41 | ret = lowPassResults;
42 | }
43 |
44 | return ret;
45 | }
46 | @end
47 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+ProximitySensor.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMCDDeviceManagerBase.h"
14 |
15 | @interface EMCDDeviceManager (ProximitySensor)
16 | #pragma mark - proximity sensor
17 | @property (nonatomic, readonly) BOOL isSupportProximitySensor;
18 | @property (nonatomic, readonly) BOOL isCloseToUser;
19 | @property (nonatomic, readonly) BOOL isProximitySensorEnabled;
20 |
21 | - (BOOL)enableProximitySensor;
22 | - (BOOL)disableProximitySensor;
23 | - (void)sensorStateChanged:(NSNotification *)notification;
24 | @end
25 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+ProximitySensor.m:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 | #import "EMCDDeviceManager+ProximitySensor.h"
15 |
16 | @implementation EMCDDeviceManager (ProximitySensor)
17 | @dynamic isSupportProximitySensor;
18 | @dynamic isCloseToUser;
19 |
20 |
21 | #pragma mark - proximity sensor
22 | - (BOOL)isProximitySensorEnabled {
23 | BOOL ret = NO;
24 | ret = self.isSupportProximitySensor && [UIDevice currentDevice].proximityMonitoringEnabled;
25 |
26 | return ret;
27 | }
28 |
29 | - (BOOL)enableProximitySensor {
30 | BOOL ret = NO;
31 | if (_isSupportProximitySensor) {
32 | [[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
33 | ret = YES;
34 | }
35 |
36 | return ret;
37 | }
38 |
39 | - (BOOL)disableProximitySensor {
40 | BOOL ret = NO;
41 | if (_isSupportProximitySensor) {
42 | [[UIDevice currentDevice] setProximityMonitoringEnabled:NO];
43 | _isCloseToUser = NO;
44 | ret = YES;
45 | }
46 |
47 | return ret;
48 | }
49 |
50 | - (void)sensorStateChanged:(NSNotification *)notification {
51 | BOOL ret = NO;
52 | if ([[UIDevice currentDevice] proximityState] == YES) {
53 | ret = YES;
54 | }
55 | _isCloseToUser = ret;
56 | if([self.delegate respondsToSelector:@selector(proximitySensorChanged:)]){
57 | [self.delegate proximitySensorChanged:_isCloseToUser];
58 | }
59 | }
60 |
61 | #pragma mark - getter
62 | - (BOOL)isCloseToUser {
63 | return _isCloseToUser;
64 | }
65 |
66 | - (BOOL)isSupportProximitySensor {
67 | return _isSupportProximitySensor;
68 | }
69 | @end
70 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+Remind.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMCDDeviceManager.h"
14 | #import
15 | @interface EMCDDeviceManager (Remind)
16 |
17 | // The system sound for a new message
18 | - (SystemSoundID)playNewMessageSound;
19 |
20 | - (void)playVibration;
21 | @end
22 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager+Remind.m:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import "EMCDDeviceManager+Remind.h"
14 |
15 | void EMSystemSoundFinishedPlayingCallback(SystemSoundID sound_id, void* user_data)
16 | {
17 | AudioServicesDisposeSystemSoundID(sound_id);
18 | }
19 |
20 | @implementation EMCDDeviceManager (Remind)
21 |
22 | // The system sound for a new message
23 | - (SystemSoundID)playNewMessageSound
24 | {
25 | // Path for the audio file
26 | NSURL *audioPath = [[NSBundle mainBundle] URLForResource:@"in" withExtension:@"caf"];
27 |
28 | SystemSoundID soundID;
29 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)(audioPath), &soundID);
30 | // Register the sound completion callback.
31 | AudioServicesAddSystemSoundCompletion(soundID,
32 | NULL, // uses the main run loop
33 | NULL, // uses kCFRunLoopDefaultMode
34 | EMSystemSoundFinishedPlayingCallback, // the name of our custom callback function
35 | NULL // for user data, but we don't need to do that in this case, so we just pass NULL
36 | );
37 |
38 | AudioServicesPlaySystemSound(soundID);
39 |
40 | return soundID;
41 | }
42 |
43 | - (void)playVibration
44 | {
45 | // Register the sound completion callback.
46 | AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate,
47 | NULL, // uses the main run loop
48 | NULL, // uses kCFRunLoopDefaultMode
49 | EMSystemSoundFinishedPlayingCallback, // the name of our custom callback function
50 | NULL // for user data, but we don't need to do that in this case, so we just pass NULL
51 | );
52 |
53 | AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
54 | }
55 | @end
56 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManager.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #ifndef ChatDemo_UI2_0_EMCDDeviceManager_h
14 | #define ChatDemo_UI2_0_EMCDDeviceManager_h
15 |
16 | #import "EMCDDeviceManager+Media.h"
17 | #import "EMCDDeviceManager+Remind.h"
18 | #import "EMCDDeviceManager+Microphone.h"
19 | #import "EMCDDeviceManager+ProximitySensor.h"
20 |
21 | #endif
22 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManagerBase.h:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 | #import "EMCDDeviceManagerDelegate.h"
15 |
16 | @interface EMCDDeviceManager : NSObject{
17 | // recorder
18 | NSDate *_recorderStartDate;
19 | NSDate *_recorderEndDate;
20 | NSString *_currCategory;
21 | BOOL _currActive;
22 |
23 | // proximitySensor
24 | BOOL _isSupportProximitySensor;
25 | BOOL _isCloseToUser;
26 | }
27 |
28 | @property (nonatomic, assign) id delegate;
29 |
30 | +(EMCDDeviceManager *)sharedInstance;
31 |
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/TestIMDemo/Classes/Vendor/DeviceHelper/internal/EMCDDeviceManagerBase.m:
--------------------------------------------------------------------------------
1 | /************************************************************
2 | * * Hyphenate CONFIDENTIAL
3 | * __________________
4 | * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
5 | *
6 | * NOTICE: All information contained herein is, and remains
7 | * the property of Hyphenate Inc.
8 | * Dissemination of this information or reproduction of this material
9 | * is strictly forbidden unless prior written permission is obtained
10 | * from Hyphenate Inc.
11 | */
12 |
13 | #import
14 | #import "EMCDDeviceManagerBase.h"
15 | #import "EMCDDeviceManager+ProximitySensor.h"
16 |
17 | static EMCDDeviceManager *emCDDeviceManager;
18 | @interface EMCDDeviceManager (){
19 |
20 | }
21 |
22 | @end
23 |
24 | @implementation EMCDDeviceManager
25 | +(EMCDDeviceManager *)sharedInstance{
26 | static dispatch_once_t onceToken;
27 | dispatch_once(&onceToken, ^{
28 | emCDDeviceManager = [[EMCDDeviceManager alloc] init];
29 | });
30 |
31 | return emCDDeviceManager;
32 | }
33 |
34 | -(instancetype)init{
35 | if (self = [super init]) {
36 | [self _setupProximitySensor];
37 | [self registerNotifications];
38 | }
39 | return self;
40 | }
41 |
42 | - (void)registerNotifications
43 | {
44 | [self unregisterNotifications];
45 | if (_isSupportProximitySensor) {
46 | static NSString *notif = @"UIDeviceProximityStateDidChangeNotification";
47 | [[NSNotificationCenter defaultCenter] addObserver:self
48 | selector:@selector(sensorStateChanged:)
49 | name:notif
50 | object:nil];
51 | }
52 | }
53 |
54 | - (void)unregisterNotifications {
55 | if (_isSupportProximitySensor) {
56 | static NSString *notif = @"UIDeviceProximityStateDidChangeNotification";
57 | [[NSNotificationCenter defaultCenter] removeObserver:self
58 | name:notif
59 | object:nil];
60 | }
61 | }
62 |
63 | - (void)_setupProximitySensor
64 | {
65 | UIDevice *device = [UIDevice currentDevice];
66 | [device setProximityMonitoringEnabled:YES];
67 | _isSupportProximitySensor = device.proximityMonitoringEnabled;
68 | if (_isSupportProximitySensor) {
69 | [device setProximityMonitoringEnabled:NO];
70 | } else {
71 |
72 | }
73 | }
74 |
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/TestIMDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | 测试环信IM
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | UILaunchStoryboardName
31 | LaunchScreen
32 | UIMainStoryboardFile
33 | Login
34 | UIRequiredDeviceCapabilities
35 |
36 | armv7
37 |
38 | UISupportedInterfaceOrientations
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | NSPhotoLibraryUsageDescription
45 | 该应用要访问你的相册
46 |
47 |
48 |
--------------------------------------------------------------------------------
/TestIMDemo/PrefixHeader.pch:
--------------------------------------------------------------------------------
1 | //
2 | // PrefixHeader.pch
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/20.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #ifndef PrefixHeader_pch
10 | #define PrefixHeader_pch
11 |
12 | #define EaseMobAppKey @"1179170720178073#testimdemo"
13 |
14 | // 导入环信头文件
15 | #import
16 |
17 | #import "UIViewController+Alert.h"
18 |
19 | #endif /* PrefixHeader_pch */
20 |
--------------------------------------------------------------------------------
/TestIMDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // TestIMDemo
4 | //
5 | // Created by 任波 on 2017/7/20.
6 | // Copyright © 2017年 renb. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------