├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── Demo
├── Demo.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── Demo.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Demo
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── .DS_Store
│ │ ├── Alarm.imageset
│ │ │ ├── Alarm.png
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ ├── Camera.imageset
│ │ │ ├── Camera.png
│ │ │ └── Contents.json
│ │ ├── Contacts.imageset
│ │ │ ├── Contacts.png
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── FT_Add.imageset
│ │ │ ├── Contents.json
│ │ │ └── FT_Add@2x.png
│ │ ├── FT_Error.imageset
│ │ │ ├── Contents.json
│ │ │ └── FT_Error@2x.png
│ │ ├── FT_Record.imageset
│ │ │ ├── Contents.json
│ │ │ └── FT_Record@2x.png
│ │ ├── Mail.imageset
│ │ │ ├── Contents.json
│ │ │ └── Mail.png
│ │ ├── Media_Pause.imageset
│ │ │ ├── Contents.json
│ │ │ └── Media_Pause.png
│ │ ├── Media_Play.imageset
│ │ │ ├── Contents.json
│ │ │ └── Media_Play.png
│ │ ├── Messages.imageset
│ │ │ ├── Contents.json
│ │ │ └── Messages.png
│ │ ├── Music.imageset
│ │ │ ├── Contents.json
│ │ │ └── Music.png
│ │ ├── Phone.imageset
│ │ │ ├── Contents.json
│ │ │ └── Phone.png
│ │ ├── Photos.imageset
│ │ │ ├── Contents.json
│ │ │ └── Photos.png
│ │ ├── Settings.imageset
│ │ │ ├── Contents.json
│ │ │ └── Settings.png
│ │ ├── VideoChat.imageset
│ │ │ ├── Contents.json
│ │ │ └── Videocamera.png
│ │ ├── Videos.imageset
│ │ │ ├── Contents.json
│ │ │ └── Videos.png
│ │ ├── Voice_Record.imageset
│ │ │ ├── Contents.json
│ │ │ └── Voice_Record.png
│ │ └── Weather.imageset
│ │ │ ├── Contents.json
│ │ │ └── Weather.png
│ ├── Base.lproj
│ │ ├── .DS_Store
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── ChatRoomTableViewCell.swift
│ ├── ChatRoomViewController.swift
│ ├── ChatTableViewController.swift
│ ├── ContactsTableViewCell.swift
│ ├── ContactsViewController.swift
│ ├── Demo-Bridging-Header.h
│ ├── Info.plist
│ ├── SignInViewController.swift
│ ├── dog.jpg
│ └── pinyin.bin
├── Podfile
├── Podfile.lock
└── Pods
│ ├── FTImageSize
│ ├── FTImageSize
│ │ └── FTImageSize.swift
│ ├── LICENSE
│ └── README.md
│ ├── FTIndicator
│ ├── FTIndicator
│ │ ├── FTIndicator.h
│ │ ├── FTIndicator.m
│ │ ├── FTNotificationIndicator
│ │ │ ├── FTNotificationIndicator.h
│ │ │ └── FTNotificationIndicator.m
│ │ ├── FTProgressIndicator
│ │ │ ├── FTProgressIndicator.bundle
│ │ │ │ ├── ft_failure.png
│ │ │ │ ├── ft_failure_dark.png
│ │ │ │ ├── ft_info.png
│ │ │ │ ├── ft_info_dark.png
│ │ │ │ ├── ft_success.png
│ │ │ │ └── ft_success_dark.png
│ │ │ ├── FTProgressIndicator.h
│ │ │ └── FTProgressIndicator.m
│ │ └── FTToastIndicator
│ │ │ ├── FTToastIndicator.h
│ │ │ └── FTToastIndicator.m
│ ├── LICENSE
│ └── README.md
│ ├── FTPickerView
│ ├── FTPickerView
│ │ ├── FTPickerView.h
│ │ └── FTPickerView.m
│ ├── LICENSE
│ └── README.md
│ ├── Kingfisher
│ ├── LICENSE
│ ├── README.md
│ └── Sources
│ │ ├── AnimatedImageView.swift
│ │ ├── Box.swift
│ │ ├── CacheSerializer.swift
│ │ ├── Filter.swift
│ │ ├── FormatIndicatedCacheSerializer.swift
│ │ ├── Image.swift
│ │ ├── ImageCache.swift
│ │ ├── ImageDownloader.swift
│ │ ├── ImageModifier.swift
│ │ ├── ImagePrefetcher.swift
│ │ ├── ImageProcessor.swift
│ │ ├── ImageTransition.swift
│ │ ├── ImageView+Kingfisher.swift
│ │ ├── Indicator.swift
│ │ ├── Kingfisher.h
│ │ ├── Kingfisher.swift
│ │ ├── KingfisherManager.swift
│ │ ├── KingfisherOptionsInfo.swift
│ │ ├── Placeholder.swift
│ │ ├── RequestModifier.swift
│ │ ├── Resource.swift
│ │ ├── String+MD5.swift
│ │ ├── ThreadHelper.swift
│ │ └── UIButton+Kingfisher.swift
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ └── project.pbxproj
│ └── Target Support Files
│ ├── FTImageSize
│ ├── FTImageSize-dummy.m
│ ├── FTImageSize-prefix.pch
│ ├── FTImageSize-umbrella.h
│ ├── FTImageSize.modulemap
│ ├── FTImageSize.xcconfig
│ └── Info.plist
│ ├── FTIndicator
│ ├── FTIndicator-dummy.m
│ ├── FTIndicator-prefix.pch
│ ├── FTIndicator-umbrella.h
│ ├── FTIndicator.modulemap
│ ├── FTIndicator.xcconfig
│ └── Info.plist
│ ├── FTPickerView
│ ├── FTPickerView-dummy.m
│ ├── FTPickerView-prefix.pch
│ ├── FTPickerView-umbrella.h
│ ├── FTPickerView.modulemap
│ ├── FTPickerView.xcconfig
│ └── Info.plist
│ ├── Kingfisher
│ ├── Info.plist
│ ├── Kingfisher-dummy.m
│ ├── Kingfisher-prefix.pch
│ ├── Kingfisher-umbrella.h
│ ├── Kingfisher.modulemap
│ └── Kingfisher.xcconfig
│ └── Pods-Demo
│ ├── Info.plist
│ ├── Pods-Demo-acknowledgements.markdown
│ ├── Pods-Demo-acknowledgements.plist
│ ├── Pods-Demo-dummy.m
│ ├── Pods-Demo-frameworks.sh
│ ├── Pods-Demo-resources.sh
│ ├── Pods-Demo-umbrella.h
│ ├── Pods-Demo.debug.xcconfig
│ ├── Pods-Demo.modulemap
│ └── Pods-Demo.release.xcconfig
├── FTChatMessage.mdj
├── FTChatMessage
├── FTChatMessageCell
│ ├── .DS_Store
│ ├── FTChatMessageBubbleItem
│ │ ├── FTChatMessageBubbleAudioItem.swift
│ │ ├── FTChatMessageBubbleImageItem.swift
│ │ ├── FTChatMessageBubbleItem.swift
│ │ ├── FTChatMessageBubbleLocationItem.swift
│ │ ├── FTChatMessageBubbleTextItem.swift
│ │ └── FTChatMessageBubbleVideoItem.swift
│ ├── FTChatMessageCell.swift
│ └── FTChatMessageDeliverStatusView.swift
├── FTChatMessageConversation.swift
├── FTChatMessageDataSource.swift
├── FTChatMessageDelegate.swift
├── FTChatMessageExtensions.swift
├── FTChatMessageHeader
│ └── FTChatMessageHeader.swift
├── FTChatMessageInput
│ ├── FTChatMessageAccessoryItem.swift
│ ├── FTChatMessageAccessoryItem.xib
│ ├── FTChatMessageAccessoryView.swift
│ ├── FTChatMessageAccessoryView.xib
│ ├── FTChatMessageInputView.swift
│ ├── FTChatMessageInputView.xib
│ ├── FTChatMessageRecorderView.swift
│ └── FTChatMessageRecorderView.xib
├── FTChatMessageMarcos.swift
├── FTChatMessageModel.swift
├── FTChatMessageTableViewController+DataSource.swift
├── FTChatMessageTableViewController.swift
└── FTChatMessageUserModel.swift
├── LICENSE
├── README.md
└── ResourceImages
├── 1.jpg
├── 2.jpg
├── 3.jpg
└── ChatMessageDemo.gif
/.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 | .DS_Store
9 |
10 | ## Various settings
11 | *.pbxuser
12 | !default.pbxuser
13 | *.mode1v3
14 | !default.mode1v3
15 | *.mode2v3
16 | !default.mode2v3
17 | *.perspectivev3
18 | !default.perspectivev3
19 | xcuserdata/
20 |
21 | ## Other
22 | *.moved-aside
23 | *.xcuserstate
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | .build/
40 |
41 | # CocoaPods
42 | #
43 | # We recommend against adding the Pods directory to your .gitignore. However
44 | # you should judge for yourself, the pros and cons are mentioned at:
45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
46 | #
47 | # Pods/
48 |
49 | # Carthage
50 | #
51 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
52 | # Carthage/Checkouts
53 |
54 | Carthage/Build
55 |
56 | # fastlane
57 | #
58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
59 | # screenshots whenever they are needed.
60 | # For more information about the recommended setup visit:
61 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
62 |
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language : swift
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # FTChatMessage CHANGELOG
2 |
3 |
4 | |Date|CHANGELOG|
5 | |:------:|:------|
6 | | 2016.04.06 | now supports images |
7 | | 2016.04.08 | add time and sender name support |
8 | | 2016.04.09 | change input bar into UIToolBar instead of UIView |
9 | | 2016.04.12 | it's getting better |
10 | | 2016.04.19 | I have been busy. |
11 | | 2016.04.20 | add record view. functions and animations not ready. |
12 | | 2016.04.26 | switch input view done ! |
13 | | 2016.04.27 | add deliver status and finish accessory view ! it's 4.28 now... |
14 | | 2016.05.02 | Audio! |
15 | | 2016.05.08 | fix something, test something |
16 | | 2016.08.08 | not doing anything. if anyone want use it, I will try finish it. |
17 | | 2016.08.21 | rewriting some module |
18 | | 2016.08.22 | rewriting some module, make some of the view with xib |
19 | | 2016.08.23 | Move repo |
20 | | 2016.09.08 | simplify some methods |
21 | | 2016.10.05 | add some methods and I really wanna rewrite this. I will maybe do this in the near future. |
22 | | 2018.05.14 | update |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Demo.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demo/Demo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/Demo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 2016/9/22.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 |
19 |
20 | return true
21 | }
22 |
23 | func applicationWillResignActive(_ application: UIApplication) {
24 | // 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.
25 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
26 | }
27 |
28 | func applicationDidEnterBackground(_ application: UIApplication) {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | func applicationWillEnterForeground(_ application: UIApplication) {
34 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | func applicationDidBecomeActive(_ application: UIApplication) {
38 | // 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.
39 | }
40 |
41 | func applicationWillTerminate(_ application: UIApplication) {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 |
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/.DS_Store
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Alarm.imageset/Alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Alarm.imageset/Alarm.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Alarm.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Alarm.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/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 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Camera.imageset/Camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Camera.imageset/Camera.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Camera.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Camera.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Contacts.imageset/Contacts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Contacts.imageset/Contacts.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Contacts.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Contacts.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/FT_Add.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "FT_Add@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 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/FT_Add.imageset/FT_Add@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/FT_Add.imageset/FT_Add@2x.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/FT_Error.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "FT_Error@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 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/FT_Error.imageset/FT_Error@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/FT_Error.imageset/FT_Error@2x.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/FT_Record.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "FT_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 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/FT_Record.imageset/FT_Record@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/FT_Record.imageset/FT_Record@2x.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Mail.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Mail.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Mail.imageset/Mail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Mail.imageset/Mail.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Media_Pause.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Media_Pause.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Media_Pause.imageset/Media_Pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Media_Pause.imageset/Media_Pause.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Media_Play.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Media_Play.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Media_Play.imageset/Media_Play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Media_Play.imageset/Media_Play.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Messages.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Messages.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Messages.imageset/Messages.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Messages.imageset/Messages.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Music.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Music.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Music.imageset/Music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Music.imageset/Music.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Phone.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Phone.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Phone.imageset/Phone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Phone.imageset/Phone.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Photos.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Photos.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Photos.imageset/Photos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Photos.imageset/Photos.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Settings.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Settings.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Settings.imageset/Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Settings.imageset/Settings.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/VideoChat.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Videocamera.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/VideoChat.imageset/Videocamera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/VideoChat.imageset/Videocamera.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Videos.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Videos.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Videos.imageset/Videos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Videos.imageset/Videos.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Voice_Record.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Voice_Record.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Voice_Record.imageset/Voice_Record.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Voice_Record.imageset/Voice_Record.png
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Weather.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Weather.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Assets.xcassets/Weather.imageset/Weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Assets.xcassets/Weather.imageset/Weather.png
--------------------------------------------------------------------------------
/Demo/Demo/Base.lproj/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/Base.lproj/.DS_Store
--------------------------------------------------------------------------------
/Demo/Demo/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Demo/Demo/ChatRoomTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatTableViewCell.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/3/27.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ChatRoomTableViewCell: UITableViewCell {
12 |
13 | @IBOutlet weak var iconImageView: UIImageView!
14 | @IBOutlet weak var nameLabel: UILabel!
15 | @IBOutlet weak var contentLabel: UILabel!
16 |
17 | override func awakeFromNib() {
18 | super.awakeFromNib()
19 |
20 | }
21 |
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/Demo/Demo/ChatRoomViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/15.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import FTIndicator
11 |
12 |
13 | class ChatRoomViewController: UIViewController, UITableViewDelegate,UITableViewDataSource{
14 |
15 | @IBOutlet weak var chatListTableView: UITableView!
16 | var messageArray : [FTChatMessageModel] = []
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | self.navigationItem.hidesBackButton = true
21 |
22 | self.chatListTableView.addSubview(refreshControl);
23 |
24 | }
25 | override func viewDidAppear(_ animated: Bool) {
26 | super.viewDidAppear(animated)
27 |
28 | self.reloadConversations()
29 | }
30 |
31 | func reloadConversations() {
32 | self.chatListTableView.reloadData()
33 | }
34 |
35 |
36 |
37 | lazy var refreshControl : UIRefreshControl = {
38 | let refresh : UIRefreshControl = UIRefreshControl.init(frame: CGRect.init(x: 0, y: 0, width: self.view.frame.width, height: 60))
39 | refresh.addTarget(self, action: #selector(self.onPullToRefreshTriggered), for: UIControlEvents.valueChanged)
40 | return refresh;
41 | }()
42 |
43 | @IBAction func onPullToRefreshTriggered() {
44 | self.reloadConversations()
45 | DispatchQueue.main.asyncAfter( deadline: DispatchTime.now() + Double(Int64(2 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) {
46 | self.refreshControl.endRefreshing()
47 | }
48 | }
49 |
50 |
51 | @IBAction func addItemAction(_ sender: UIBarButtonItem) {
52 | self.performSegue(withIdentifier: "ChooseContactsToChat", sender: self)
53 | }
54 |
55 | /* UITableViewDelegate,UITableViewDataSource */
56 |
57 | func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
58 | return 0.01
59 | }
60 | func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
61 | return 0.01
62 | }
63 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
64 | return 1
65 | }
66 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
67 | let cell : ChatRoomTableViewCell = tableView.dequeueReusableCell(withIdentifier: "ChatRoomTableViewCellIndentifier") as! ChatRoomTableViewCell
68 | return cell
69 | }
70 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
71 | tableView.deselectRow(at: indexPath, animated: true)
72 |
73 | self.didTappedCell(at: indexPath)
74 | }
75 |
76 | func didTappedCell(at indexPath: IndexPath) {
77 |
78 | let chat : ChatTableViewController = self.storyboard?.instantiateViewController(withIdentifier: "ChatTableViewController") as! ChatTableViewController
79 |
80 | self.navigationController?.pushViewController(chat, animated: true)
81 |
82 | }
83 |
84 |
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/Demo/Demo/ChatTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChatTableViewController.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/28.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import FTIndicator
11 |
12 | class ChatTableViewController: FTChatMessageTableViewController,FTChatMessageAccessoryViewDelegate,FTChatMessageAccessoryViewDataSource,FTChatMessageRecorderViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate{
13 |
14 | let sender1 = FTChatMessageUserModel.init(id: "1", name: "Someone", icon_url: "http://ww3.sinaimg.cn/mw600/6cca1403jw1f3lrknzxczj20gj0g0t96.jpg", extra_data: nil, isSelf: false)
15 |
16 |
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | self.navigationItem.setRightBarButton(UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.add, target: self, action: #selector(self.addNewIncomingMessage)), animated: true)
22 |
23 | messageRecordView.recorderDelegate = self
24 | messageAccessoryView.setupWithDataSource(self , accessoryViewDelegate : self)
25 |
26 | chatMessageDataArray = self.loadDefaultMessages()
27 |
28 | }
29 |
30 | //MARK: - addNewIncomingMessage
31 |
32 | @objc func addNewIncomingMessage() {
33 |
34 | let message8 = FTChatMessageModel(data: "New Message added, try something else.", time: "4.12 22:42", from: sender1, type: .text)
35 | self.addNewMessage(message8)
36 |
37 | }
38 |
39 | func loadDefaultMessages() -> [FTChatMessageModel] {
40 |
41 | let message1 = FTChatMessageModel(data: "最近有点无聊,抽点时间写了这个聊天的UI框架。", time: "4.12 21:09:50", from: sender1, type: .text)
42 | let message2 = FTChatMessageModel(data: "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈", time: "4.12 21:09:51", from: sender1, type: .video)
43 | let message3 = FTChatMessageImageModel(data: "http://ww2.sinaimg.cn/mw600/6aa09e8fgw1f8iquoznw2j20dw0bv0uk.jpg", time: "4.12 21:09:52", from: sender1, type: .image)
44 | message3.imageUrl = "http://ww2.sinaimg.cn/mw600/6aa09e8fgw1f8iquoznw2j20dw0bv0uk.jpg"
45 |
46 |
47 | let message4 = FTChatMessageModel(data: "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈", time: "4.12 21:09:53", from: sender2, type: .text)
48 | let message5 = FTChatMessageModel(data: "文字背景不是图片,是用贝塞尔曲线画的,效率应该不高,后期优化", time: "4.12 21:09:53", from: sender2, type: .text)
49 | let message6 = FTChatMessageModel(data: "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈", time: "4.12 21:09:54", from: sender2, type: .text)
50 | let message8 = FTChatMessageImageModel(data: "http://wx3.sinaimg.cn/mw600/9e745efdly1fbmfs45minj20tg0xcq6v.jpg", time: "4.12 21:09:56", from: sender1, type: .image)
51 | message8.imageUrl = "http://wx3.sinaimg.cn/mw600/9e745efdly1fbmfs45minj20tg0xcq6v.jpg"
52 |
53 |
54 | let message7 = FTChatMessageModel(data: "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈", time: "4.12 21:09:55", from: sender1, type: .text)
55 |
56 |
57 | let array = [message1,message2,message3,message4,message5,message6,message8,message7]
58 |
59 | return array;
60 |
61 | }
62 |
63 |
64 | func getAccessoryItemTitleArray() -> [String] {
65 | return ["Alarm","Camera","Contacts","Mail","Messages","Music","Phone","Photos","Settings","VideoChat","Videos","Weather"]
66 | }
67 |
68 |
69 | //MARK: - FTChatMessageAccessoryViewDataSource
70 |
71 | func ftChatMessageAccessoryViewModelArray() -> [FTChatMessageAccessoryViewModel] {
72 | var array : [FTChatMessageAccessoryViewModel] = []
73 | let titleArray = self.getAccessoryItemTitleArray()
74 | for i in 0...titleArray.count-1 {
75 | let string = titleArray[i]
76 | array.append(FTChatMessageAccessoryViewModel.init(title: string, iconImage: UIImage(named: string)!))
77 | }
78 | return array
79 | }
80 |
81 | //MARK: - FTChatMessageAccessoryViewDelegate
82 |
83 | func ftChatMessageAccessoryViewDidTappedOnItemAtIndex(_ index: NSInteger) {
84 |
85 | if index == 0 {
86 |
87 | let imagePicker : UIImagePickerController = UIImagePickerController()
88 | imagePicker.sourceType = .photoLibrary
89 | imagePicker.delegate = self
90 | self.present(imagePicker, animated: true, completion: {
91 |
92 | })
93 | }else{
94 | let string = "I just tapped at accessory view at index : \(index)"
95 |
96 | print(string)
97 |
98 | // FTIndicator.showInfo(withMessage: string)
99 |
100 | let message2 = FTChatMessageModel(data: string, time: "4.12 21:09:51", from: sender2, type: .text)
101 |
102 | self.addNewMessage(message2)
103 | }
104 | }
105 |
106 | //MARK: - FTChatMessageRecorderViewDelegate
107 |
108 | func ft_chatMessageRecordViewDidStartRecording(){
109 | print("Start recording...")
110 | FTIndicator.showProgress(withMessage: "Recording...")
111 | }
112 | func ft_chatMessageRecordViewDidCancelRecording(){
113 | print("Recording canceled.")
114 | FTIndicator.dismissProgress()
115 | }
116 | func ft_chatMessageRecordViewDidStopRecording(_ duriation: TimeInterval, file: Data?){
117 | print("Recording ended!")
118 | FTIndicator.showSuccess(withMessage: "Record done.")
119 |
120 | let message2 = FTChatMessageModel(data: "", time: "4.12 21:09:51", from: sender2, type: .audio)
121 |
122 | self.addNewMessage(message2)
123 |
124 | }
125 |
126 |
127 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
128 |
129 | picker.dismiss(animated: true) {
130 |
131 | let image : UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
132 | let message2 = FTChatMessageImageModel(data: "", time: "4.12 21:09:51", from: self.sender2, type: .image)
133 | message2.image = image;
134 | self.addNewMessage(message2)
135 | }
136 | }
137 |
138 | func saveImageToDisk(image: UIImage) -> String {
139 |
140 |
141 | return ""
142 | }
143 |
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/Demo/Demo/ContactsTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContactsTableViewCell.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 2016/10/20.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ContactsTableViewCell: UITableViewCell {
12 |
13 | @IBOutlet weak var iconImageView: UIImageView!
14 | @IBOutlet weak var nameLabel: UILabel!
15 |
16 | // open func setupWithUser(user : NIMUser) {
17 | // if let iconUrl : String = user.userInfo?.avatarUrl {
18 | // self.iconImageView.kf.setImage(with: URL(string: iconUrl)!)
19 | // }
20 | // self.nameLabel.text = user.userInfo?.nickName
21 | // }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Demo/Demo/ContactsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContactsViewController.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 2016/10/20.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ContactsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
12 |
13 | @IBOutlet weak var tableView: UITableView!
14 | @IBOutlet weak var searchBar: UISearchBar!
15 |
16 |
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 |
22 |
23 | }
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | /* UITableViewDelegate,UITableViewDataSource */
32 |
33 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
34 | return 2
35 | }
36 | func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
37 | return 0.01
38 | }
39 | func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
40 | return 0.01
41 | }
42 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
43 | return 70
44 | }
45 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
46 | let cell : ContactsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "ContactsTableViewCellIdentifier") as! ContactsTableViewCell
47 | return cell
48 | }
49 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
50 | tableView.deselectRow(at: indexPath, animated: true)
51 |
52 | self.didTappedCell(at: indexPath)
53 | }
54 |
55 | func didTappedCell(at indexPath: IndexPath) {
56 |
57 | let chat : ChatTableViewController = self.storyboard?.instantiateViewController(withIdentifier: "ChatTableViewController") as! ChatTableViewController
58 |
59 | self.navigationController?.pushViewController(chat, animated: true)
60 |
61 | }
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/Demo/Demo/Demo-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/Demo/Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | FTChaMessage
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.0.1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | NSPhotoLibraryUsageDescription
31 | $(PRODUCT_BUNDLE_IDENTIFIER) would like to use your photo library.
32 | UILaunchStoryboardName
33 | LaunchScreen
34 | UIMainStoryboardFile
35 | Main
36 | UIRequiredDeviceCapabilities
37 |
38 | armv7
39 |
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 |
44 | UISupportedInterfaceOrientations~ipad
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationPortraitUpsideDown
48 | UIInterfaceOrientationLandscapeLeft
49 | UIInterfaceOrientationLandscapeRight
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Demo/Demo/SignInViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SignInViewController.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 2016/10/18.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import FTIndicator
11 | import FTPickerView
12 |
13 | class SignInViewController: UIViewController {
14 |
15 | @IBOutlet weak var accountTextField: UITextField!
16 | @IBOutlet weak var passwordTextField: UITextField!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | self.accountTextField.text = "liufengting"
22 | self.passwordTextField.text = "123456"
23 |
24 |
25 | }
26 |
27 | var accounts : [String] = ["liufengting",
28 | "123456",
29 | "Test01",
30 | "Test02",
31 | "Test03",
32 | "Test04",
33 | "Test05"]
34 |
35 |
36 | @IBAction func chooseAccountAction(_ sender: UIButton) {
37 | FTPickerView.show(withTitle: "Choose account",
38 | nameArray: self.accounts,
39 | doneBlock: { (selectedIndex) in
40 | self.accountTextField.text = self.accounts[selectedIndex]
41 | }) {
42 |
43 | }
44 | }
45 |
46 | @IBAction func signInAction(_ sender: UIButton) {
47 |
48 |
49 | // if self.accountTextField.text == "" {
50 | // return;
51 | // }
52 | // if self.passwordTextField.text == "" {
53 | // return;
54 | // }
55 | // self.view.endEditing(true)
56 | //
57 | // FTIndicator.showProgressWithmessage("Signing in...", userInteractionEnable:false)
58 | //
59 | // NIMSDK.shared().loginManager.login(self.accountTextField.text!, token: (self.passwordTextField.text! as NSString).tokenByPassword()) { (error) in
60 | // if (error != nil) {
61 | // FTIndicator.showError(withMessage: "Sign in failed with code:\((error! as NSError).code)")
62 | // }else{
63 | // FTIndicator.showSuccess(withMessage: "Sign in succeeded.");
64 | //
65 | // DispatchQueue.main.asyncAfter( deadline: DispatchTime.now() + Double(Int64(1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) {
66 | self.performSegue(withIdentifier: "SigninToHome", sender: self)
67 | // }
68 | // }
69 | // }
70 | }
71 |
72 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
73 | self.view.endEditing(true)
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/Demo/Demo/dog.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/dog.jpg
--------------------------------------------------------------------------------
/Demo/Demo/pinyin.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Demo/pinyin.bin
--------------------------------------------------------------------------------
/Demo/Podfile:
--------------------------------------------------------------------------------
1 | use_frameworks!
2 |
3 | target 'Demo' do
4 |
5 | pod 'Kingfisher'
6 | pod 'FTIndicator'
7 | pod 'FTPickerView'
8 | pod 'FTImageSize'
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/Demo/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FTImageSize (0.0.4)
3 | - FTIndicator (1.2.9):
4 | - FTIndicator/FTNotificationIndicator (= 1.2.9)
5 | - FTIndicator/FTProgressIndicator (= 1.2.9)
6 | - FTIndicator/FTToastIndicator (= 1.2.9)
7 | - FTIndicator/FTNotificationIndicator (1.2.9)
8 | - FTIndicator/FTProgressIndicator (1.2.9)
9 | - FTIndicator/FTToastIndicator (1.2.9)
10 | - FTPickerView (1.0.2)
11 | - Kingfisher (4.7.0)
12 |
13 | DEPENDENCIES:
14 | - FTImageSize
15 | - FTIndicator
16 | - FTPickerView
17 | - Kingfisher
18 |
19 | SPEC CHECKSUMS:
20 | FTImageSize: 29c6fc0830dbe33973286148a8e32cd582a9f26d
21 | FTIndicator: f7f071fd159e5befa1d040a9ef2e3ab53fa9322c
22 | FTPickerView: 3fb6055e057ac608435ce7d938f2bbc0640f4948
23 | Kingfisher: da6b005aa96d37698e3e4f1ccfe96a5b9bbf27d6
24 |
25 | PODFILE CHECKSUM: 0897bbd78b2258d0c7f01ee2e9d5eb5a802cde17
26 |
27 | COCOAPODS: 1.4.0
28 |
--------------------------------------------------------------------------------
/Demo/Pods/FTImageSize/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Liu Fengting
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Demo/Pods/FTImageSize/README.md:
--------------------------------------------------------------------------------
1 | # FTImageSize
2 | FTImageSize
3 |
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTIndicator.m:
--------------------------------------------------------------------------------
1 | //
2 | // FTIndicator.m
3 | // FTIndicator
4 | //
5 | // Created by liufengting on 16/7/21.
6 | // Copyright © 2016年 liufengting ( https://github.com/liufengting ). All rights reserved.
7 | //
8 |
9 | #import "FTIndicator.h"
10 |
11 | @interface FTIndicator ()
12 |
13 | @end
14 |
15 | @implementation FTIndicator
16 |
17 | + (void)setIndicatorStyleToDefaultStyle
18 | {
19 | [self setIndicatorStyle:UIBlurEffectStyleLight];
20 | }
21 |
22 | + (void)setIndicatorStyle:(UIBlurEffectStyle)style
23 | {
24 | [FTToastIndicator setToastIndicatorStyle:style];
25 | [FTProgressIndicator setProgressIndicatorStyle:style];
26 | [FTNotificationIndicator setNotificationIndicatorStyle:style];
27 | }
28 |
29 | #pragma mark - FTToastIndicator
30 | /**
31 | * FTToastIndicator
32 | */
33 | + (void)showToastMessage:(NSString *)toastMessage
34 | {
35 | [FTToastIndicator showToastMessage:toastMessage];
36 | }
37 |
38 | + (void)dismissToast
39 | {
40 | [FTToastIndicator dismiss];
41 | }
42 |
43 |
44 | #pragma mark - FTProgressIndicator
45 | /**
46 | * FTProgressIndicator
47 | */
48 | + (void)showProgressWithMessage:(NSString *)message
49 | {
50 | [self showProgressWithMessage:message userInteractionEnable:YES];
51 | }
52 | + (void)showProgressWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable
53 | {
54 | [FTProgressIndicator showProgressWithMessage:message userInteractionEnable:userInteractionEnable];
55 | }
56 |
57 |
58 | + (void)showInfoWithMessage:(NSString *)message
59 | {
60 | [self showInfoWithMessage:message image:nil userInteractionEnable:YES];
61 | }
62 | + (void)showInfoWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable
63 | {
64 | [self showInfoWithMessage:message image:nil userInteractionEnable:userInteractionEnable];
65 | }
66 | + (void)showInfoWithMessage:(NSString *)message image:(UIImage *)image userInteractionEnable:(BOOL)userInteractionEnable
67 | {
68 | [FTProgressIndicator showInfoWithMessage:message image:image userInteractionEnable:userInteractionEnable];
69 | }
70 |
71 |
72 | + (void)showSuccessWithMessage:(NSString *)message
73 | {
74 | [self showSuccessWithMessage:message image:nil userInteractionEnable:YES];
75 | }
76 | + (void)showSuccessWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable
77 | {
78 | [self showSuccessWithMessage:message image:nil userInteractionEnable:userInteractionEnable];
79 | }
80 | + (void)showSuccessWithMessage:(NSString *)message image:(UIImage *)image userInteractionEnable:(BOOL)userInteractionEnable
81 | {
82 | [FTProgressIndicator showSuccessWithMessage:message image:image userInteractionEnable:userInteractionEnable];
83 | }
84 |
85 |
86 | + (void)showErrorWithMessage:(NSString *)message
87 | {
88 | [self showErrorWithMessage:message image:nil userInteractionEnable:YES];
89 | }
90 | + (void)showErrorWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable
91 | {
92 | [self showErrorWithMessage:message image:nil userInteractionEnable:userInteractionEnable];
93 | }
94 | + (void)showErrorWithMessage:(NSString *)message image:(UIImage *)image userInteractionEnable:(BOOL)userInteractionEnable
95 | {
96 | [FTProgressIndicator showErrorWithMessage:message image:image userInteractionEnable:userInteractionEnable];
97 | }
98 |
99 |
100 | + (void)dismissProgress
101 | {
102 | [FTProgressIndicator dismiss];
103 | }
104 |
105 | #pragma mark - FTNotificationIndicator
106 | /**
107 | * FTNotificationIndicator
108 | */
109 | + (void)showNotificationWithTitle:(NSString *)title message:(NSString *)message
110 | {
111 | [self showNotificationWithImage:nil title:title message:message autoDismiss:YES tapHandler:nil completion:nil];
112 | }
113 |
114 | + (void)showNotificationWithTitle:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler
115 | {
116 | [self showNotificationWithImage:nil title:title message:message autoDismiss:YES tapHandler:tapHandler completion:nil];
117 | }
118 |
119 | + (void)showNotificationWithTitle:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler completion:(FTNotificationCompletion)completion
120 | {
121 | [self showNotificationWithImage:nil title:title message:message autoDismiss:YES tapHandler:tapHandler completion:completion];
122 | }
123 |
124 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message
125 | {
126 | [self showNotificationWithImage:image title:title message:message autoDismiss:YES tapHandler:nil completion:nil];
127 | }
128 |
129 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler
130 | {
131 | [self showNotificationWithImage:image title:title message:message autoDismiss:YES tapHandler:tapHandler completion:nil];
132 | }
133 |
134 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler completion:(FTNotificationCompletion)completion
135 | {
136 | [self showNotificationWithImage:image title:title message:message autoDismiss:YES tapHandler:tapHandler completion:completion];
137 | }
138 |
139 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message autoDismiss:(BOOL)autoDismiss tapHandler:(FTNotificationTapHandler)tapHandler completion:(FTNotificationCompletion)completion
140 | {
141 | [FTNotificationIndicator showNotificationWithImage:image title:title message:message autoDismiss:autoDismiss tapHandler:tapHandler completion:completion];
142 | }
143 |
144 | + (void)dismissNotification
145 | {
146 | [FTNotificationIndicator dismiss];
147 | }
148 |
149 | @end
150 |
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTNotificationIndicator/FTNotificationIndicator.h:
--------------------------------------------------------------------------------
1 | //
2 | // FTNotificationIndicator.h
3 | // FTIndicator
4 | //
5 | // Created by liufengting on 16/7/26.
6 | // Copyright © 2016年 liufengting ( https://github.com/liufengting ). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #pragma mark - FTNotificationIndicator
12 |
13 | typedef void (^FTNotificationTapHandler)(void);
14 | typedef void (^FTNotificationCompletion)(void);
15 |
16 | /**
17 | FTNotificationIndicator
18 | */
19 | @interface FTNotificationIndicator : NSObject
20 |
21 | /**
22 | setIndicatorStyleToDefaultStyle
23 | */
24 | + (void)setNotificationIndicatorStyleToDefaultStyle;
25 | /**
26 | setIndicatorStyle
27 |
28 | @param style style
29 | */
30 | + (void)setNotificationIndicatorStyle:(UIBlurEffectStyle)style;
31 | /**
32 | showNotificationWithTitle message
33 |
34 | @param title title
35 | @param message message
36 | */
37 | + (void)showNotificationWithTitle:(NSString *)title message:(NSString *)message;
38 | /**
39 | showNotificationWithTitle message tapHandler
40 |
41 | @param title title
42 | @param message message
43 | @param tapHandler tapHandler
44 | */
45 | + (void)showNotificationWithTitle:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler;
46 | /**
47 | showNotificationWithTitle message tapHandler completion
48 |
49 | @param title title
50 | @param message message
51 | @param tapHandler tapHandler
52 | @param completion completion
53 | */
54 | + (void)showNotificationWithTitle:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler completion:(FTNotificationCompletion)completion;
55 | /**
56 | showNotificationWithImage title message
57 |
58 | @param image image
59 | @param title title
60 | @param message message
61 | */
62 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message;
63 | /**
64 | showNotificationWithImage title message tapHandler
65 |
66 | @param image image
67 | @param title title
68 | @param message message
69 | @param tapHandler tapHandler
70 | */
71 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler;
72 | /**
73 | showNotificationWithImage title message tapHandler completion
74 |
75 |
76 | @param image image
77 | @param title title
78 | @param message message
79 | @param tapHandler tapHandler
80 | @param completion completion
81 | */
82 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message tapHandler:(FTNotificationTapHandler)tapHandler completion:(FTNotificationCompletion)completion;
83 |
84 |
85 | /**
86 | showNotificationWithImage title message autoDismiss tapHandler completion
87 |
88 | !!!!!!!!! Only this method suports not dismiss automatically, user has to tap or swipe to dismiss.
89 |
90 | @param image image
91 | @param title title
92 | @param message message
93 | @param autoDismiss autoDismiss
94 | @param tapHandler tapHandler
95 | @param completion completion
96 | */
97 | + (void)showNotificationWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message autoDismiss:(BOOL)autoDismiss tapHandler:(FTNotificationTapHandler)tapHandler completion:(FTNotificationCompletion)completion;
98 | /**
99 | dismiss
100 | */
101 | + (void)dismiss;
102 |
103 |
104 | /**
105 | Default delay until dismiss notification
106 |
107 | @param time Delay in seconds
108 | */
109 | + (void)setDefaultDismissTime:(NSTimeInterval)time;
110 |
111 |
112 | /**
113 | Default delay until dismiss notification
114 |
115 | @return Delay in seconds
116 | */
117 | + (NSTimeInterval)defaultDismissTime;
118 |
119 | @end
120 |
121 | #pragma mark - FTNotificationIndicatorView
122 |
123 | /**
124 | FTNotificationIndicatorView
125 | */
126 | @interface FTNotificationIndicatorView : UIVisualEffectView
127 | /**
128 | showWithImage
129 |
130 | @param image image
131 | @param title title
132 | @param message message
133 | @param style style
134 | */
135 | - (void)showWithImage:(UIImage *)image title:(NSString *)title message:(NSString *)message style:(UIBlurEffectStyle)style;
136 | /**
137 | getFrameForNotificationViewWithImage
138 |
139 | @param image image
140 | @param notificationMessage message
141 | @return CGSize
142 | */
143 | - (CGSize )getFrameForNotificationViewWithImage:(UIImage *)image message:(NSString *)notificationMessage;
144 |
145 | @end
146 |
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_failure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_failure.png
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_failure_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_failure_dark.png
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_info.png
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_info_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_info_dark.png
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_success.png
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_success_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.bundle/ft_success_dark.png
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTProgressIndicator/FTProgressIndicator.h:
--------------------------------------------------------------------------------
1 | //
2 | // FTProgressIndicator.h
3 | // FTIndicator
4 | //
5 | // Created by liufengting on 16/7/26.
6 | // Copyright © 2016年 liufengting ( https://github.com/liufengting ). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #pragma mark - FTProgressIndicatorMessageType
12 |
13 | /**
14 | FTProgressIndicatorMessageType
15 |
16 | - FTProgressIndicatorMessageTypeInfo: FTProgressIndicatorMessageTypeInfo
17 | - FTProgressIndicatorMessageTypeSuccess: FTProgressIndicatorMessageTypeSuccess
18 | - FTProgressIndicatorMessageTypeError: FTProgressIndicatorMessageTypeError
19 | - FTProgressIndicatorMessageTypeProgress: FTProgressIndicatorMessageTypeProgress
20 | */
21 | typedef NS_ENUM(NSUInteger, FTProgressIndicatorMessageType) {
22 | FTProgressIndicatorMessageTypeInfo,
23 | FTProgressIndicatorMessageTypeSuccess,
24 | FTProgressIndicatorMessageTypeError,
25 | FTProgressIndicatorMessageTypeProgress
26 | };
27 |
28 | #pragma mark - FTProgressIndicator
29 | /**
30 | FTProgressIndicator
31 | */
32 | @interface FTProgressIndicator : NSObject
33 |
34 | /**
35 | showProgressWithMessage
36 |
37 | @param message message
38 | */
39 | + (void)showProgressWithMessage:(NSString *)message;
40 |
41 | /**
42 | showProgressWithMessage userInteractionEnable
43 |
44 | @param message message
45 | @param userInteractionEnable userInteractionEnable
46 | */
47 | + (void)showProgressWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable;
48 |
49 | /**
50 | showInfoWithMessage
51 |
52 | @param message message
53 | */
54 | + (void)showInfoWithMessage:(NSString *)message;
55 |
56 | /**
57 | showInfoWithMessage userInteractionEnable
58 |
59 | @param message message
60 | @param userInteractionEnable userInteractionEnable
61 | */
62 | + (void)showInfoWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable;
63 |
64 | /**
65 | showInfoWithMessage image userInteractionEnable
66 |
67 | @param message message
68 | @param image image
69 | @param userInteractionEnable userInteractionEnable
70 | */
71 | + (void)showInfoWithMessage:(NSString *)message image:(UIImage *)image userInteractionEnable:(BOOL)userInteractionEnable;
72 |
73 | /**
74 | showSuccessWithMessage
75 |
76 | @param message message
77 | */
78 | + (void)showSuccessWithMessage:(NSString *)message;
79 |
80 | /**
81 | showSuccessWithMessage userInteractionEnable
82 |
83 | @param message message
84 | @param userInteractionEnable userInteractionEnable
85 | */
86 | + (void)showSuccessWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable;
87 |
88 | /**
89 | showSuccessWithMessage image userInteractionEnable
90 |
91 | @param message message
92 | @param image image
93 | @param userInteractionEnable userInteractionEnable
94 | */
95 | + (void)showSuccessWithMessage:(NSString *)message image:(UIImage *)image userInteractionEnable:(BOOL)userInteractionEnable;
96 |
97 | /**
98 | showErrorWithMessage
99 |
100 | @param message message
101 | */
102 | + (void)showErrorWithMessage:(NSString *)message;
103 |
104 | /**
105 | showErrorWithMessage userInteractionEnable
106 |
107 | @param message message
108 | @param userInteractionEnable userInteractionEnable
109 | */
110 | + (void)showErrorWithMessage:(NSString *)message userInteractionEnable:(BOOL)userInteractionEnable;
111 |
112 | /**
113 | showErrorWithMessage image userInteractionEnable
114 |
115 | @param message message
116 | @param image image
117 | @param userInteractionEnable userInteractionEnable
118 | */
119 | + (void)showErrorWithMessage:(NSString *)message image:(UIImage *)image userInteractionEnable:(BOOL)userInteractionEnable;
120 |
121 | /**
122 | dismiss
123 | */
124 | + (void)dismiss;
125 |
126 | /**
127 | setProgressIndicatorStyleToDefaultStyle
128 | */
129 | + (void)setProgressIndicatorStyleToDefaultStyle;
130 |
131 | /**
132 | setProgressIndicatorStyle
133 |
134 | @param style style
135 | */
136 | + (void)setProgressIndicatorStyle:(UIBlurEffectStyle)style;
137 |
138 | @end
139 |
140 | #pragma mark - FTProgressIndicatorView
141 |
142 | /**
143 | FTProgressIndicatorView
144 | */
145 | @interface FTProgressIndicatorView : UIVisualEffectView
146 |
147 | /**
148 | userInteractionEnable, if allows user touches at view
149 | */
150 | @property (assign, nonatomic) BOOL userInteractionEnable;
151 |
152 | /**
153 | showProgressWithType
154 |
155 | @param type type
156 | @param message message
157 | @param image custom image
158 | @param style style
159 | @param userInteractionEnable userInteractionEnable
160 | */
161 | - (void)showProgressWithType:(FTProgressIndicatorMessageType )type message:(NSString *)message image:(UIImage *)image style:(UIBlurEffectStyle)style userInteractionEnable:(BOOL)userInteractionEnable;
162 |
163 | /**
164 | getFrameForProgressViewWithMessage
165 |
166 | @param progressMessage progressMessage
167 | @return CGSize
168 | */
169 | - (CGSize )getFrameForProgressViewWithMessage:(NSString *)progressMessage;
170 |
171 | @end
172 |
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/FTIndicator/FTToastIndicator/FTToastIndicator.h:
--------------------------------------------------------------------------------
1 | //
2 | // FTToastIndicator.h
3 | // FTIndicator
4 | //
5 | // Created by liufengting on 16/7/26.
6 | // Copyright © 2016年 liufengting ( https://github.com/liufengting ). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #pragma mark - FTToastIndicator
12 | /**
13 | FTToastIndicator
14 | */
15 | @interface FTToastIndicator : NSObject
16 | /**
17 | setIndicatorStyleToDefaultStyle
18 | */
19 | + (void)setToastIndicatorStyleToDefaultStyle;
20 | /**
21 | setIndicatorStyle
22 |
23 | @param style style
24 | */
25 | + (void)setToastIndicatorStyle:(UIBlurEffectStyle)style;
26 | /**
27 | showToastMessage
28 |
29 | @param toastMessage toastMessage
30 | */
31 | + (void)showToastMessage:(NSString *)toastMessage;
32 |
33 | /**
34 | dismiss
35 | */
36 | + (void)dismiss;
37 |
38 | @end
39 |
40 | #pragma mark - FTToastIndicatorView
41 |
42 | /**
43 | FTToastIndicatorView
44 | */
45 | @interface FTToastIndicatorView : UIVisualEffectView
46 | /**
47 | showToastMessage
48 |
49 | @param toastMessage toastMessage
50 | @param style style
51 | */
52 | - (void)showToastMessage:(NSString *)toastMessage withStyle:(UIBlurEffectStyle)style;
53 | /**
54 | getFrameForToastViewWithMessage
55 |
56 | @param toastMessage toastMessage
57 | @return CGSize
58 | */
59 | - (CGSize )getFrameForToastViewWithMessage:(NSString *)toastMessage;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/Demo/Pods/FTIndicator/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Liu Fengting
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Demo/Pods/FTPickerView/FTPickerView/FTPickerView.h:
--------------------------------------------------------------------------------
1 | //
2 | // FTPickerView.h
3 | // FTPickerView
4 | //
5 | // Created by liufengting https://github.com/liufengting on 15/12/3.
6 | // Copyright © 2015年 liufengting. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef void (^ FTPickerDoneBlock )(NSInteger selectedIndex);
12 | typedef void (^ FTPickerCancelBlock )(void);
13 | typedef void (^ FTDatePickerDoneBlock )(NSDate *selectedDate);
14 | typedef void (^ FTDatePickerCancelBlock )(void);
15 |
16 | /**
17 | * FTPickerTitleView
18 | */
19 |
20 | @interface FTPickerTitleView : UIView
21 |
22 | @end
23 |
24 | /**
25 | * FTPickerView
26 | */
27 |
28 | @interface FTPickerView : NSObject
29 |
30 | /**
31 | * show method
32 | *
33 | * @param title title
34 | * @param nameArray nameArray
35 | * @param doneBlock FTPickerDoneBlock
36 | * @param cancelBlock FTPickerCancelBlock
37 | */
38 | +(void)showWithTitle:(NSString *)title
39 | nameArray:(NSArray *)nameArray
40 | doneBlock :(FTPickerDoneBlock)doneBlock
41 | cancelBlock:(FTPickerCancelBlock)cancelBlock;
42 | /**
43 | * dismiss
44 | */
45 | +(void)dismiss;
46 |
47 | @end
48 |
49 | /**
50 | * FTDatePickerView
51 | */
52 |
53 | @interface FTDatePickerView : UIView
54 |
55 | /**
56 | * show method
57 | *
58 | * @param title title
59 | * @param doneBlock FTDatePickerDoneBlock
60 | * @param cancelBlock FTDatePickerCancelBlock
61 | */
62 | +(void)showWithTitle:(NSString *)title
63 | doneBlock :(FTDatePickerDoneBlock)doneBlock
64 | cancelBlock:(FTDatePickerCancelBlock)cancelBlock;
65 | /**
66 | * show method
67 | *
68 | * @param title title
69 | * @param selectDate selectDate
70 | * @param datePickerMode datePickerMode
71 | * @param doneBlock FTDatePickerDoneBlock
72 | * @param cancelBlock FTDatePickerCancelBlock
73 | */
74 | +(void)showWithTitle:(NSString *)title
75 | selectDate:(NSDate *)selectDate
76 | datePickerMode:(UIDatePickerMode )datePickerMode
77 | doneBlock :(FTDatePickerDoneBlock)doneBlock
78 | cancelBlock:(FTDatePickerCancelBlock)cancelBlock;
79 | /**
80 | * dismiss
81 | */
82 | +(void)dismiss;
83 |
84 | @end
85 |
--------------------------------------------------------------------------------
/Demo/Pods/FTPickerView/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 刘锋婷
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Demo/Pods/FTPickerView/README.md:
--------------------------------------------------------------------------------
1 | # FTPickerView
2 | [](http://twitter.com/liufengting)
3 | [](https://raw.githubusercontent.com/liufengting/FTPickerView/master/LICENSE)
4 | [](http://cocoapods.org/pods/FTPickerView)
5 | [](https://travis-ci.org/liufengting/FTPickerView)
6 | [](https://github.com/liufengting/FTPickerView/stargazers)
7 |
8 |
9 | A simple UIPickerView/UIDatePicker wrapper.
10 |
11 | ## Features
12 |
13 | - singleton
14 | - block callbacks
15 |
16 |
17 | ## ScreenShots
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | ## Useage
28 |
29 | * Simple Picker
30 |
31 | ```objective-c
32 | //simple picker
33 | [FTPickerView showWithTitle:@"Choose a step"
34 | nameArray:self.optionArrayOne
35 | doneBlock:^(NSInteger selectedIndex) {
36 | [sender setTitle:_optionArrayOne[selectedIndex] forState:UIControlStateNormal];
37 | } cancelBlock:^{
38 |
39 | }];
40 | ```
41 |
42 | * Date Picker
43 |
44 |
45 | ```objective-c
46 | //date picker
47 | [FTDatePickerView showWithTitle:@"Choose a date"
48 | selectDate:nil
49 | datePickerMode:UIDatePickerModeDateAndTime
50 | doneBlock:^(NSDate *selectedDate) {
51 | NSDateFormatter *dateFormate = [[NSDateFormatter alloc]init];
52 | [dateFormate setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
53 | [sender setTitle:[dateFormate stringFromDate:selectedDate] forState:UIControlStateNormal];
54 | } cancelBlock:^{
55 |
56 | }];
57 | ```
58 |
59 | # Installation
60 |
61 | ## Manual
62 | * Drag 'FTPickerView' file to you project,
63 | * Import 'FTPickerView.h',
64 | * Enjoy! 🍺
65 |
66 | ## Cocoapods
67 |
68 | * add the following line to you podFile,then `pod update`
69 |
70 | ```
71 | pod 'FTPickerView', '~> 0.1.1'
72 | ```
73 |
74 | ## License
75 |
76 | FTPickerView is available under the MIT license. See the LICENSE file for more info.
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Wei Wang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2018/3/17.
6 | // Copyright (c) 2018 Wei Wang
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 |
26 | import Foundation
27 |
28 | class Box {
29 | let value: T
30 |
31 | init(_ value: T) {
32 | self.value = value
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/CacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CacheSerializer.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/02.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// An `CacheSerializer` would be used to convert some data to an image object for
30 | /// retrieving from disk cache and vice versa for storing to disk cache.
31 | public protocol CacheSerializer {
32 |
33 | /// Get the serialized data from a provided image
34 | /// and optional original data for caching to disk.
35 | ///
36 | ///
37 | /// - parameter image: The image needed to be serialized.
38 | /// - parameter original: The original data which is just downloaded.
39 | /// If the image is retrieved from cache instead of
40 | /// downloaded, it will be `nil`.
41 | ///
42 | /// - returns: A data which will be stored to cache, or `nil` when no valid
43 | /// data could be serialized.
44 | func data(with image: Image, original: Data?) -> Data?
45 |
46 | /// Get an image deserialized from provided data.
47 | ///
48 | /// - parameter data: The data from which an image should be deserialized.
49 | /// - parameter options: Options for deserialization.
50 | ///
51 | /// - returns: An image deserialized or `nil` when no valid image
52 | /// could be deserialized.
53 | func image(with data: Data, options: KingfisherOptionsInfo?) -> Image?
54 | }
55 |
56 |
57 | /// `DefaultCacheSerializer` is a basic `CacheSerializer` used in default cache of
58 | /// Kingfisher. It could serialize and deserialize PNG, JEPG and GIF images. For
59 | /// image other than these formats, a normalized `pngRepresentation` will be used.
60 | public struct DefaultCacheSerializer: CacheSerializer {
61 |
62 | public static let `default` = DefaultCacheSerializer()
63 | private init() {}
64 |
65 | public func data(with image: Image, original: Data?) -> Data? {
66 | let imageFormat = original?.kf.imageFormat ?? .unknown
67 |
68 | let data: Data?
69 | switch imageFormat {
70 | case .PNG: data = image.kf.pngRepresentation()
71 | case .JPEG: data = image.kf.jpegRepresentation(compressionQuality: 1.0)
72 | case .GIF: data = image.kf.gifRepresentation()
73 | case .unknown: data = original ?? image.kf.normalized.kf.pngRepresentation()
74 | }
75 |
76 | return data
77 | }
78 |
79 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
80 | let options = options ?? KingfisherEmptyOptionsInfo
81 | return Kingfisher.image(
82 | data: data,
83 | scale: options.scaleFactor,
84 | preloadAllAnimationData: options.preloadAllAnimationData,
85 | onlyFirstFrame: options.onlyLoadFirstFrame)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Filter.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/08/31.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 |
28 |
29 | import CoreImage
30 | import Accelerate
31 |
32 | // Reuse the same CI Context for all CI drawing.
33 | private let ciContext = CIContext(options: nil)
34 |
35 | /// Transformer method which will be used in to provide a `Filter`.
36 | public typealias Transformer = (CIImage) -> CIImage?
37 |
38 | /// Supply a filter to create an `ImageProcessor`.
39 | public protocol CIImageProcessor: ImageProcessor {
40 | var filter: Filter { get }
41 | }
42 |
43 | extension CIImageProcessor {
44 | public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
45 | switch item {
46 | case .image(let image):
47 | return image.kf.apply(filter)
48 | case .data(_):
49 | return (DefaultImageProcessor.default >> self).process(item: item, options: options)
50 | }
51 | }
52 | }
53 |
54 | /// Wrapper for a `Transformer` of CIImage filters.
55 | public struct Filter {
56 |
57 | let transform: Transformer
58 |
59 | public init(tranform: @escaping Transformer) {
60 | self.transform = tranform
61 | }
62 |
63 | /// Tint filter which will apply a tint color to images.
64 | public static var tint: (Color) -> Filter = {
65 | color in
66 | Filter { input in
67 | let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
68 | colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
69 |
70 | let colorImage = colorFilter.outputImage
71 | let filter = CIFilter(name: "CISourceOverCompositing")!
72 | filter.setValue(colorImage, forKey: kCIInputImageKey)
73 | filter.setValue(input, forKey: kCIInputBackgroundImageKey)
74 | #if swift(>=4.0)
75 | return filter.outputImage?.cropped(to: input.extent)
76 | #else
77 | return filter.outputImage?.cropping(to: input.extent)
78 | #endif
79 | }
80 | }
81 |
82 | public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
83 |
84 | /// Color control filter which will apply color control change to images.
85 | public static var colorControl: (ColorElement) -> Filter = { arg -> Filter in
86 | let (brightness, contrast, saturation, inputEV) = arg
87 | return Filter { input in
88 | let paramsColor = [kCIInputBrightnessKey: brightness,
89 | kCIInputContrastKey: contrast,
90 | kCIInputSaturationKey: saturation]
91 |
92 | let paramsExposure = [kCIInputEVKey: inputEV]
93 | #if swift(>=4.0)
94 | let blackAndWhite = input.applyingFilter("CIColorControls", parameters: paramsColor)
95 | return blackAndWhite.applyingFilter("CIExposureAdjust", parameters: paramsExposure)
96 | #else
97 | let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
98 | return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
99 | #endif
100 | }
101 |
102 | }
103 | }
104 |
105 | extension Kingfisher where Base: Image {
106 | /// Apply a `Filter` containing `CIImage` transformer to `self`.
107 | ///
108 | /// - parameter filter: The filter used to transform `self`.
109 | ///
110 | /// - returns: A transformed image by input `Filter`.
111 | ///
112 | /// - Note: Only CG-based images are supported. If any error happens during transforming, `self` will be returned.
113 | public func apply(_ filter: Filter) -> Image {
114 |
115 | guard let cgImage = cgImage else {
116 | assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
117 | return base
118 | }
119 |
120 | let inputImage = CIImage(cgImage: cgImage)
121 | guard let outputImage = filter.transform(inputImage) else {
122 | return base
123 | }
124 |
125 | guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
126 | assertionFailure("[Kingfisher] Can not make an tint image within context.")
127 | return base
128 | }
129 |
130 | #if os(macOS)
131 | return fixedForRetinaPixel(cgImage: result, to: size)
132 | #else
133 | return Image(cgImage: result, scale: base.scale, orientation: base.imageOrientation)
134 | #endif
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/FormatIndicatedCacheSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Junyu Kuang on 5/28/17.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// `FormatIndicatedCacheSerializer` let you indicate an image format for serialized caches.
30 | ///
31 | /// It could serialize and deserialize PNG, JEPG and GIF images. For
32 | /// image other than these formats, a normalized `pngRepresentation` will be used.
33 | ///
34 | /// Example:
35 | /// ````
36 | /// private let profileImageSize = CGSize(width: 44, height: 44)
37 | ///
38 | /// private let imageProcessor = RoundCornerImageProcessor(
39 | /// cornerRadius: profileImageSize.width / 2, targetSize: profileImageSize)
40 | ///
41 | /// private let optionsInfo: KingfisherOptionsInfo = [
42 | /// .cacheSerializer(FormatIndicatedCacheSerializer.png),
43 | /// .backgroundDecode, .processor(imageProcessor), .scaleFactor(UIScreen.main.scale)]
44 | ///
45 | /// extension UIImageView {
46 | /// func setProfileImage(with url: URL) {
47 | /// // Image will always cached as PNG format to preserve alpha channel for round rect.
48 | /// _ = kf.setImage(with: url, options: optionsInfo)
49 | /// }
50 | ///}
51 | /// ````
52 | public struct FormatIndicatedCacheSerializer: CacheSerializer {
53 |
54 | public static let png = FormatIndicatedCacheSerializer(imageFormat: .PNG)
55 | public static let jpeg = FormatIndicatedCacheSerializer(imageFormat: .JPEG)
56 | public static let gif = FormatIndicatedCacheSerializer(imageFormat: .GIF)
57 |
58 | /// The indicated image format.
59 | private let imageFormat: ImageFormat
60 |
61 | public func data(with image: Image, original: Data?) -> Data? {
62 |
63 | func imageData(withFormat imageFormat: ImageFormat) -> Data? {
64 | switch imageFormat {
65 | case .PNG: return image.kf.pngRepresentation()
66 | case .JPEG: return image.kf.jpegRepresentation(compressionQuality: 1.0)
67 | case .GIF: return image.kf.gifRepresentation()
68 | case .unknown: return nil
69 | }
70 | }
71 |
72 | // generate data with indicated image format
73 | if let data = imageData(withFormat: imageFormat) {
74 | return data
75 | }
76 |
77 | let originalFormat = original?.kf.imageFormat ?? .unknown
78 |
79 | // generate data with original image's format
80 | if originalFormat != imageFormat, let data = imageData(withFormat: originalFormat) {
81 | return data
82 | }
83 |
84 | return original ?? image.kf.normalized.kf.pngRepresentation()
85 | }
86 |
87 | /// Same implementation as `DefaultCacheSerializer`.
88 | public func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
89 | let options = options ?? KingfisherEmptyOptionsInfo
90 | return Kingfisher.image(
91 | data: data,
92 | scale: options.scaleFactor,
93 | preloadAllAnimationData: options.preloadAllAnimationData,
94 | onlyFirstFrame: options.onlyLoadFirstFrame)
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/ImageTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageTransition.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/9/18.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | // Not implemented for macOS and watchOS yet.
29 |
30 | import AppKit
31 |
32 | /// Image transition is not supported on macOS.
33 | public enum ImageTransition {
34 | case none
35 | var duration: TimeInterval {
36 | return 0
37 | }
38 | }
39 |
40 | #elseif os(watchOS)
41 | import UIKit
42 | /// Image transition is not supported on watchOS.
43 | public enum ImageTransition {
44 | case none
45 | var duration: TimeInterval {
46 | return 0
47 | }
48 | }
49 | #else
50 | import UIKit
51 |
52 | /**
53 | Transition effect which will be used when an image downloaded and set by `UIImageView` extension API in Kingfisher.
54 | You can assign an enum value with transition duration as an item in `KingfisherOptionsInfo`
55 | to enable the animation transition.
56 |
57 | Apple's UIViewAnimationOptions is used under the hood.
58 | For custom transition, you should specified your own transition options, animations and
59 | comletion handler as well.
60 | */
61 | public enum ImageTransition {
62 | /// No animation transistion.
63 | case none
64 |
65 | /// Fade in the loaded image.
66 | case fade(TimeInterval)
67 |
68 | /// Flip from left transition.
69 | case flipFromLeft(TimeInterval)
70 |
71 | /// Flip from right transition.
72 | case flipFromRight(TimeInterval)
73 |
74 | /// Flip from top transition.
75 | case flipFromTop(TimeInterval)
76 |
77 | /// Flip from bottom transition.
78 | case flipFromBottom(TimeInterval)
79 |
80 | /// Custom transition.
81 | case custom(duration: TimeInterval,
82 | options: UIViewAnimationOptions,
83 | animations: ((UIImageView, UIImage) -> Void)?,
84 | completion: ((Bool) -> Void)?)
85 |
86 | var duration: TimeInterval {
87 | switch self {
88 | case .none: return 0
89 | case .fade(let duration): return duration
90 |
91 | case .flipFromLeft(let duration): return duration
92 | case .flipFromRight(let duration): return duration
93 | case .flipFromTop(let duration): return duration
94 | case .flipFromBottom(let duration): return duration
95 |
96 | case .custom(let duration, _, _, _): return duration
97 | }
98 | }
99 |
100 | var animationOptions: UIViewAnimationOptions {
101 | switch self {
102 | case .none: return []
103 | case .fade(_): return .transitionCrossDissolve
104 |
105 | case .flipFromLeft(_): return .transitionFlipFromLeft
106 | case .flipFromRight(_): return .transitionFlipFromRight
107 | case .flipFromTop(_): return .transitionFlipFromTop
108 | case .flipFromBottom(_): return .transitionFlipFromBottom
109 |
110 | case .custom(_, let options, _, _): return options
111 | }
112 | }
113 |
114 | var animations: ((UIImageView, UIImage) -> Void)? {
115 | switch self {
116 | case .custom(_, _, let animations, _): return animations
117 | default: return { $0.image = $1 }
118 | }
119 | }
120 |
121 | var completion: ((Bool) -> Void)? {
122 | switch self {
123 | case .custom(_, _, _, let completion): return completion
124 | default: return nil
125 | }
126 | }
127 | }
128 | #endif
129 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Kingfisher.h:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.h
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #import
28 |
29 | //! Project version number for Kingfisher.
30 | FOUNDATION_EXPORT double KingfisherVersionNumber;
31 |
32 | //! Project version string for Kingfisher.
33 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
34 |
35 | // In this header, you should import all the public headers of your framework using statements like #import
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Kingfisher.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Kingfisher.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 16/9/14.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 | import ImageIO
29 |
30 | #if os(macOS)
31 | import AppKit
32 | public typealias Image = NSImage
33 | public typealias View = NSView
34 | public typealias Color = NSColor
35 | public typealias ImageView = NSImageView
36 | public typealias Button = NSButton
37 | #else
38 | import UIKit
39 | public typealias Image = UIImage
40 | public typealias Color = UIColor
41 | #if !os(watchOS)
42 | public typealias ImageView = UIImageView
43 | public typealias View = UIView
44 | public typealias Button = UIButton
45 | #endif
46 | #endif
47 |
48 | public final class Kingfisher {
49 | public let base: Base
50 | public init(_ base: Base) {
51 | self.base = base
52 | }
53 | }
54 |
55 | /**
56 | A type that has Kingfisher extensions.
57 | */
58 | public protocol KingfisherCompatible {
59 | associatedtype CompatibleType
60 | var kf: CompatibleType { get }
61 | }
62 |
63 | public extension KingfisherCompatible {
64 | public var kf: Kingfisher {
65 | get { return Kingfisher(self) }
66 | }
67 | }
68 |
69 | extension Image: KingfisherCompatible { }
70 | #if !os(watchOS)
71 | extension ImageView: KingfisherCompatible { }
72 | extension Button: KingfisherCompatible { }
73 | #endif
74 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Placeholder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Placeholder.swift
3 | // Kingfisher
4 | //
5 | // Created by Tieme van Veen on 28/08/2017.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(macOS)
28 | import AppKit
29 | #else
30 | import UIKit
31 | #endif
32 |
33 |
34 | /// Represent a placeholder type which could be set while loading as well as
35 | /// loading finished without getting an image.
36 | public protocol Placeholder {
37 |
38 | /// How the placeholder should be added to a given image view.
39 | func add(to imageView: ImageView)
40 |
41 | /// How the placeholder should be removed from a given image view.
42 | func remove(from imageView: ImageView)
43 | }
44 |
45 | /// Default implementation of an image placeholder. The image will be set or
46 | /// reset directly for `image` property of the image view.
47 | extension Placeholder where Self: Image {
48 |
49 | /// How the placeholder should be added to a given image view.
50 | public func add(to imageView: ImageView) { imageView.image = self }
51 |
52 | /// How the placeholder should be removed from a given image view.
53 | public func remove(from imageView: ImageView) { imageView.image = nil }
54 | }
55 |
56 | extension Image: Placeholder {}
57 |
58 | /// Default implementation of an arbitrary view as placeholder. The view will be
59 | /// added as a subview when adding and be removed from its super view when removing.
60 | ///
61 | /// To use your customize View type as placeholder, simply let it conforming to
62 | /// `Placeholder` by `extension MyView: Placeholder {}`.
63 | extension Placeholder where Self: View {
64 |
65 | /// How the placeholder should be added to a given image view.
66 | public func add(to imageView: ImageView) {
67 | imageView.addSubview(self)
68 |
69 | self.translatesAutoresizingMaskIntoConstraints = false
70 | NSLayoutConstraint.activate([
71 | NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: imageView, attribute: .centerX, multiplier: 1, constant: 0),
72 | NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: imageView, attribute: .centerY, multiplier: 1, constant: 0),
73 | NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: imageView, attribute: .height, multiplier: 1, constant: 0),
74 | NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: imageView, attribute: .width, multiplier: 1, constant: 0)
75 | ])
76 | }
77 |
78 | /// How the placeholder should be removed from a given image view.
79 | public func remove(from imageView: ImageView) {
80 | self.removeFromSuperview()
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/RequestModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestModifier.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 2016/09/05.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | /// Request modifier of image downloader.
30 | public protocol ImageDownloadRequestModifier {
31 | func modified(for request: URLRequest) -> URLRequest?
32 | }
33 |
34 | struct NoModifier: ImageDownloadRequestModifier {
35 | static let `default` = NoModifier()
36 | private init() {}
37 | func modified(for request: URLRequest) -> URLRequest? {
38 | return request
39 | }
40 | }
41 |
42 | public struct AnyModifier: ImageDownloadRequestModifier {
43 |
44 | let block: (URLRequest) -> URLRequest?
45 |
46 | public func modified(for request: URLRequest) -> URLRequest? {
47 | return block(request)
48 | }
49 |
50 | public init(modify: @escaping (URLRequest) -> URLRequest? ) {
51 | block = modify
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Resource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Resource.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/4/6.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 |
30 | /// `Resource` protocol defines how to download and cache a resource from network.
31 | public protocol Resource {
32 | /// The key used in cache.
33 | var cacheKey: String { get }
34 |
35 | /// The target image URL.
36 | var downloadURL: URL { get }
37 | }
38 |
39 | /**
40 | ImageResource is a simple combination of `downloadURL` and `cacheKey`.
41 |
42 | When passed to image view set methods, Kingfisher will try to download the target
43 | image from the `downloadURL`, and then store it with the `cacheKey` as the key in cache.
44 | */
45 | public struct ImageResource: Resource {
46 | /// The key used in cache.
47 | public let cacheKey: String
48 |
49 | /// The target image URL.
50 | public let downloadURL: URL
51 |
52 | /**
53 | Create a resource.
54 |
55 | - parameter downloadURL: The target image URL.
56 | - parameter cacheKey: The cache key. If `nil`, Kingfisher will use the `absoluteString` of `downloadURL` as the key.
57 |
58 | - returns: A resource.
59 | */
60 | public init(downloadURL: URL, cacheKey: String? = nil) {
61 | self.downloadURL = downloadURL
62 | self.cacheKey = cacheKey ?? downloadURL.absoluteString
63 | }
64 | }
65 |
66 | /**
67 | URL conforms to `Resource` in Kingfisher.
68 | The `absoluteString` of this URL is used as `cacheKey`. And the URL itself will be used as `downloadURL`.
69 | If you need customize the url and/or cache key, use `ImageResource` instead.
70 | */
71 | extension URL: Resource {
72 | public var cacheKey: String { return absoluteString }
73 | public var downloadURL: URL { return self }
74 | }
75 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/ThreadHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreadHelper.swift
3 | // Kingfisher
4 | //
5 | // Created by Wei Wang on 15/10/9.
6 | //
7 | // Copyright (c) 2018 Wei Wang
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | extension DispatchQueue {
30 | // This method will dispatch the `block` to self.
31 | // If `self` is the main queue, and current thread is main thread, the block
32 | // will be invoked immediately instead of being dispatched.
33 | func safeAsync(_ block: @escaping ()->()) {
34 | if self === DispatchQueue.main && Thread.isMainThread {
35 | block()
36 | } else {
37 | async { block() }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Demo/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FTImageSize (0.0.4)
3 | - FTIndicator (1.2.9):
4 | - FTIndicator/FTNotificationIndicator (= 1.2.9)
5 | - FTIndicator/FTProgressIndicator (= 1.2.9)
6 | - FTIndicator/FTToastIndicator (= 1.2.9)
7 | - FTIndicator/FTNotificationIndicator (1.2.9)
8 | - FTIndicator/FTProgressIndicator (1.2.9)
9 | - FTIndicator/FTToastIndicator (1.2.9)
10 | - FTPickerView (1.0.2)
11 | - Kingfisher (4.7.0)
12 |
13 | DEPENDENCIES:
14 | - FTImageSize
15 | - FTIndicator
16 | - FTPickerView
17 | - Kingfisher
18 |
19 | SPEC CHECKSUMS:
20 | FTImageSize: 29c6fc0830dbe33973286148a8e32cd582a9f26d
21 | FTIndicator: f7f071fd159e5befa1d040a9ef2e3ab53fa9322c
22 | FTPickerView: 3fb6055e057ac608435ce7d938f2bbc0640f4948
23 | Kingfisher: da6b005aa96d37698e3e4f1ccfe96a5b9bbf27d6
24 |
25 | PODFILE CHECKSUM: 0897bbd78b2258d0c7f01ee2e9d5eb5a802cde17
26 |
27 | COCOAPODS: 1.4.0
28 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/FTImageSize-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_FTImageSize : NSObject
3 | @end
4 | @implementation PodsDummy_FTImageSize
5 | @end
6 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/FTImageSize-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/FTImageSize-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double FTImageSizeVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char FTImageSizeVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/FTImageSize.modulemap:
--------------------------------------------------------------------------------
1 | framework module FTImageSize {
2 | umbrella header "FTImageSize-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/FTImageSize.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FTImageSize
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FTImageSize
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 | SWIFT_VERSION = 3.0
12 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.0.4
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/FTIndicator-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_FTIndicator : NSObject
3 | @end
4 | @implementation PodsDummy_FTIndicator
5 | @end
6 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/FTIndicator-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/FTIndicator-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "FTIndicator.h"
14 | #import "FTNotificationIndicator.h"
15 | #import "FTProgressIndicator.h"
16 | #import "FTToastIndicator.h"
17 | #import "FTNotificationIndicator.h"
18 | #import "FTProgressIndicator.h"
19 | #import "FTToastIndicator.h"
20 |
21 | FOUNDATION_EXPORT double FTIndicatorVersionNumber;
22 | FOUNDATION_EXPORT const unsigned char FTIndicatorVersionString[];
23 |
24 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/FTIndicator.modulemap:
--------------------------------------------------------------------------------
1 | framework module FTIndicator {
2 | umbrella header "FTIndicator-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/FTIndicator.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FTIndicator
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | PODS_BUILD_DIR = ${BUILD_DIR}
5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FTIndicator
8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.2.9
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/FTPickerView-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_FTPickerView : NSObject
3 | @end
4 | @implementation PodsDummy_FTPickerView
5 | @end
6 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/FTPickerView-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/FTPickerView-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "FTPickerView.h"
14 |
15 | FOUNDATION_EXPORT double FTPickerViewVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char FTPickerViewVersionString[];
17 |
18 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/FTPickerView.modulemap:
--------------------------------------------------------------------------------
1 | framework module FTPickerView {
2 | umbrella header "FTPickerView-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/FTPickerView.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FTPickerView
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | PODS_BUILD_DIR = ${BUILD_DIR}
5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FTPickerView
8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.2
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 4.7.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Kingfisher-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Kingfisher : NSObject
3 | @end
4 | @implementation PodsDummy_Kingfisher
5 | @end
6 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Kingfisher-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 | #import "Kingfisher.h"
14 |
15 | FOUNDATION_EXPORT double KingfisherVersionNumber;
16 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
17 |
18 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Kingfisher.modulemap:
--------------------------------------------------------------------------------
1 | framework module Kingfisher {
2 | umbrella header "Kingfisher-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Kingfisher.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
4 | OTHER_LDFLAGS = -framework "CFNetwork"
5 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Kingfisher
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## FTImageSize
5 |
6 | MIT License
7 |
8 | Copyright (c) 2016 Liu Fengting
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 |
17 | The above copyright notice and this permission notice shall be included in all
18 | copies or substantial portions of the Software.
19 |
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 | SOFTWARE.
27 |
28 |
29 | ## FTIndicator
30 |
31 | The MIT License (MIT)
32 |
33 | Copyright (c) 2016 Liu Fengting
34 |
35 | Permission is hereby granted, free of charge, to any person obtaining a copy
36 | of this software and associated documentation files (the "Software"), to deal
37 | in the Software without restriction, including without limitation the rights
38 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39 | copies of the Software, and to permit persons to whom the Software is
40 | furnished to do so, subject to the following conditions:
41 |
42 | The above copyright notice and this permission notice shall be included in all
43 | copies or substantial portions of the Software.
44 |
45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
51 | SOFTWARE.
52 |
53 |
54 | ## FTPickerView
55 |
56 | The MIT License (MIT)
57 |
58 | Copyright (c) 2016 刘锋婷
59 |
60 | Permission is hereby granted, free of charge, to any person obtaining a copy
61 | of this software and associated documentation files (the "Software"), to deal
62 | in the Software without restriction, including without limitation the rights
63 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64 | copies of the Software, and to permit persons to whom the Software is
65 | furnished to do so, subject to the following conditions:
66 |
67 | The above copyright notice and this permission notice shall be included in all
68 | copies or substantial portions of the Software.
69 |
70 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
73 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
76 | SOFTWARE.
77 |
78 |
79 | ## Kingfisher
80 |
81 | The MIT License (MIT)
82 |
83 | Copyright (c) 2018 Wei Wang
84 |
85 | Permission is hereby granted, free of charge, to any person obtaining a copy
86 | of this software and associated documentation files (the "Software"), to deal
87 | in the Software without restriction, including without limitation the rights
88 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
89 | copies of the Software, and to permit persons to whom the Software is
90 | furnished to do so, subject to the following conditions:
91 |
92 | The above copyright notice and this permission notice shall be included in all
93 | copies or substantial portions of the Software.
94 |
95 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
96 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
97 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
98 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
99 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
100 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
101 | SOFTWARE.
102 |
103 |
104 | Generated by CocoaPods - https://cocoapods.org
105 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_Demo : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_Demo
5 | @end
6 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
14 |
15 | case "${TARGETED_DEVICE_FAMILY}" in
16 | 1,2)
17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
18 | ;;
19 | 1)
20 | TARGET_DEVICE_ARGS="--target-device iphone"
21 | ;;
22 | 2)
23 | TARGET_DEVICE_ARGS="--target-device ipad"
24 | ;;
25 | 3)
26 | TARGET_DEVICE_ARGS="--target-device tv"
27 | ;;
28 | 4)
29 | TARGET_DEVICE_ARGS="--target-device watch"
30 | ;;
31 | *)
32 | TARGET_DEVICE_ARGS="--target-device mac"
33 | ;;
34 | esac
35 |
36 | install_resource()
37 | {
38 | if [[ "$1" = /* ]] ; then
39 | RESOURCE_PATH="$1"
40 | else
41 | RESOURCE_PATH="${PODS_ROOT}/$1"
42 | fi
43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
44 | cat << EOM
45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
46 | EOM
47 | exit 1
48 | fi
49 | case $RESOURCE_PATH in
50 | *.storyboard)
51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
53 | ;;
54 | *.xib)
55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
57 | ;;
58 | *.framework)
59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
63 | ;;
64 | *.xcdatamodel)
65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
67 | ;;
68 | *.xcdatamodeld)
69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
71 | ;;
72 | *.xcmappingmodel)
73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
75 | ;;
76 | *.xcassets)
77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
79 | ;;
80 | *)
81 | echo "$RESOURCE_PATH" || true
82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
83 | ;;
84 | esac
85 | }
86 |
87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
92 | fi
93 | rm -f "$RESOURCES_TO_COPY"
94 |
95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
96 | then
97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
99 | while read line; do
100 | if [[ $line != "${PODS_ROOT}*" ]]; then
101 | XCASSET_FILES+=("$line")
102 | fi
103 | done <<<"$OTHER_XCASSETS"
104 |
105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
106 | fi
107 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_DemoVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_DemoVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FTImageSize" "${PODS_CONFIGURATION_BUILD_DIR}/FTIndicator" "${PODS_CONFIGURATION_BUILD_DIR}/FTPickerView" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FTImageSize/FTImageSize.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FTIndicator/FTIndicator.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FTPickerView/FTPickerView.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "FTImageSize" -framework "FTIndicator" -framework "FTPickerView" -framework "Kingfisher"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_Demo {
2 | umbrella header "Pods-Demo-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FTImageSize" "${PODS_CONFIGURATION_BUILD_DIR}/FTIndicator" "${PODS_CONFIGURATION_BUILD_DIR}/FTPickerView" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FTImageSize/FTImageSize.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FTIndicator/FTIndicator.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/FTPickerView/FTPickerView.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers"
6 | OTHER_LDFLAGS = $(inherited) -framework "FTImageSize" -framework "FTIndicator" -framework "FTPickerView" -framework "Kingfisher"
7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/FTChatMessage/FTChatMessageCell/.DS_Store
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageBubbleItem/FTChatMessageBubbleAudioItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageBubbleAudioItem.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/5/7.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageBubbleAudioItem: FTChatMessageBubbleItem {
12 |
13 | var playImageView : UIImageView!
14 | var mediaInfoLabel : UILabel!
15 |
16 | convenience init(frame: CGRect, aMessage : FTChatMessageModel, for indexPath: IndexPath) {
17 | self.init(frame:frame)
18 | self.backgroundColor = UIColor.clear
19 | message = aMessage
20 | let messageBubblePath = self.getAudioBubblePath(frame.size, isUserSelf: aMessage.isUserSelf)
21 |
22 | messageBubbleLayer.path = messageBubblePath.cgPath
23 | messageBubbleLayer.fillColor = aMessage.messageSender.isUserSelf ? FTDefaultOutgoingColor.cgColor : FTDefaultIncomingColor.cgColor
24 | self.layer.addSublayer(messageBubbleLayer)
25 |
26 | let mediaImageRect = self.getPlayImageViewFrame(aMessage.isUserSelf)
27 | playImageView = UIImageView(frame : mediaImageRect)
28 | playImageView.backgroundColor = UIColor.clear
29 | playImageView.tintColor = aMessage.messageSender.isUserSelf ? UIColor.white : UIColor.black
30 | if let image = UIImage(named: "Media_Play") {
31 | playImageView.image = image.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
32 | }
33 | self.addSubview(playImageView)
34 |
35 | let mediaInfoLabelRect = self.getMediaInfoLabelFrame(aMessage.isUserSelf)
36 | mediaInfoLabel = UILabel(frame : mediaInfoLabelRect)
37 | mediaInfoLabel.backgroundColor = UIColor.clear
38 | mediaInfoLabel.font = FTDefaultFontSize
39 | mediaInfoLabel.textColor = aMessage.messageSender.isUserSelf ? UIColor.white : UIColor.black
40 | mediaInfoLabel.textAlignment = aMessage.isUserSelf ? NSTextAlignment.left : NSTextAlignment.right
41 | mediaInfoLabel.text = "1′ 22″"
42 | self.addSubview(mediaInfoLabel)
43 |
44 | }
45 |
46 | fileprivate func getAudioBubblePath(_ size:CGSize , isUserSelf : Bool) -> UIBezierPath {
47 | let bubbleRect = CGRect(x: isUserSelf ? 0 : FTDefaultMessageBubbleAngleWidth, y: 0, width: size.width - FTDefaultMessageBubbleAngleWidth , height: size.height)
48 | let path = UIBezierPath.init(roundedRect: bubbleRect, cornerRadius: size.height/2)
49 | return path;
50 | }
51 |
52 | fileprivate func getPlayImageViewFrame(_ isUserSelf : Bool) -> CGRect {
53 | let margin = (FTDefaultMessageBubbleAudioHeight - FTDefaultMessageBubbleAudioIconHeight)/2
54 | return isUserSelf ?
55 | CGRect(x: margin, y: margin, width: FTDefaultMessageBubbleAudioIconHeight, height: FTDefaultMessageBubbleAudioIconHeight) :
56 | CGRect(x: self.frame.size.width - FTDefaultMessageBubbleAudioHeight + margin , y: margin, width: FTDefaultMessageBubbleAudioIconHeight, height: FTDefaultMessageBubbleAudioIconHeight)
57 |
58 | }
59 | fileprivate func getMediaInfoLabelFrame(_ isUserSelf : Bool) -> CGRect {
60 | let margin = (FTDefaultMessageBubbleAudioHeight - FTDefaultMessageBubbleAudioIconHeight)/2
61 | return isUserSelf ?
62 | CGRect(x: FTDefaultMessageBubbleAudioHeight, y: margin, width: self.frame.size.width - FTDefaultMessageBubbleAudioHeight - FTDefaultMessageBubbleAngleWidth - margin, height: FTDefaultMessageBubbleAudioIconHeight) :
63 | CGRect( x: FTDefaultMessageBubbleAngleWidth + margin, y: margin, width: self.frame.size.width - FTDefaultMessageBubbleAudioHeight - FTDefaultMessageBubbleAngleWidth - margin, height: FTDefaultMessageBubbleAudioIconHeight)
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageBubbleItem/FTChatMessageBubbleImageItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageBubbleImageItem.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/5/7.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Kingfisher
11 |
12 | class FTChatMessageBubbleImageItem: FTChatMessageBubbleItem {
13 |
14 | convenience init(frame: CGRect, aMessage : FTChatMessageModel, for indexPath: IndexPath) {
15 | self.init(frame:frame)
16 | self.backgroundColor = UIColor.clear
17 | message = aMessage
18 |
19 | let messageBubblePath = self.getBubbleShapePathWithSize(frame.size, isUserSelf: aMessage.isUserSelf, for: indexPath)
20 |
21 | let maskLayer = CAShapeLayer()
22 | maskLayer.path = messageBubblePath.cgPath
23 | maskLayer.frame = self.bounds
24 |
25 | let layer = CALayer()
26 | layer.mask = maskLayer
27 | layer.frame = self.bounds
28 | layer.contentsScale = UIScreen.main.scale
29 | layer.contentsGravity = kCAGravityResizeAspectFill
30 | layer.backgroundColor = aMessage.messageSender.isUserSelf ? FTDefaultOutgoingColor.cgColor : FTDefaultIncomingColor.cgColor
31 | self.layer.addSublayer(layer)
32 |
33 | if aMessage.isKind(of: FTChatMessageImageModel.classForCoder()) {
34 | if let image : UIImage = (aMessage as! FTChatMessageImageModel).image {
35 | layer.contents = image.withRenderingMode(.alwaysOriginal).cgImage
36 | }else if let imageURL : String = (aMessage as! FTChatMessageImageModel).imageUrl {
37 | ImageDownloader.default.downloadImage(with: URL(string: imageURL)!, options: [], progressBlock: nil) {
38 | (image, error, url, data) in
39 | if image != nil {
40 | layer.contents = image?.cgImage
41 | }
42 | }
43 | }
44 | }else{
45 | if let image = UIImage(named : "dog.jpg") {
46 | layer.contents = image.cgImage
47 | }
48 | }
49 | }
50 |
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageBubbleItem/FTChatMessageBubbleLocationItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageBubbleLocationItem.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/5/7.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MapKit
11 |
12 | class FTChatMessageBubbleLocationItem: FTChatMessageBubbleItem {
13 |
14 | var mapView : MKMapView!
15 |
16 | convenience init(frame: CGRect, aMessage : FTChatMessageModel, for indexPath: IndexPath) {
17 | self.init(frame:frame)
18 | self.backgroundColor = UIColor.clear
19 | message = aMessage
20 |
21 | let mapRect = self.getMapSize(aMessage.isUserSelf)
22 | mapView = MKMapView(frame : mapRect)
23 | mapView.isScrollEnabled = false
24 | mapView.isUserInteractionEnabled = false
25 | mapView.layer.cornerRadius = FTDefaultMessageRoundCorner
26 | mapView.layer.borderColor = aMessage.messageSender.isUserSelf ? FTDefaultOutgoingColor.cgColor : FTDefaultIncomingColor.cgColor
27 | mapView.layer.borderWidth = 0.8
28 | self.addSubview(mapView)
29 |
30 |
31 | // setRegion
32 | let coordinate = CLLocationCoordinate2DMake(31.479461477978905, 120.38549624655187);
33 | let region = MKCoordinateRegionMakeWithDistance(coordinate, Double(mapRect.size.width), Double(mapRect.size.height))
34 | mapView.setRegion(region, animated: false)
35 | // addAnnotation
36 | let string = NSString(format: "%.1f,%.1f",coordinate.latitude,coordinate.longitude)
37 | let pin = MapPin.init(coordinate: coordinate, title: "My Location", subtitle: string as String)
38 | mapView.addAnnotation(pin as MKAnnotation)
39 |
40 | }
41 |
42 |
43 | fileprivate func getMapSize(_ isUserSelf : Bool) -> CGRect {
44 | let bubbleRect = CGRect(x: isUserSelf ? 0 : FTDefaultMessageBubbleAngleWidth, y: 0, width: self.bounds.size.width - FTDefaultMessageBubbleAngleWidth , height: self.bounds.size.height)
45 | return bubbleRect;
46 | }
47 |
48 |
49 |
50 | }
51 |
52 |
53 | class MapPin : NSObject, MKAnnotation {
54 | var coordinate: CLLocationCoordinate2D
55 | var title: String?
56 | var subtitle: String?
57 |
58 | init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
59 | self.coordinate = coordinate
60 | self.title = title
61 | self.subtitle = subtitle
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageBubbleItem/FTChatMessageBubbleTextItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageBubbleTextItem.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/5/7.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageBubbleTextItem: FTChatMessageBubbleItem {
12 |
13 | convenience init(frame: CGRect, aMessage : FTChatMessageModel, for indexPath: IndexPath) {
14 | self.init(frame:frame)
15 | self.backgroundColor = UIColor.clear
16 | message = aMessage
17 |
18 | let messageBubblePath = self.getBubbleShapePathWithSize(frame.size, isUserSelf: aMessage.isUserSelf, for: indexPath)
19 |
20 | messageBubbleLayer.path = messageBubblePath.cgPath
21 | messageBubbleLayer.fillColor = aMessage.messageSender.isUserSelf ? FTDefaultOutgoingColor.cgColor : FTDefaultIncomingColor.cgColor
22 | self.layer.addSublayer(messageBubbleLayer)
23 |
24 |
25 | //text
26 | messageLabel = UILabel(frame: self.getTextRectWithSize(frame.size, isUserSelf: aMessage.isUserSelf));
27 | messageLabel.text = message.messageText
28 | messageLabel.numberOfLines = 0
29 | messageLabel.textColor = aMessage.messageSender.isUserSelf ? UIColor.white : UIColor.black
30 | messageLabel.font = FTDefaultFontSize
31 | self.addSubview(messageLabel)
32 | let attributeString = NSMutableAttributedString(attributedString: messageLabel.attributedText!)
33 | attributeString.addAttributes([NSAttributedStringKey.font:FTDefaultFontSize,NSAttributedStringKey.paragraphStyle: FTChatMessagePublicMethods.getFTDefaultMessageParagraphStyle()], range: NSMakeRange(0, (messageLabel.text! as NSString).length))
34 | messageLabel.attributedText = attributeString
35 |
36 | }
37 |
38 | fileprivate func getTextRectWithSize(_ size:CGSize , isUserSelf : Bool) -> CGRect {
39 | let bubbleWidth = size.width - FTDefaultMessageBubbleAngleWidth - FTDefaultTextLeftMargin*2
40 | let bubbleHeight = size.height - FTDefaultTextTopMargin*2
41 | let y = FTDefaultTextTopMargin
42 | let x : CGFloat = isUserSelf ? FTDefaultTextLeftMargin : FTDefaultMessageBubbleAngleWidth + FTDefaultTextLeftMargin
43 | return CGRect(x: x,y: y,width: bubbleWidth,height: bubbleHeight);
44 | }
45 |
46 |
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageBubbleItem/FTChatMessageBubbleVideoItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageBubbleVideoItem.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/5/7.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageBubbleVideoItem: FTChatMessageBubbleItem {
12 |
13 | var mediaPlayImageView : UIImageView!
14 |
15 |
16 | convenience init(frame: CGRect, aMessage : FTChatMessageModel, for indexPath: IndexPath) {
17 | self.init(frame:frame)
18 | self.backgroundColor = UIColor.clear
19 | message = aMessage
20 | let messageBubblePath = self.getBubbleShapePathWithSize(frame.size, isUserSelf: aMessage.isUserSelf, for: indexPath)
21 |
22 |
23 | let maskLayer = CAShapeLayer()
24 | maskLayer.path = messageBubblePath.cgPath
25 | maskLayer.frame = self.bounds
26 | maskLayer.contentsScale = UIScreen.main.scale;
27 |
28 | let layer = CAShapeLayer()
29 | layer.mask = maskLayer
30 | layer.frame = self.bounds
31 | self.layer.addSublayer(layer)
32 |
33 | if let image = UIImage(named : "dog.jpg") {
34 | layer.contents = image.cgImage
35 | }
36 |
37 |
38 | let mediaImageRect = self.getMediaImageViewFrame(aMessage.isUserSelf)
39 |
40 | mediaPlayImageView = UIImageView(frame : mediaImageRect)
41 | mediaPlayImageView.backgroundColor = UIColor.clear
42 | mediaPlayImageView.image = UIImage(named: "Media_Play")
43 | self.addSubview(mediaPlayImageView)
44 | }
45 |
46 | fileprivate func getMediaImageViewFrame(_ isUserSelf : Bool) -> CGRect {
47 | let xx = isUserSelf ?
48 | (self.frame.size.width - FTDefaultMessageBubbleAngleWidth - FTDefaultMessageBubbleMediaIconHeight)/2 :
49 | FTDefaultMessageBubbleAngleWidth + (self.frame.size.width - FTDefaultMessageBubbleAngleWidth - FTDefaultMessageBubbleMediaIconHeight)/2
50 | let yy = (self.frame.size.height - FTDefaultMessageBubbleMediaIconHeight)/2
51 | return CGRect(x: xx, y: yy, width: FTDefaultMessageBubbleMediaIconHeight, height: FTDefaultMessageBubbleMediaIconHeight)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageCell.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/28.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //MARK: - FTChatMessageCell
12 |
13 | class FTChatMessageCell: UITableViewCell {
14 |
15 | var message : FTChatMessageModel!
16 | var messageBubbleItem: FTChatMessageBubbleItem!
17 |
18 | //MARK: - messageTimeLabel
19 | lazy var messageTimeLabel: UILabel! = {
20 | let label = UILabel(frame: CGRect.zero)
21 | label.font = FTDefaultTimeLabelFont
22 | label.textAlignment = .center
23 | label.textColor = UIColor.lightGray
24 | return label
25 | }()
26 |
27 |
28 | //MARK: - messageDeliverStatusView
29 | var messageDeliverStatusView : FTChatMessageDeliverStatusView? = {
30 | return FTChatMessageDeliverStatusView(frame: CGRect.zero)
31 | }()
32 |
33 | //MARK: - convenience init
34 | convenience init(style: UITableViewCellStyle, reuseIdentifier: String?, theMessage : FTChatMessageModel, for indexPath: IndexPath) {
35 | self.init(style: style, reuseIdentifier: reuseIdentifier)
36 |
37 | message = theMessage
38 |
39 | let heightSoFar : CGFloat = 0
40 | var bubbleRect = CGRect.zero
41 |
42 |
43 | if indexPath.row == 0 {
44 | self.addTimeLabel()
45 | }
46 |
47 | let y : CGFloat = heightSoFar
48 | let bubbleWidth : CGFloat = FTChatMessageBubbleItem.getMessageBubbleWidthForMessage(theMessage)
49 | let bubbleHeight : CGFloat = FTChatMessageBubbleItem.getMessageBubbleHeightForMessage(theMessage)
50 |
51 | let x = theMessage.isUserSelf ? FTScreenWidth - (FTDefaultIconSize + FTDefaultMargin + FTDefaultMessageCellIconToMessageMargin) - bubbleWidth : FTDefaultIconSize + FTDefaultMargin + FTDefaultMessageCellIconToMessageMargin
52 |
53 | bubbleRect = CGRect(x: x, y: y, width: bubbleWidth, height: bubbleHeight)
54 |
55 | self.setupCellBubbleItem(bubbleRect, for: indexPath)
56 |
57 | }
58 |
59 | //MARK: - setupCellBubbleItem
60 | func setupCellBubbleItem(_ bubbleFrame: CGRect, for indexPath: IndexPath) {
61 |
62 | messageBubbleItem = FTChatMessageBubbleItem.getBubbleItemWithFrame(bubbleFrame, aMessage: message, for: indexPath)
63 | messageBubbleItem.addTarget(self, action: #selector(self.itemTapped), for: UIControlEvents.touchUpInside)
64 | self.addSubview(messageBubbleItem)
65 |
66 | if message.isUserSelf && message.messageDeliverStatus != FTChatMessageDeliverStatus.succeeded{
67 | self.addSendStatusView(bubbleFrame)
68 | }
69 | }
70 |
71 | //MARK: - addTimeLabel
72 | func addTimeLabel() {
73 | let timeLabelRect = CGRect(x: 0, y: -FTDefaultMessageCellTimeLabelHeight ,width: FTScreenWidth, height: FTDefaultMessageCellTimeLabelHeight);
74 | messageTimeLabel.frame = timeLabelRect
75 | messageTimeLabel.text = message.messageTimeStamp
76 | self.addSubview(messageTimeLabel)
77 | }
78 |
79 | //MARK: - addSenderLabel
80 | // func addSenderLabel() {
81 | // var nameLabelTextAlignment : NSTextAlignment = .right
82 | // var nameLabelRect = CGRect( x: 0, y: -FTDefaultSectionHeight/2 , width: FTScreenWidth - (FTDefaultMargin + FTDefaultIconSize + FTDefaultMessageBubbleAngleWidth), height: FTDefaultSectionHeight/2)
83 | //
84 | // if message.isUserSelf == false {
85 | // nameLabelRect.origin.x = FTDefaultMargin + FTDefaultIconSize + FTDefaultMessageBubbleAngleWidth
86 | // nameLabelTextAlignment = .left
87 | // }
88 | //
89 | // messageSenderNameLabel.frame = nameLabelRect
90 | // messageSenderNameLabel.text = message.messageSender.senderName
91 | // messageSenderNameLabel.textAlignment = nameLabelTextAlignment
92 | // self.addSubview(messageSenderNameLabel)
93 | // }
94 |
95 | //MARK: - addSendStatusView
96 | func addSendStatusView(_ bubbleFrame: CGRect) {
97 | let statusViewRect = CGRect(x: bubbleFrame.origin.x - FTDefaultMessageCellSendStatusViewSize - FTDefaultMargin, y: (bubbleFrame.origin.y + bubbleFrame.size.height - FTDefaultMessageCellSendStatusViewSize)/2, width: FTDefaultMessageCellSendStatusViewSize, height: FTDefaultMessageCellSendStatusViewSize)
98 | messageDeliverStatusView?.frame = statusViewRect
99 | messageDeliverStatusView?.setupWithDeliverStatus(message.messageDeliverStatus)
100 | self.addSubview(messageDeliverStatusView!)
101 | }
102 |
103 | @objc func itemTapped() {
104 | print("message item tapped");
105 | }
106 | }
107 |
108 |
109 | //MARK: - FTChatMessageCell extension
110 |
111 | extension FTChatMessageCell {
112 |
113 | internal class func getCellHeightWithMessage(_ theMessage : FTChatMessageModel, for indexPath: IndexPath) -> CGFloat{
114 | var cellDesiredHeight : CGFloat = 0;
115 | cellDesiredHeight += FTChatMessageBubbleItem.getMessageBubbleHeightForMessage(theMessage)
116 | cellDesiredHeight += FTDefaultMargin
117 | cellDesiredHeight = max(1, cellDesiredHeight)
118 | return cellDesiredHeight
119 | }
120 | }
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/FTChatMessageDeliverStatusView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageDeliverStatusView.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/9/12.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageDeliverStatusView: UIButton {
12 |
13 | //MARK: - activityIndicator
14 | lazy var activityIndicator : UIActivityIndicatorView = {
15 | let activity = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
16 | activity.frame = self.bounds
17 | activity.hidesWhenStopped = true
18 | return activity
19 | }()
20 |
21 | //MARK: - setupWithDeliverStatus
22 | func setupWithDeliverStatus(_ status : FTChatMessageDeliverStatus) {
23 | self.backgroundColor = UIColor.clear
24 | self.addSubview(activityIndicator)
25 | switch status {
26 | case .sending:
27 | activityIndicator.startAnimating()
28 | self.setBackgroundImage(nil, for: UIControlState())
29 | case .succeeded:
30 | activityIndicator.stopAnimating()
31 | self.setBackgroundImage(nil, for: UIControlState())
32 | case .failed:
33 | activityIndicator.stopAnimating()
34 | self.setBackgroundImage(UIImage(named: "FT_Error"), for: UIControlState())
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageConversation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageConversation.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 2017/1/12.
6 | // Copyright © 2017年 LiuFengting. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageConversation: NSObject {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageDataSource.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/8/19.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc protocol FTChatMessageDataSource : NSObjectProtocol {
12 |
13 | func ftChatMessageMessageArray() -> [FTChatMessageModel]
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageDelegate.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/8/19.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc protocol FTChatMessageDelegate : NSObjectProtocol {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageExtensions.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 2017/1/12.
6 | // Copyright © 2017年 LiuFengting. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageExtensions: NSObject {
12 |
13 | }
14 |
15 | extension UIView {
16 |
17 | public var width: CGFloat {
18 | return self.frame.size.width
19 | }
20 | public var height: CGFloat {
21 | return self.frame.size.height
22 | }
23 |
24 | }
25 |
26 |
27 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageHeader/FTChatMessageHeader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageHeader.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/28.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol FTChatMessageHeaderDelegate {
12 | func ft_chatMessageHeaderDidTappedOnIcon(_ messageSenderModel : FTChatMessageUserModel)
13 | }
14 |
15 | class FTChatMessageHeader: UILabel {
16 |
17 | var iconButton : UIButton!
18 | var messageSenderModel : FTChatMessageUserModel!
19 | var headerViewDelegate : FTChatMessageHeaderDelegate?
20 |
21 | lazy var messageSenderNameLabel: UILabel! = {
22 | let label = UILabel(frame: CGRect.zero)
23 | label.font = FTDefaultTimeLabelFont
24 | label.textAlignment = .center
25 | label.textColor = UIColor.lightGray
26 | return label
27 | }()
28 |
29 |
30 |
31 | convenience init(frame: CGRect, senderModel: FTChatMessageUserModel ) {
32 | self.init(frame : frame)
33 |
34 |
35 | messageSenderModel = senderModel;
36 | self.setupHeader( senderModel, isSender: senderModel.isUserSelf)
37 | }
38 |
39 |
40 |
41 | fileprivate func setupHeader(_ user : FTChatMessageUserModel, isSender: Bool){
42 | self.backgroundColor = UIColor.clear
43 |
44 | let iconRect = isSender ? CGRect(x: self.frame.width-FTDefaultMargin-FTDefaultIconSize, y: FTDefaultMargin, width: FTDefaultIconSize, height: FTDefaultIconSize) : CGRect(x: FTDefaultMargin, y: FTDefaultMargin, width: FTDefaultIconSize, height: FTDefaultIconSize)
45 | iconButton = UIButton(frame: iconRect)
46 | iconButton.backgroundColor = isSender ? FTDefaultOutgoingColor : FTDefaultIncomingColor
47 | iconButton.layer.cornerRadius = FTDefaultIconSize/2;
48 | iconButton.clipsToBounds = true
49 | iconButton.isUserInteractionEnabled = true
50 | iconButton.addTarget(self, action: #selector(self.iconTapped), for: UIControlEvents.touchUpInside)
51 | self.addSubview(iconButton)
52 |
53 | if (user.senderIconUrl != nil) {
54 | // iconButton.kf.setBackgroundImage(with: URL(string : user.senderIconUrl!), for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
55 | }
56 |
57 |
58 | // var nameLabelRect = CGRect( x: 0, y: 0 , width: FTScreenWidth - (FTDefaultMargin*2 + FTDefaultIconSize), height: FTDefaultSectionHeight)
59 | // var nameLabelTextAlignment : NSTextAlignment = .right
60 | //
61 | // if isSender == false {
62 | // nameLabelRect.origin.x = FTDefaultMargin + FTDefaultIconSize + FTDefaultMargin
63 | // nameLabelTextAlignment = .left
64 | // }
65 | //
66 | // messageSenderNameLabel.frame = nameLabelRect
67 | // messageSenderNameLabel.text = user.senderName
68 | // messageSenderNameLabel.textAlignment = nameLabelTextAlignment
69 | // self.addSubview(messageSenderNameLabel)
70 |
71 |
72 |
73 | }
74 |
75 |
76 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
77 | if self.iconButton.frame.contains(point) {
78 | return self.iconButton
79 | }
80 | return nil
81 | }
82 |
83 |
84 |
85 | @objc func iconTapped() {
86 | if (headerViewDelegate != nil) {
87 | headerViewDelegate?.ft_chatMessageHeaderDidTappedOnIcon(messageSenderModel)
88 | }
89 | }
90 |
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageAccessoryItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageAccessoryItem.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/9/22.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //MARK: - FTChatMessageAccessoryItem -
12 |
13 | class FTChatMessageAccessoryItem : UIButton {
14 |
15 | @IBOutlet weak var accessoryImageView: UIImageView!
16 | @IBOutlet weak var accessoryNameLabel: UILabel!
17 |
18 | func setupWithAccessoryViewModel(_ viewModel : FTChatMessageAccessoryViewModel, index : NSInteger) {
19 |
20 | self.tag = index
21 | self.accessoryImageView.image = viewModel.iconImage
22 | self.accessoryNameLabel.text = viewModel.title
23 | }
24 |
25 | }
26 |
27 | //MARK: - FTChatMessageAccessoryViewModel -
28 |
29 | class FTChatMessageAccessoryViewModel: NSObject {
30 | var title : String = ""
31 | var iconImage : UIImage? = nil
32 |
33 | convenience init(title: String, iconImage: UIImage?) {
34 | self.init()
35 | self.title = title
36 | self.iconImage = iconImage
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageAccessoryItem.xib:
--------------------------------------------------------------------------------
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageAccessoryView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageAccessoryView.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/4/21.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | //MARK: - FTChatMessageAccessoryViewDataSource -
12 |
13 | @objc protocol FTChatMessageAccessoryViewDataSource : NSObjectProtocol {
14 |
15 | func ftChatMessageAccessoryViewModelArray() -> [FTChatMessageAccessoryViewModel]
16 | }
17 |
18 | //MARK: - FTChatMessageAccessoryViewDelegate -
19 |
20 | @objc protocol FTChatMessageAccessoryViewDelegate : NSObjectProtocol {
21 |
22 | func ftChatMessageAccessoryViewDidTappedOnItemAtIndex(_ index : NSInteger)
23 |
24 | }
25 |
26 | //MARK: - FTChatMessageAccessoryView -
27 |
28 | class FTChatMessageAccessoryView: UIView, UIScrollViewDelegate{
29 |
30 | @IBOutlet weak var scrollView: UIScrollView!
31 | @IBOutlet weak var pageControl: UIPageControl!
32 | var accessoryDataSource : FTChatMessageAccessoryViewDataSource!
33 | var accessoryDelegate : FTChatMessageAccessoryViewDelegate!
34 |
35 | //MARK: - awakeFromNib
36 | override func awakeFromNib() {
37 | super.awakeFromNib()
38 | scrollView.scrollsToTop = false
39 | scrollView.delegate = self
40 | }
41 |
42 | //MARK: - setupWithDataSource
43 | func setupWithDataSource(_ accessoryViewDataSource : FTChatMessageAccessoryViewDataSource , accessoryViewDelegate : FTChatMessageAccessoryViewDelegate) {
44 |
45 | self.setNeedsLayout()
46 |
47 | accessoryDataSource = accessoryViewDataSource
48 | accessoryDelegate = accessoryViewDelegate
49 |
50 | if self.accessoryDelegate == nil || self.accessoryDataSource == nil {
51 | NSException(name: NSExceptionName(rawValue: "Notice"), reason: "FTChatMessageAccessoryView. Missing accessoryDelegate or accessoryDelegate", userInfo: nil).raise()
52 | return
53 | }else{
54 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(Double(0.1) * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) {
55 | self.setupAccessoryView()
56 | }
57 | }
58 | }
59 |
60 | //MARK: - setupAccessoryView
61 | func setupAccessoryView() {
62 |
63 | self.layoutIfNeeded()
64 |
65 | for items in self.scrollView.subviews {
66 | if items.isKind(of: FTChatMessageAccessoryItem.classForCoder()) {
67 | items.removeFromSuperview()
68 | }
69 | }
70 |
71 |
72 | let modelArray = accessoryDataSource.ftChatMessageAccessoryViewModelArray()
73 |
74 | let totalCount = modelArray.count
75 | let totalPage = NSInteger(ceilf(Float(totalCount) / 8))
76 | self.pageControl.numberOfPages = totalPage
77 | self.scrollView.contentSize = CGSize(width: self.bounds.width * CGFloat(totalPage), height: self.bounds.height)
78 |
79 | let xMargin : CGFloat = (self.bounds.width - FTDefaultAccessoryViewLeftMargin*2 - FTDefaultAccessoryViewItemWidth*4)/3
80 | let yMargin : CGFloat = (self.bounds.height - FTDefaultAccessoryViewTopMargin - FTDefaultAccessoryViewBottomMargin - FTDefaultAccessoryViewItemHeight*2)
81 |
82 | for i in 0...totalCount-1 {
83 | let currentPage = i / 8
84 | let indexForCurrentPage = i % 8
85 |
86 | let x = self.bounds.width * CGFloat(currentPage) + FTDefaultAccessoryViewLeftMargin + (xMargin + FTDefaultAccessoryViewItemWidth)*CGFloat(i % 4)
87 | let y = FTDefaultAccessoryViewTopMargin + (yMargin + FTDefaultAccessoryViewItemHeight) * CGFloat(indexForCurrentPage / 4)
88 |
89 | let item : FTChatMessageAccessoryItem = Bundle.main.loadNibNamed("FTChatMessageAccessoryItem", owner: nil, options: nil)![0] as! FTChatMessageAccessoryItem
90 | item.frame = CGRect(x: x, y: y, width: FTDefaultAccessoryViewItemWidth, height: FTDefaultAccessoryViewItemHeight)
91 |
92 | let model = modelArray[i]
93 |
94 | item.setupWithAccessoryViewModel(model, index: i)
95 | item.addTarget(self, action: #selector(self.buttonItemTapped(_:)), for: UIControlEvents.touchUpInside)
96 | self.scrollView.addSubview(item)
97 | }
98 | }
99 |
100 | //MARK: - scrollViewDidEndDecelerating
101 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
102 | let currentPage = lroundf(Float(scrollView.contentOffset.x/self.bounds.width))
103 | self.pageControl.currentPage = currentPage
104 | }
105 |
106 |
107 | //MARK: - buttonItemTapped
108 | @objc func buttonItemTapped(_ sender : UIButton) {
109 | if (accessoryDelegate != nil) {
110 | accessoryDelegate.ftChatMessageAccessoryViewDidTappedOnItemAtIndex(sender.tag)
111 | }
112 | }
113 |
114 | }
115 |
116 |
117 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageAccessoryView.xib:
--------------------------------------------------------------------------------
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageInputView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageInputView.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/3/22.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | enum FTChatMessageInputMode {
12 | case keyboard
13 | case record
14 | case accessory
15 | case none
16 | }
17 |
18 | protocol FTChatMessageInputViewDelegate {
19 | func ft_chatMessageInputViewShouldBeginEditing()
20 | func ft_chatMessageInputViewShouldEndEditing()
21 | func ft_chatMessageInputViewShouldUpdateHeight(_ desiredHeight : CGFloat)
22 | func ft_chatMessageInputViewShouldDoneWithText(_ textString : String)
23 | func ft_chatMessageInputViewShouldShowRecordView()
24 | func ft_chatMessageInputViewShouldShowAccessoryView()
25 | }
26 |
27 | class FTChatMessageInputView: UIToolbar, UITextViewDelegate{
28 |
29 | var inputDelegate : FTChatMessageInputViewDelegate?
30 |
31 | @IBOutlet weak var recordButton: UIButton!
32 | @IBOutlet weak var inputTextView: UITextView!
33 | @IBOutlet weak var accessoryButton: UIButton!
34 | @IBOutlet weak var inputTextViewTopMargin: NSLayoutConstraint! {
35 | didSet {
36 | self.layoutIfNeeded()
37 | }
38 | }
39 | @IBOutlet weak var inputTextViewBottomMargin: NSLayoutConstraint! {
40 | didSet {
41 | self.layoutIfNeeded()
42 | }
43 | }
44 |
45 |
46 | //MARK: - awakeFromNib -
47 | override func awakeFromNib() {
48 | super.awakeFromNib()
49 |
50 | inputTextView.layer.cornerRadius = FTDefaultInputViewTextCornerRadius
51 | inputTextView.layer.borderColor = UIColor.lightGray.cgColor
52 | inputTextView.layer.borderWidth = 0.5
53 | inputTextView.textContainerInset = FTDefaultInputTextViewEdgeInset
54 | inputTextView.delegate = self
55 |
56 | self.bringSubview(toFront: self.inputTextView);
57 | self.bringSubview(toFront: self.recordButton);
58 | self.bringSubview(toFront: self.accessoryButton);
59 | }
60 |
61 | //MARK: - layoutSubviews -
62 | override func layoutSubviews() {
63 | super.layoutSubviews()
64 |
65 | if self.inputTextView.attributedText.length > 0 {
66 | self.inputTextView.scrollRangeToVisible(NSMakeRange(self.inputTextView.attributedText.length - 1, 1))
67 | }
68 | }
69 |
70 | //MARK: - recordButtonTapped -
71 | @IBAction func recordButtonTapped(_ sender: UIButton) {
72 | if (inputDelegate != nil) {
73 | inputDelegate!.ft_chatMessageInputViewShouldShowRecordView()
74 | }
75 | }
76 | //MARK: - accessoryButtonTapped -
77 | @IBAction func accessoryButtonTapped(_ sender: UIButton) {
78 | if (inputDelegate != nil) {
79 | inputDelegate!.ft_chatMessageInputViewShouldShowAccessoryView()
80 | }
81 | }
82 |
83 | //MARK: - clearText -
84 | func clearText(){
85 | inputTextView.text = ""
86 | if (inputDelegate != nil) {
87 | inputDelegate!.ft_chatMessageInputViewShouldUpdateHeight(FTDefaultInputViewHeight)
88 | }
89 | }
90 |
91 | //MARK: - UITextViewDelegate -
92 | func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
93 | if (inputDelegate != nil) {
94 | inputDelegate!.ft_chatMessageInputViewShouldBeginEditing()
95 | }
96 | return true
97 | }
98 | func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
99 | if (inputDelegate != nil) {
100 | inputDelegate!.ft_chatMessageInputViewShouldEndEditing()
101 | }
102 | return true
103 | }
104 |
105 | func textViewDidChange(_ textView: UITextView) {
106 | if let text : NSAttributedString = textView.attributedText {
107 | let textRect = text.boundingRect(with: CGSize(width: textView.bounds.width - textView.textContainerInset.left - textView.textContainerInset.right, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin , .usesFontLeading, .truncatesLastVisibleLine], context: nil);
108 |
109 | if (inputDelegate != nil) {
110 | inputDelegate!.ft_chatMessageInputViewShouldUpdateHeight(min(max(textRect.height + inputTextViewTopMargin.constant + inputTextViewBottomMargin.constant + textView.textContainerInset.top + textView.textContainerInset.bottom, FTDefaultInputViewHeight), FTDefaultInputViewMaxHeight))
111 | }
112 | }
113 | }
114 |
115 | func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
116 | if (text == "\n") {
117 | if (textView.text as NSString).length > 0 {
118 | if (inputDelegate != nil) {
119 | inputDelegate!.ft_chatMessageInputViewShouldDoneWithText(textView.text)
120 | self.clearText()
121 | }
122 | }
123 | return false
124 | }
125 | return true
126 | }
127 |
128 |
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageInputView.xib:
--------------------------------------------------------------------------------
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageRecorderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageRecorderView.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/4/20.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc protocol FTChatMessageRecorderViewDelegate : NSObjectProtocol {
12 |
13 | func ft_chatMessageRecordViewDidStartRecording()
14 | func ft_chatMessageRecordViewDidCancelRecording()
15 | func ft_chatMessageRecordViewDidStopRecording(_ duriation: TimeInterval, file: Data?)
16 |
17 | }
18 |
19 |
20 | class FTChatMessageRecorderView: UIView {
21 |
22 | @IBOutlet weak var recordButton: UIButton!
23 | @IBOutlet weak var descriptionLabel: UILabel!
24 | var recorderTimer : Timer!
25 | var recorderDelegate : FTChatMessageRecorderViewDelegate!
26 |
27 |
28 | @IBAction func buttonTouchDown(_ sender: UIButton) {
29 | self.startRecording()
30 | if recorderDelegate != nil {
31 | recorderDelegate.ft_chatMessageRecordViewDidStartRecording()
32 | }
33 | }
34 |
35 | @IBAction func buttonTouchUpInside(_ sender: UIButton) {
36 | if recorderDelegate != nil {
37 | recorderDelegate.ft_chatMessageRecordViewDidStopRecording(10, file: nil)
38 | }
39 | }
40 |
41 | @IBAction func buttonTouchUpOutside(_ sender: UIButton) {
42 | if recorderDelegate != nil {
43 | recorderDelegate.ft_chatMessageRecordViewDidCancelRecording()
44 | }
45 | }
46 |
47 |
48 | @IBAction func buttonTouchCancel(_ sender: UIButton) {
49 |
50 | if recorderDelegate != nil {
51 | recorderDelegate.ft_chatMessageRecordViewDidCancelRecording()
52 | }
53 | }
54 |
55 | func startRecording() {
56 |
57 | }
58 | func stopRecording() {
59 |
60 |
61 |
62 | }
63 |
64 |
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageInput/FTChatMessageRecorderView.xib:
--------------------------------------------------------------------------------
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageMarcos.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageMarcos.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/28.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /**
12 | FTChatMessageType
13 |
14 | - Text: Text message
15 | - Image: Image message
16 | - Audio: Audio message
17 | - Video: Video message
18 | - Location: Location message
19 | */
20 | enum FTChatMessageType {
21 | case text
22 | case image
23 | case audio
24 | case video
25 | case location
26 | case Share
27 | case More
28 | }
29 |
30 | public var FTScreenWidth : CGFloat { return UIScreen.main.bounds.size.width }
31 | public var FTScreenHeight : CGFloat { return UIScreen.main.bounds.size.height }
32 |
33 |
34 | let FTDefaultMargin : CGFloat = 5.0
35 | //MARK: - TimeLabel -
36 | let FTDefaultTimeLabelHeight : CGFloat = 10.0
37 | let FTDefaultTimeLabelFont : UIFont = UIFont.systemFont(ofSize: 10)
38 | //MARK: - NameLabel -
39 | let FTDefaultNameLabelHeight : CGFloat = 20.0
40 | let FTDefaultNameLabelFont : UIFont = UIFont.systemFont(ofSize: 12)
41 | //MARK: - Input -
42 | let FTDefaultInputViewHeight : CGFloat = 44.0
43 | let FTDefaultInputViewMargin : CGFloat = 8.0
44 | let FTDefaultInputViewTextCornerRadius : CGFloat = 8.0
45 | let FTDefaultInputViewMaxHeight : CGFloat = 150.0
46 | let FTDefaultInputTextViewEdgeInset: UIEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5)
47 | let FTDefaultInputViewBackgroundColor : UIColor = UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1)
48 | //MARK: - Accessory -
49 | let FTDefaultAccessoryViewHeight : CGFloat = 216.0
50 | let FTDefaultAccessoryViewItemWidth : CGFloat = 60.0
51 | let FTDefaultAccessoryViewItemHeight : CGFloat = 80.0
52 | let FTDefaultAccessoryViewTopMargin : CGFloat = 15.0
53 | let FTDefaultAccessoryViewLeftMargin : CGFloat = 25.0
54 | let FTDefaultAccessoryViewBottomMargin : CGFloat = 30.0
55 | //MARK: - MessageBubble -
56 | let FTDefaultMessageBubbleTextInViewMaxWidth : CGFloat = FTScreenWidth*0.65
57 | let FTDefaultMessageBubbleAngleWidth : CGFloat = 6.0
58 | let FTDefaultMessageBubbleImageWidth : CGFloat = FTScreenWidth*0.48
59 | let FTDefaultMessageBubbleImageHeight : CGFloat = FTDefaultMessageBubbleImageWidth*0.62
60 | let FTDefaultMessageBubbleMapViewWidth : CGFloat = FTDefaultMessageBubbleImageWidth
61 | let FTDefaultMessageBubbleMapViewHeight : CGFloat = FTDefaultMessageBubbleImageHeight
62 | let FTDefaultMessageBubbleAudioHeight : CGFloat = 36.0
63 | let FTDefaultMessageBubbleAudioIconHeight : CGFloat = 24.0
64 | let FTDefaultMessageBubbleMediaIconHeight : CGFloat = 30.0
65 | //MARK: - MessageCell -
66 | let FTDefaultMessageCellTimeLabelHeight : CGFloat = 20.0
67 | let FTDefaultMessageCellSendStatusViewSize : CGFloat = 20.0
68 | let FTDefaultMessageCellIconToMessageMargin : CGFloat = 2.0
69 | let FTDefaultMessageCellReuseIndentifier = "FTDefaultMessageCellReuseIndentifier"
70 |
71 |
72 | let FTDefaultTextTopMargin : CGFloat = 10.0
73 | let FTDefaultTextLeftMargin : CGFloat = 15.0
74 | let FTDefaultLineSpacing : CGFloat = 2.0
75 | let FTDefaultSectionHeight : CGFloat = 40.0
76 | let FTDefaultIconSize : CGFloat = 30.0
77 | let FTDefaultMessageRoundCorner : CGFloat = 16.0
78 | let FTDefaultFontSize : UIFont = UIFont.systemFont(ofSize: 14)
79 | let FTDefaultOutgoingColor : UIColor = UIColor(red: 1/255, green: 123/255, blue: 225/255, alpha: 1)
80 | let FTDefaultIncomingColor : UIColor = UIColor(red: 229/255, green: 229/255, blue: 234/255, alpha: 1)
81 | //MARK: - Animation -
82 | let FTDefaultMessageDefaultAnimationDuration : Double = 0.3
83 |
84 |
85 |
86 | class FTChatMessagePublicMethods {
87 |
88 | class func getFTDefaultMessageParagraphStyle() -> NSMutableParagraphStyle{
89 | let paragraphStyle : NSMutableParagraphStyle = NSMutableParagraphStyle()
90 | paragraphStyle.lineSpacing = FTDefaultLineSpacing
91 | return paragraphStyle;
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageModel.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/28.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // MARK: - FTChatMessageDeliverStatus
12 |
13 | enum FTChatMessageDeliverStatus {
14 | case sending
15 | case succeeded
16 | case failed
17 | }
18 |
19 | // MARK: - FTChatMessageModel
20 |
21 | class FTChatMessageModel: NSObject {
22 |
23 | var targetId : String!
24 | var isUserSelf : Bool = false;
25 | var messageText : String!
26 | var messageTimeStamp : String!
27 | var messageType : FTChatMessageType = .text
28 | var messageSender : FTChatMessageUserModel!
29 | var messageExtraData : NSDictionary?
30 | var messageDeliverStatus : FTChatMessageDeliverStatus = FTChatMessageDeliverStatus.succeeded
31 |
32 | // MARK: - convenience init
33 |
34 | convenience init(data : String? ,time : String?, from : FTChatMessageUserModel, type : FTChatMessageType){
35 | self.init()
36 | self.transformMessage(data,time : time,extraDic: nil,from: from,type: type)
37 | }
38 |
39 | convenience init(data : String?,time : String?, extraDic : NSDictionary?, from : FTChatMessageUserModel, type : FTChatMessageType){
40 | self.init()
41 | self.transformMessage(data,time : time,extraDic: extraDic,from: from,type: type)
42 | }
43 |
44 | // MARK: - transformMessage
45 |
46 | fileprivate func transformMessage(_ data : String? ,time : String?, extraDic : NSDictionary?, from : FTChatMessageUserModel, type : FTChatMessageType){
47 | messageType = type
48 | messageText = data
49 | messageTimeStamp = time
50 | messageSender = from
51 | isUserSelf = from.isUserSelf
52 | if (extraDic != nil) {
53 | messageExtraData = extraDic;
54 | }
55 | }
56 |
57 | }
58 |
59 | class FTChatMessageImageModel: FTChatMessageModel {
60 |
61 | var image : UIImage!
62 | var imageUrl : String!
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageTableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageTableViewController.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/2/28.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageTableViewController: UIViewController, UITableViewDelegate,UITableViewDataSource, FTChatMessageInputViewDelegate, FTChatMessageHeaderDelegate {
12 |
13 | var chatMessageDataArray : [FTChatMessageModel] = [] {
14 | didSet {
15 | self.origanizeAndReload()
16 | }
17 | }
18 | open var messageArray : [[FTChatMessageModel]] = []
19 | var delegete : FTChatMessageDelegate?
20 | var dataSource : FTChatMessageDataSource?
21 | var messageInputMode : FTChatMessageInputMode = FTChatMessageInputMode.none
22 |
23 | let sender2 = FTChatMessageUserModel.init(id: "2", name: "LiuFengting", icon_url: "http://ww3.sinaimg.cn/mw600/9d319f9agw1f3k8e4pixfj20u00u0ac6.jpg", extra_data: nil, isSelf: true)
24 |
25 |
26 |
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 |
30 | self.view.addSubview(messageTableView)
31 |
32 | self.view.addSubview(messageInputView)
33 |
34 | self.view.addSubview(messageRecordView)
35 |
36 | self.view.addSubview(messageAccessoryView)
37 |
38 | DispatchQueue.main.asyncAfter( deadline: DispatchTime.now() + Double(Int64(0.1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) {
39 | self.scrollToBottom(false)
40 | }
41 | }
42 |
43 |
44 |
45 |
46 |
47 | lazy var messageTableView : UITableView! = {
48 | let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: FTScreenWidth, height: FTScreenHeight), style: .plain)
49 | tableView.separatorStyle = .none
50 | tableView.allowsSelection = false
51 | tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
52 | tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, FTDefaultInputViewHeight, 0)
53 | tableView.delegate = self
54 | tableView.dataSource = self
55 |
56 | let footer = UIView(frame: CGRect( x: 0, y: 0, width: FTScreenWidth, height: FTDefaultInputViewHeight))
57 | tableView.tableFooterView = footer
58 |
59 | return tableView
60 | }()
61 |
62 | lazy var messageInputView : FTChatMessageInputView! = {
63 | let inputView : FTChatMessageInputView! = Bundle.main.loadNibNamed("FTChatMessageInputView", owner: nil, options: nil)?[0] as! FTChatMessageInputView
64 | inputView.frame = CGRect(x: 0, y: FTScreenHeight-FTDefaultInputViewHeight, width: FTScreenWidth, height: FTDefaultInputViewHeight)
65 | inputView.inputDelegate = self
66 | return inputView
67 | }()
68 |
69 | lazy var messageRecordView : FTChatMessageRecorderView! = {
70 | let recordView : FTChatMessageRecorderView! = Bundle.main.loadNibNamed("FTChatMessageRecorderView", owner: nil, options: nil)?[0] as! FTChatMessageRecorderView
71 | recordView.frame = CGRect(x: 0, y: FTScreenHeight, width: FTScreenWidth, height: FTDefaultAccessoryViewHeight)
72 | return recordView
73 | }()
74 |
75 | lazy var messageAccessoryView : FTChatMessageAccessoryView! = {
76 | let accessoryView = Bundle.main.loadNibNamed("FTChatMessageAccessoryView", owner: nil, options: nil)?[0] as! FTChatMessageAccessoryView
77 | accessoryView.frame = CGRect(x: 0, y: FTScreenHeight, width: FTScreenWidth, height: FTDefaultAccessoryViewHeight)
78 | return accessoryView
79 | }()
80 |
81 |
82 |
83 |
84 | func repositionEverything() {
85 | self.messageTableView.frame = CGRect(x: 0, y: 0, width: FTScreenWidth, height: FTScreenHeight)
86 | self.messageInputView.frame = CGRect(x: 0, y: FTScreenHeight-FTDefaultInputViewHeight, width: FTScreenWidth, height: FTDefaultInputViewHeight)
87 | self.messageRecordView.frame = CGRect(x: 0, y: FTScreenHeight, width: FTScreenWidth, height: FTDefaultAccessoryViewHeight)
88 | self.messageAccessoryView.frame = CGRect(x: 0, y: FTScreenHeight, width: FTScreenWidth, height: FTDefaultAccessoryViewHeight)
89 | self.messageTableView.reloadData()
90 | }
91 |
92 |
93 |
94 |
95 |
96 |
97 | internal func addNewMessage(_ message : FTChatMessageModel) {
98 |
99 | chatMessageDataArray.append(message);
100 |
101 | self.origanizeAndReload()
102 |
103 | self.scrollToBottom(true)
104 |
105 | }
106 |
107 | func origanizeAndReload() {
108 | var nastyArray : [[FTChatMessageModel]] = []
109 | var tempArray : [FTChatMessageModel] = []
110 | var tempId = ""
111 | for i in 0...chatMessageDataArray.count-1 {
112 | let message = chatMessageDataArray[i]
113 | if message.messageSender.senderId == tempId {
114 | tempArray.append(message)
115 | }else{
116 | tempId = message.messageSender.senderId;
117 | if tempArray.count > 0 {
118 | nastyArray.append(tempArray)
119 | }
120 | tempArray.removeAll()
121 | tempArray.append(message)
122 | }
123 | if i == chatMessageDataArray.count - 1 {
124 | if tempArray.count > 0 {
125 | nastyArray.append(tempArray)
126 | }
127 | }
128 | }
129 |
130 | self.messageArray = nastyArray
131 | self.messageTableView.reloadData()
132 | }
133 |
134 |
135 |
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageUserModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FTChatMessageUserModel.swift
3 | // FTChatMessage
4 | //
5 | // Created by liufengting on 16/8/21.
6 | // Copyright © 2016年 liufengting . All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class FTChatMessageUserModel : NSObject{
12 |
13 | var isUserSelf : Bool = false;
14 | var senderId : String!
15 | var senderName : String!
16 | var senderIconUrl : String!
17 | var senderExtraData : NSDictionary?
18 |
19 | // MARK: - convenience init
20 | convenience init(id : String? ,name : String?, icon_url : String?, extra_data : NSDictionary?, isSelf : Bool){
21 | self.init()
22 | senderId = id
23 | senderName = name
24 | senderIconUrl = icon_url
25 | senderExtraData = extra_data
26 | isUserSelf = isSelf
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Liu Fengting
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # FTChatMessage
4 |
5 | [](http://twitter.com/liufengting)
6 | [](https://raw.githubusercontent.com/liufengting/FTChatMessage/master/LICENSE)
7 | [](https://github.com/liufengting/FTChatMessage/stargazers)
8 |
9 |
10 | # Working in progress
11 |
12 | Still working in progress.
13 |
14 | # Requirements
15 |
16 | Swift 3.0 Xcode 8.0
17 |
18 | # CHANGELOG
19 |
20 | [See CHANGELOG](https://github.com/liufengting/FTChatMessage/blob/master/CHANGELOG.md)
21 |
22 | # ScreenShots
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | # Preview
34 |
35 |
36 |
37 |
38 | # Something
39 |
40 | 24 Dec, 2016. It's Christmas tomorrow. It's hard for me to focus on something recently. I'm thinking of rewrite it from the ground up. I have been write some other frameworks that I'm interested in, mostly not perfect. So sometimes I feel so depressed.
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ResourceImages/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/ResourceImages/1.jpg
--------------------------------------------------------------------------------
/ResourceImages/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/ResourceImages/2.jpg
--------------------------------------------------------------------------------
/ResourceImages/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/ResourceImages/3.jpg
--------------------------------------------------------------------------------
/ResourceImages/ChatMessageDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessage/4eab5515d975681735ac7df1f19d0af259dc7b61/ResourceImages/ChatMessageDemo.gif
--------------------------------------------------------------------------------