*)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) 2015 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/README.md:
--------------------------------------------------------------------------------
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 | Kingfisher is a lightweight, pure-Swift library for downloading and caching images from the web. This project is heavily inspired by the popular [SDWebImage](https://github.com/rs/SDWebImage). It provides you a chance to use a pure-Swift alternative in your next app.
29 |
30 | ## Features
31 |
32 | - [x] Asynchronous image downloading and caching.
33 | - [x] `URLSession`-based networking. Basic image processors and filters supplied.
34 | - [x] Multiple-layer cache for both memory and disk.
35 | - [x] Cancelable downloading and processing tasks to improve performance.
36 | - [x] Independent components. Use the downloader or caching system separately as you need.
37 | - [x] Prefetching images and showing them from cache later when necessary.
38 | - [x] Extensions for `UIImageView`, `NSImage` and `UIButton` to directly set an image from a URL.
39 | - [x] Built-in transition animation when setting images.
40 | - [x] Extensible image processing and image format support.
41 |
42 | The simplest use-case is setting an image to an image view with the `UIImageView` extension:
43 |
44 | ```swift
45 | let url = URL(string: "url_of_your_image")
46 | imageView.kf.setImage(with: url)
47 | ```
48 |
49 | Kingfisher will download the image from `url`, send it to both the memory cache and the disk cache, and display it in `imageView`. When you use the same code later, the image will be retrieved from cache and shown immediately.
50 |
51 | ## Requirements
52 |
53 | - iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
54 | - Swift 3 (Kingfisher 3.x), Swift 2.3 (Kingfisher 2.x)
55 |
56 | Main development of Kingfisher will support Swift 3. Only critical bug fixes will be made for Kingfisher 2.x.
57 |
58 | [Kingfisher 3.0 Migration Guide](https://github.com/onevcat/Kingfisher/wiki/Kingfisher-3.0-Migration-Guide) - If you are upgrading to Kingfisher 3.x from an earlier version, please read this for more information.
59 |
60 | ## Next Steps
61 |
62 | We prepared a [wiki page](https://github.com/onevcat/Kingfisher/wiki). You can find tons of useful things there.
63 |
64 | * [Installation Guide](https://github.com/onevcat/Kingfisher/wiki/Installation-Guide) - Follow it to integrate Kingfisher into your project.
65 | * [Cheat Sheet](https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet)- Curious about what Kingfisher could do and how would it look like when used in your project? See this page for useful code snippets. If you are already familiar with Kingfisher, you could also learn new tricks to improve the way you use Kingfisher!
66 | * [API Reference](http://cocoadocs.org/docsets/Kingfisher/) - Lastly, please remember to read the full whenever you may need a more detailed reference.
67 |
68 | ## Other
69 |
70 | ### Future of Kingfisher
71 |
72 | I want to keep Kingfisher lightweight. This framework will focus on providing a simple solution for downloading and caching images. This doesn’t mean the framework can’t be improved. Kingfisher is far from perfect, so necessary and useful updates will be made to make it better.
73 |
74 | ### About the logo
75 |
76 | The logo of Kingfisher is inspired by [Tangram (七巧板)](http://en.wikipedia.org/wiki/Tangram), a dissection puzzle consisting of seven flat shapes from China. I believe she's a kingfisher bird instead of a swift, but someone insists that she is a pigeon. I guess I should give her a name. Hi, guys, do you have any suggestions?
77 |
78 | ### Contact
79 |
80 | Follow and contact me on [Twitter](http://twitter.com/onevcat) or [Sina Weibo](http://weibo.com/onevcat). If you find an issue, just [open a ticket](https://github.com/onevcat/Kingfisher/issues/new). Pull requests are warmly welcome as well.
81 |
82 | ### License
83 |
84 | Kingfisher is released under the MIT license. See LICENSE for details.
85 |
86 |
87 |
--------------------------------------------------------------------------------
/Demo/Pods/Kingfisher/Sources/Box.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Box.swift
3 | // Kingfisher
4 | //
5 | // Created by WANG WEI on 2016/09/12.
6 | // Copyright © 2016年 Wei Wang. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class Box {
12 | let value: T
13 | init(value: T) {
14 | self.value = value
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/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) 2016 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 scale = (options ?? KingfisherEmptyOptionsInfo).scaleFactor
81 | let preloadAllGIFData = (options ?? KingfisherEmptyOptionsInfo).preloadAllGIFData
82 |
83 | return Kingfisher.image(data: data, scale: scale, preloadAllGIFData: preloadAllGIFData)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/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) 2016 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 | return filter.outputImage?.cropping(to: input.extent)
75 | }
76 | }
77 |
78 | public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
79 |
80 | /// Color control filter which will apply color control change to images.
81 | public static var colorControl: (ColorElement) -> Filter = {
82 | brightness, contrast, saturation, inputEV in
83 | Filter { input in
84 | let paramsColor = [kCIInputBrightnessKey: brightness,
85 | kCIInputContrastKey: contrast,
86 | kCIInputSaturationKey: saturation]
87 |
88 | let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
89 | let paramsExposure = [kCIInputEVKey: inputEV]
90 | return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
91 | }
92 |
93 | }
94 | }
95 |
96 | extension Kingfisher where Base: Image {
97 | /// Apply a `Filter` containing `CIImage` transformer to `self`.
98 | ///
99 | /// - parameter filter: The filter used to transform `self`.
100 | ///
101 | /// - returns: A transformed image by input `Filter`.
102 | ///
103 | /// - Note: Only CG-based images are supported. If any error happens during transforming, `self` will be returned.
104 | public func apply(_ filter: Filter) -> Image {
105 |
106 | guard let cgImage = cgImage else {
107 | assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
108 | return base
109 | }
110 |
111 | let inputImage = CIImage(cgImage: cgImage)
112 | guard let outputImage = filter.transform(inputImage) else {
113 | return base
114 | }
115 |
116 | guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
117 | assertionFailure("[Kingfisher] Can not make an tint image within context.")
118 | return base
119 | }
120 |
121 | #if os(macOS)
122 | return fixedForRetinaPixel(cgImage: result, to: size)
123 | #else
124 | return Image(cgImage: result, scale: base.scale, orientation: base.imageOrientation)
125 | #endif
126 | }
127 |
128 | }
129 |
130 | public extension Image {
131 |
132 | /// Apply a `Filter` containing `CIImage` transformer to `self`.
133 | ///
134 | /// - parameter filter: The filter used to transform `self`.
135 | ///
136 | /// - returns: A transformed image by input `Filter`.
137 | ///
138 | /// - Note: Only CG-based images are supported. If any error happens during transforming, `self` will be returned.
139 | @available(*, deprecated,
140 | message: "Extensions directly on Image are deprecated. Use `kf.apply` instead.",
141 | renamed: "kf.apply")
142 | public func kf_apply(_ filter: Filter) -> Image {
143 | return kf.apply(filter)
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/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) 2016 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) 2016 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) 2016 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 Color = NSColor
34 | public typealias ImageView = NSImageView
35 | typealias Button = NSButton
36 | #else
37 | import UIKit
38 | public typealias Image = UIImage
39 | public typealias Color = UIColor
40 | #if !os(watchOS)
41 | public typealias ImageView = UIImageView
42 | typealias Button = UIButton
43 | #endif
44 | #endif
45 |
46 | public final class Kingfisher {
47 | public let base: Base
48 | public init(_ base: Base) {
49 | self.base = base
50 | }
51 | }
52 |
53 | /**
54 | A type that has Kingfisher extensions.
55 | */
56 | public protocol KingfisherCompatible {
57 | associatedtype CompatibleType
58 | var kf: CompatibleType { get }
59 | }
60 |
61 | public extension KingfisherCompatible {
62 | public var kf: Kingfisher {
63 | get { return Kingfisher(self) }
64 | }
65 | }
66 |
67 | extension Image: KingfisherCompatible { }
68 | #if !os(watchOS)
69 | extension ImageView: KingfisherCompatible { }
70 | extension Button: KingfisherCompatible { }
71 | #endif
72 |
--------------------------------------------------------------------------------
/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) 2016 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) 2016 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) 2016 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.1.5):
4 | - FTIndicator/FTNotificationIndicator (= 1.1.5)
5 | - FTIndicator/FTProgressIndicator (= 1.1.5)
6 | - FTIndicator/FTToastIndicator (= 1.1.5)
7 | - FTIndicator/FTNotificationIndicator (1.1.5)
8 | - FTIndicator/FTProgressIndicator (1.1.5)
9 | - FTIndicator/FTToastIndicator (1.1.5)
10 | - FTPickerView (1.0.1)
11 | - Kingfisher (3.2.4)
12 |
13 | DEPENDENCIES:
14 | - FTImageSize
15 | - FTIndicator
16 | - FTPickerView
17 | - Kingfisher
18 |
19 | SPEC CHECKSUMS:
20 | FTImageSize: 29c6fc0830dbe33973286148a8e32cd582a9f26d
21 | FTIndicator: 8b9885b84340a19029ad13672add3bb8183feba8
22 | FTPickerView: fd26852f56c352c777d1dafc87ed4c2138eeea4c
23 | Kingfisher: 8d80f39da403cd9c9ee11984e1655f4d6a566cdb
24 |
25 | PODFILE CHECKSUM: 0897bbd78b2258d0c7f01ee2e9d5eb5a802cde17
26 |
27 | COCOAPODS: 1.1.1
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 | #endif
4 |
5 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTImageSize/FTImageSize-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 |
6 | FOUNDATION_EXPORT double FTImageSizeVersionNumber;
7 | FOUNDATION_EXPORT const unsigned char FTImageSizeVersionString[];
8 |
9 |
--------------------------------------------------------------------------------
/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 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
9 | SKIP_INSTALL = YES
10 | SWIFT_VERSION = 3.0
11 |
--------------------------------------------------------------------------------
/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 | #endif
4 |
5 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTIndicator/FTIndicator-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 | #import "FTIndicator.h"
6 | #import "FTNotificationIndicator.h"
7 | #import "FTProgressIndicator.h"
8 | #import "FTToastIndicator.h"
9 | #import "FTNotificationIndicator.h"
10 | #import "FTProgressIndicator.h"
11 | #import "FTToastIndicator.h"
12 |
13 | FOUNDATION_EXPORT double FTIndicatorVersionNumber;
14 | FOUNDATION_EXPORT const unsigned char FTIndicatorVersionString[];
15 |
16 |
--------------------------------------------------------------------------------
/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 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
8 | SKIP_INSTALL = YES
9 |
--------------------------------------------------------------------------------
/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.1.5
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 | #endif
4 |
5 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/FTPickerView/FTPickerView-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 | #import "FTPickerView.h"
6 |
7 | FOUNDATION_EXPORT double FTPickerViewVersionNumber;
8 | FOUNDATION_EXPORT const unsigned char FTPickerViewVersionString[];
9 |
10 |
--------------------------------------------------------------------------------
/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 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
8 | SKIP_INSTALL = YES
9 |
--------------------------------------------------------------------------------
/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.1
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 | 3.2.4
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 | #endif
4 |
5 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Kingfisher/Kingfisher-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 | #import "Kingfisher.h"
6 |
7 | FOUNDATION_EXPORT double KingfisherVersionNumber;
8 | FOUNDATION_EXPORT const unsigned char KingfisherVersionString[];
9 |
10 |
--------------------------------------------------------------------------------
/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 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 | SWIFT_VERSION = 3.0
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 刘锋婷
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) 2015 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-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
6 |
7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
8 |
9 | install_framework()
10 | {
11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
12 | local source="${BUILT_PRODUCTS_DIR}/$1"
13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
15 | elif [ -r "$1" ]; then
16 | local source="$1"
17 | fi
18 |
19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 |
21 | if [ -L "${source}" ]; then
22 | echo "Symlinked..."
23 | source="$(readlink "${source}")"
24 | fi
25 |
26 | # use filter instead of exclude so missing patterns dont' throw errors
27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
29 |
30 | local basename
31 | basename="$(basename -s .framework "$1")"
32 | binary="${destination}/${basename}.framework/${basename}"
33 | if ! [ -r "$binary" ]; then
34 | binary="${destination}/${basename}"
35 | fi
36 |
37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
39 | strip_invalid_archs "$binary"
40 | fi
41 |
42 | # Resign the code if required by the build settings to avoid unstable apps
43 | code_sign_if_enabled "${destination}/$(basename "$1")"
44 |
45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
47 | local swift_runtime_libs
48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
49 | for lib in $swift_runtime_libs; do
50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
52 | code_sign_if_enabled "${destination}/${lib}"
53 | done
54 | fi
55 | }
56 |
57 | # Signs a framework with the provided identity
58 | code_sign_if_enabled() {
59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
60 | # Use the current code_sign_identitiy
61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
64 | fi
65 | }
66 |
67 | # Strip invalid architectures
68 | strip_invalid_archs() {
69 | binary="$1"
70 | # Get architectures for current file
71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
72 | stripped=""
73 | for arch in $archs; do
74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
75 | # Strip non-valid architectures in-place
76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
77 | stripped="$stripped $arch"
78 | fi
79 | done
80 | if [[ "$stripped" ]]; then
81 | echo "Stripped $binary of architectures:$stripped"
82 | fi
83 | }
84 |
85 |
86 | if [[ "$CONFIGURATION" == "Debug" ]]; then
87 | install_framework "$BUILT_PRODUCTS_DIR/FTImageSize/FTImageSize.framework"
88 | install_framework "$BUILT_PRODUCTS_DIR/FTIndicator/FTIndicator.framework"
89 | install_framework "$BUILT_PRODUCTS_DIR/FTPickerView/FTPickerView.framework"
90 | install_framework "$BUILT_PRODUCTS_DIR/Kingfisher/Kingfisher.framework"
91 | fi
92 | if [[ "$CONFIGURATION" == "Release" ]]; then
93 | install_framework "$BUILT_PRODUCTS_DIR/FTImageSize/FTImageSize.framework"
94 | install_framework "$BUILT_PRODUCTS_DIR/FTIndicator/FTIndicator.framework"
95 | install_framework "$BUILT_PRODUCTS_DIR/FTPickerView/FTPickerView.framework"
96 | install_framework "$BUILT_PRODUCTS_DIR/Kingfisher/Kingfisher.framework"
97 | fi
98 |
--------------------------------------------------------------------------------
/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 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | *)
22 | TARGET_DEVICE_ARGS="--target-device mac"
23 | ;;
24 | esac
25 |
26 | install_resource()
27 | {
28 | if [[ "$1" = /* ]] ; then
29 | RESOURCE_PATH="$1"
30 | else
31 | RESOURCE_PATH="${PODS_ROOT}/$1"
32 | fi
33 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
34 | cat << EOM
35 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
36 | EOM
37 | exit 1
38 | fi
39 | case $RESOURCE_PATH in
40 | *.storyboard)
41 | 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}"
42 | 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}
43 | ;;
44 | *.xib)
45 | 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}"
46 | 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}
47 | ;;
48 | *.framework)
49 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
50 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
51 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
52 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
53 | ;;
54 | *.xcdatamodel)
55 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
56 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
57 | ;;
58 | *.xcdatamodeld)
59 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
60 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
61 | ;;
62 | *.xcmappingmodel)
63 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
64 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
65 | ;;
66 | *.xcassets)
67 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
68 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
69 | ;;
70 | *)
71 | echo "$RESOURCE_PATH"
72 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
73 | ;;
74 | esac
75 | }
76 |
77 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
78 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
79 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
80 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
82 | fi
83 | rm -f "$RESOURCES_TO_COPY"
84 |
85 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
86 | then
87 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
88 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
89 | while read line; do
90 | if [[ $line != "${PODS_ROOT}*" ]]; then
91 | XCASSET_FILES+=("$line")
92 | fi
93 | done <<<"$OTHER_XCASSETS"
94 |
95 | 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}"
96 | fi
97 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 |
6 | FOUNDATION_EXPORT double Pods_DemoVersionNumber;
7 | FOUNDATION_EXPORT const unsigned char Pods_DemoVersionString[];
8 |
9 |
--------------------------------------------------------------------------------
/Demo/Pods/Target Support Files/Pods-Demo/Pods-Demo.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FTImageSize" "$PODS_CONFIGURATION_BUILD_DIR/FTIndicator" "$PODS_CONFIGURATION_BUILD_DIR/FTPickerView" "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | 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"
7 | OTHER_LDFLAGS = $(inherited) -framework "FTImageSize" -framework "FTIndicator" -framework "FTPickerView" -framework "Kingfisher"
8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
9 | PODS_BUILD_DIR = $BUILD_DIR
10 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
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 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/FTImageSize" "$PODS_CONFIGURATION_BUILD_DIR/FTIndicator" "$PODS_CONFIGURATION_BUILD_DIR/FTPickerView" "$PODS_CONFIGURATION_BUILD_DIR/Kingfisher"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | 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"
7 | OTHER_LDFLAGS = $(inherited) -framework "FTImageSize" -framework "FTIndicator" -framework "FTPickerView" -framework "Kingfisher"
8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
9 | PODS_BUILD_DIR = $BUILD_DIR
10 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
11 | PODS_ROOT = ${SRCROOT}/Pods
12 |
--------------------------------------------------------------------------------
/FTChatMessage/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/FTChatMessage/.DS_Store
--------------------------------------------------------------------------------
/FTChatMessage/FTChatMessageCell/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/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([NSFontAttributeName:FTDefaultFontSize,NSParagraphStyleAttributeName: 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 | // Demo
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 | // Demo
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 |
77 |
78 | @objc func iconTapped() {
79 | if (headerViewDelegate != nil) {
80 | headerViewDelegate?.ft_chatMessageHeaderDidTappedOnIcon(messageSenderModel)
81 | }
82 | }
83 |
84 |
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/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 | 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 | }
57 |
58 | //MARK: - layoutSubviews -
59 | override func layoutSubviews() {
60 | super.layoutSubviews()
61 |
62 | if self.inputTextView.attributedText.length > 0 {
63 | self.inputTextView.scrollRangeToVisible(NSMakeRange(self.inputTextView.attributedText.length - 1, 1))
64 | }
65 | }
66 |
67 | //MARK: - recordButtonTapped -
68 | @IBAction func recordButtonTapped(_ sender: UIButton) {
69 | if (inputDelegate != nil) {
70 | inputDelegate!.ft_chatMessageInputViewShouldShowRecordView()
71 | }
72 | }
73 | //MARK: - accessoryButtonTapped -
74 | @IBAction func accessoryButtonTapped(_ sender: UIButton) {
75 | if (inputDelegate != nil) {
76 | inputDelegate!.ft_chatMessageInputViewShouldShowAccessoryView()
77 | }
78 | }
79 |
80 | //MARK: - clearText -
81 | func clearText(){
82 | inputTextView.text = ""
83 | if (inputDelegate != nil) {
84 | inputDelegate!.ft_chatMessageInputViewShouldUpdateHeight(FTDefaultInputViewHeight)
85 | }
86 | }
87 |
88 | //MARK: - UITextViewDelegate -
89 | func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
90 | if (inputDelegate != nil) {
91 | inputDelegate!.ft_chatMessageInputViewShouldBeginEditing()
92 | }
93 | return true
94 | }
95 | func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
96 | if (inputDelegate != nil) {
97 | inputDelegate!.ft_chatMessageInputViewShouldEndEditing()
98 | }
99 | return true
100 | }
101 |
102 | func textViewDidChange(_ textView: UITextView) {
103 | if let text : NSAttributedString = textView.attributedText {
104 | let textRect = text.boundingRect(with: CGSize(width: textView.bounds.width - textView.textContainerInset.left - textView.textContainerInset.right, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin , .usesFontLeading], context: nil);
105 |
106 | if (inputDelegate != nil) {
107 | inputDelegate!.ft_chatMessageInputViewShouldUpdateHeight(min(max(textRect.height + inputTextViewTopMargin.constant + inputTextViewBottomMargin.constant + textView.textContainerInset.top + textView.textContainerInset.bottom, FTDefaultInputViewHeight), FTDefaultInputViewMaxHeight))
108 | }
109 | }
110 | }
111 |
112 | func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
113 | if (text == "\n") {
114 | if (textView.text as NSString).length > 0 {
115 | if (inputDelegate != nil) {
116 | inputDelegate!.ft_chatMessageInputViewShouldDoneWithText(textView.text)
117 | self.clearText()
118 | }
119 | }
120 | return false
121 | }
122 | return true
123 | }
124 |
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/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.width }
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 | lazy var messageTableView : UITableView! = {
27 | let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: FTScreenWidth, height: FTScreenHeight), style: .plain)
28 | tableView.separatorStyle = .none
29 | tableView.allowsSelection = false
30 | tableView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.onDrag
31 | tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, FTDefaultInputViewHeight, 0)
32 | tableView.delegate = self
33 | tableView.dataSource = self
34 |
35 | // let header = UIView(frame: CGRect( x: 0, y: 0, width: FTScreenWidth, height: FTDefaultMargin*2))
36 | // tableView.tableHeaderView = header
37 |
38 | let footer = UIView(frame: CGRect( x: 0, y: 0, width: FTScreenWidth, height: FTDefaultInputViewHeight))
39 | tableView.tableFooterView = footer
40 |
41 | return tableView
42 | }()
43 |
44 | lazy var messageInputView : FTChatMessageInputView! = {
45 | let inputView : FTChatMessageInputView! = Bundle.main.loadNibNamed("FTChatMessageInputView", owner: nil, options: nil)?[0] as! FTChatMessageInputView
46 | inputView.frame = CGRect(x: 0, y: FTScreenHeight-FTDefaultInputViewHeight, width: FTScreenWidth, height: FTDefaultInputViewHeight)
47 | inputView.inputDelegate = self
48 | return inputView
49 | }()
50 |
51 | lazy var messageRecordView : FTChatMessageRecorderView! = {
52 | let recordView : FTChatMessageRecorderView! = Bundle.main.loadNibNamed("FTChatMessageRecorderView", owner: nil, options: nil)?[0] as! FTChatMessageRecorderView
53 | recordView.frame = CGRect(x: 0, y: FTScreenHeight, width: FTScreenWidth, height: FTDefaultAccessoryViewHeight)
54 | return recordView
55 | }()
56 |
57 | lazy var messageAccessoryView : FTChatMessageAccessoryView! = {
58 | let accessoryView = Bundle.main.loadNibNamed("FTChatMessageAccessoryView", owner: nil, options: nil)?[0] as! FTChatMessageAccessoryView
59 | accessoryView.frame = CGRect(x: 0, y: FTScreenHeight, width: FTScreenWidth, height: FTDefaultAccessoryViewHeight)
60 | return accessoryView
61 | }()
62 |
63 |
64 |
65 |
66 |
67 | override func viewDidLoad() {
68 | super.viewDidLoad()
69 |
70 | self.view.addSubview(messageTableView)
71 |
72 | self.view.addSubview(messageInputView)
73 |
74 | self.view.addSubview(messageRecordView)
75 |
76 | self.view.addSubview(messageAccessoryView)
77 |
78 | DispatchQueue.main.asyncAfter( deadline: DispatchTime.now() + Double(Int64(0.1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) {
79 | self.scrollToBottom(false)
80 | }
81 | }
82 |
83 |
84 |
85 | override func viewDidAppear(_ animated: Bool) {
86 | super.viewDidAppear(animated)
87 |
88 |
89 | messageAccessoryView.setupAccessoryView()
90 | }
91 |
92 |
93 | override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
94 | return UIInterfaceOrientationMask.portrait
95 | }
96 |
97 |
98 | internal func addNewMessage(_ message : FTChatMessageModel) {
99 |
100 | chatMessageDataArray.append(message);
101 |
102 | self.origanizeAndReload()
103 |
104 | self.scrollToBottom(true)
105 |
106 | }
107 |
108 | func origanizeAndReload() {
109 | var nastyArray : [[FTChatMessageModel]] = []
110 | var tempArray : [FTChatMessageModel] = []
111 | var tempId = ""
112 | for i in 0...chatMessageDataArray.count-1 {
113 | let message = chatMessageDataArray[i]
114 | if message.messageSender.senderId == tempId {
115 | tempArray.append(message)
116 | }else{
117 | tempId = message.messageSender.senderId;
118 | if tempArray.count > 0 {
119 | nastyArray.append(tempArray)
120 | }
121 | tempArray.removeAll()
122 | tempArray.append(message)
123 | }
124 | if i == chatMessageDataArray.count - 1 {
125 | if tempArray.count > 0 {
126 | nastyArray.append(tempArray)
127 | }
128 | }
129 | }
130 |
131 | self.messageArray = nastyArray
132 | self.messageTableView.reloadData()
133 | }
134 |
135 |
136 |
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/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 | 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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FTChatMessageDemoProject
2 | # It has been moved to [FTChatMessage](https://github.com/liufengting/FTChatMessage).
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ResourceImages/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/ResourceImages/.DS_Store
--------------------------------------------------------------------------------
/ResourceImages/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/ResourceImages/1.jpg
--------------------------------------------------------------------------------
/ResourceImages/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/ResourceImages/2.jpg
--------------------------------------------------------------------------------
/ResourceImages/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/ResourceImages/3.jpg
--------------------------------------------------------------------------------
/ResourceImages/ChatMessageDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liufengting/FTChatMessageDemoProject/4fc15d6e64b945d79474960b761f36f3471f3a09/ResourceImages/ChatMessageDemo.gif
--------------------------------------------------------------------------------