├── .swift-version
├── Chidori
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Icon-29.png
│ │ ├── Icon-40.png
│ │ ├── Icon-76.png
│ │ ├── Icon-29@2x.png
│ │ ├── Icon-29@3x.png
│ │ ├── Icon-40@2x.png
│ │ ├── Icon-40@3x.png
│ │ ├── Icon-60@2x.png
│ │ ├── Icon-60@3x.png
│ │ ├── Icon-76@2x.png
│ │ ├── Icon-29@2x-1.png
│ │ ├── Icon-40@2x-1.png
│ │ └── Contents.json
│ ├── round_avatar_placeholder.imageset
│ │ ├── round_avatar_placeholder.pdf
│ │ └── Contents.json
│ └── square_avatar_placeholder.imageset
│ │ ├── square_avatar_placeholder.pdf
│ │ └── Contents.json
├── Helpers
│ ├── Config.swift
│ └── Filter.swift
├── Extensions
│ └── UIFont+Chidori.swift
├── AppDelegate.swift
├── Views
│ └── Cells
│ │ └── Avatar
│ │ ├── AvatarCell.swift
│ │ └── AvatarCell.xib
├── Info.plist
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
└── ViewControllers
│ └── AvatarsViewController.swift
├── Chidori.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ └── Navi.xcscheme
└── project.pbxproj
├── Navi
├── Navi.h
├── Info.plist
├── UIImageView+Navi.swift
├── Avatar.swift
├── AvatarPod.swift
└── UIImage+Navi.swift
├── .gitignore
├── Navi.podspec
├── LICENSE
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/round_avatar_placeholder.imageset/round_avatar_placeholder.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/round_avatar_placeholder.imageset/round_avatar_placeholder.pdf
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/square_avatar_placeholder.imageset/square_avatar_placeholder.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixzhu/Navi/HEAD/Chidori/Assets.xcassets/square_avatar_placeholder.imageset/square_avatar_placeholder.pdf
--------------------------------------------------------------------------------
/Chidori.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/round_avatar_placeholder.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "round_avatar_placeholder.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/square_avatar_placeholder.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "square_avatar_placeholder.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Chidori/Helpers/Config.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Config.swift
3 | // Chidori
4 | //
5 | // Created by NIX on 15/10/4.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | struct Config {
10 |
11 | struct Notification {
12 |
13 | static let newUsers = "newUsers"
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/Chidori/Extensions/UIFont+Chidori.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIFont+Chidori.swift
3 | // Chidori
4 | //
5 | // Created by NIX on 15/10/3.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIFont {
12 |
13 | class func tweetMessageFont() -> UIFont {
14 | return UIFont.systemFont(ofSize: 15)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Chidori/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Chidori
4 | //
5 | // Created by NIX on 15/9/26.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
17 | return true
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/Navi/Navi.h:
--------------------------------------------------------------------------------
1 | //
2 | // Navi.h
3 | // Navi
4 | //
5 | // Created by NIX on 15/9/26.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for Navi.
12 | FOUNDATION_EXPORT double NaviVersionNumber;
13 |
14 | //! Project version string for Navi.
15 | FOUNDATION_EXPORT const unsigned char NaviVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | ## Build generated
5 | build/
6 | DerivedData
7 |
8 | ## Various settings
9 | *.pbxuser
10 | !default.pbxuser
11 | *.mode1v3
12 | !default.mode1v3
13 | *.mode2v3
14 | !default.mode2v3
15 | *.perspectivev3
16 | !default.perspectivev3
17 | xcuserdata
18 |
19 | ## Other
20 | *.xccheckout
21 | *.moved-aside
22 | *.xcuserstate
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 |
29 | # CocoaPods
30 | Pods/
31 |
32 | # Carthage
33 | Carthage/Checkouts
34 | Carthage/Build
35 |
36 |
--------------------------------------------------------------------------------
/Chidori/Views/Cells/Avatar/AvatarCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AvatarCell.swift
3 | // Chidori
4 | //
5 | // Created by NIX on 15/9/26.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Navi
11 |
12 | class AvatarCell: UICollectionViewCell {
13 |
14 | @IBOutlet weak var imageView: UIImageView!
15 |
16 | override func awakeFromNib() {
17 | super.awakeFromNib()
18 |
19 | imageView.contentMode = .center
20 | }
21 |
22 | func configureWithAvatar(_ avatar: Navi.Avatar) {
23 |
24 | imageView.navi_setAvatar(avatar, withFadeTransitionDuration: 0.25)
25 | }
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/Navi.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "Navi"
4 | s.version = "1.1.1"
5 | s.summary = "Focus on avatar caching."
6 |
7 | s.description = <<-DESC
8 | Navi is designed for avatar caching, with style.
9 | DESC
10 |
11 | s.homepage = "https://github.com/nixzhu/Navi"
12 |
13 | s.license = { :type => "MIT", :file => "LICENSE" }
14 |
15 | s.authors = { "nixzhu" => "zhuhongxu@gmail.com" }
16 | s.social_media_url = "https://twitter.com/nixzhu"
17 |
18 | s.ios.deployment_target = "8.0"
19 |
20 | s.source = { :git => "https://github.com/nixzhu/Navi.git", :tag => s.version }
21 | s.source_files = "Navi/*.swift"
22 | s.requires_arc = true
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/Navi/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.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2016 nixzhu
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 |
--------------------------------------------------------------------------------
/Navi/UIImageView+Navi.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+Navi.swift
3 | // Navi
4 | //
5 | // Created by NIX on 15/10/1.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | private var avatarKeyAssociatedObject: Void?
12 |
13 | public extension UIImageView {
14 |
15 | fileprivate var navi_avatarKey: String? {
16 | return objc_getAssociatedObject(self, &avatarKeyAssociatedObject) as? String
17 | }
18 |
19 | fileprivate func navi_setAvatarKey(_ avatarKey: String) {
20 | objc_setAssociatedObject(self, &avatarKeyAssociatedObject, avatarKey, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
21 | }
22 |
23 | public func navi_setAvatar(_ avatar: Avatar, withFadeTransitionDuration fadeTransitionDuration: TimeInterval = 0) {
24 |
25 | navi_setAvatarKey(avatar.key)
26 |
27 | AvatarPod.wakeAvatar(avatar) { [weak self] finished, image, cacheType in
28 |
29 | guard let strongSelf = self, let avatarKey = strongSelf.navi_avatarKey , avatarKey == avatar.key else {
30 | return
31 | }
32 |
33 | if finished && cacheType != .memory {
34 | UIView.transition(with: strongSelf, duration: fadeTransitionDuration, options: .transitionCrossDissolve, animations: {
35 | self?.image = image
36 | }, completion: nil)
37 |
38 | } else {
39 | self?.image = image
40 | }
41 | }
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | # Navi
7 |
8 | Navi is designed for avatar caching, with style.
9 |
10 | The name of **Navi** from movie [Avatar](https://en.wikipedia.org/wiki/Avatar_(2009_film)).
11 |
12 | ## Requirements
13 |
14 | Swift 3.1, iOS 8.0
15 |
16 | - Swift 2.3, use version 0.5.0
17 | - Swift 3.0, use version 1.1.0
18 |
19 | ## Usage
20 |
21 | 1. Make your User conform Avatar protocol.
22 |
23 | ``` swift
24 | protocol Avatar {
25 |
26 | var url: URL? { get }
27 | var style: AvatarStyle { get }
28 | var placeholderImage: UIImage? { get }
29 | var localOriginalImage: UIImage? { get }
30 | var localStyledImage: UIImage? { get }
31 |
32 | func save(originalImage: UIImage, styledImage: UIImage)
33 | }
34 | ```
35 |
36 | 2. And, set avatar for your avatarImageView
37 |
38 | ``` swift
39 | avatarImageView.navi_setAvatar(userAvatar)
40 | ```
41 |
42 | Check the demo for more information.
43 |
44 | 另有[中文介绍](https://github.com/nixzhu/dev-blog/blob/master/2015-10-08-navi.md)。
45 |
46 | ## Installation
47 |
48 | ### Carthage
49 |
50 | ```ogdl
51 | github "nixzhu/Navi"
52 | ```
53 |
54 | ### CocoaPods
55 |
56 | ```ruby
57 | pod 'Navi'
58 | ```
59 |
60 | ## Contact
61 |
62 | NIX [@nixzhu](https://twitter.com/nixzhu)
63 |
64 | ## License
65 |
66 | Navi is available under the MIT license. See the LICENSE file for more info.
67 |
--------------------------------------------------------------------------------
/Chidori/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 | APPL
17 | CFBundleShortVersionString
18 | 1.1.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 31
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | UILaunchStoryboardName
31 | LaunchScreen
32 | UIMainStoryboardFile
33 | Main
34 | UIRequiredDeviceCapabilities
35 |
36 | armv7
37 |
38 | UISupportedInterfaceOrientations
39 |
40 | UIInterfaceOrientationPortrait
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UISupportedInterfaceOrientations~ipad
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationPortraitUpsideDown
48 | UIInterfaceOrientationLandscapeLeft
49 | UIInterfaceOrientationLandscapeRight
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/Chidori/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-29@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-29@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-40@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-40@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "60x60",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-60@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-60@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "29x29",
41 | "idiom" : "ipad",
42 | "filename" : "Icon-29.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "Icon-29@2x-1.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "Icon-40.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-40@2x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "76x76",
65 | "idiom" : "ipad",
66 | "filename" : "Icon-76.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-76@2x.png",
73 | "scale" : "2x"
74 | }
75 | ],
76 | "info" : {
77 | "version" : 1,
78 | "author" : "xcode"
79 | }
80 | }
--------------------------------------------------------------------------------
/Chidori/Helpers/Filter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Filter.swift
3 | // Chidori
4 | //
5 | // Created by NIX on 15/10/2.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreImage
11 |
12 | typealias Filter = (CIImage) -> CIImage
13 |
14 | func blurWithRadius(_ radius: CGFloat) -> Filter {
15 |
16 | return { image in
17 |
18 | let parameters = [
19 | kCIInputRadiusKey: radius,
20 | kCIInputImageKey: image,
21 | ] as [String : Any]
22 |
23 | let filter = CIFilter(name: "CIGaussianBlur", withInputParameters: parameters)
24 |
25 | return filter!.outputImage!
26 | }
27 | }
28 |
29 | func colorGenerator(_ color: UIColor) -> Filter {
30 |
31 | return { _ in
32 |
33 | let parameters = [
34 | kCIInputColorKey: CIColor(color: color),
35 | ]
36 |
37 | let filter = CIFilter(name: "CIConstantColorGenerator", withInputParameters: parameters)
38 |
39 | return filter!.outputImage!
40 | }
41 | }
42 |
43 | func compositeSourceOver(_ overlay: CIImage) -> Filter {
44 | return { image in
45 | let parameters = [
46 | kCIInputBackgroundImageKey: image,
47 | kCIInputImageKey: overlay,
48 | ]
49 |
50 | let filter = CIFilter(name: "CISourceOverCompositing", withInputParameters: parameters)
51 |
52 | let cropRect = image.extent
53 |
54 | return filter!.outputImage!.cropped(to: cropRect)
55 | }
56 | }
57 |
58 | func overlayWithColor(_ color: UIColor) -> Filter {
59 | return { image in
60 | let overlay = colorGenerator(color)(image)
61 | return compositeSourceOver(overlay)(image)
62 | }
63 | }
64 |
65 | precedencegroup FilterPrecedence {
66 | associativity: left
67 | }
68 |
69 | infix operator +++: FilterPrecedence
70 |
71 | func +++(filterA: @escaping Filter, filterB: @escaping Filter) -> Filter {
72 | return { image in
73 | return filterB(filterA(image))
74 | }
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/Chidori/Views/Cells/Avatar/AvatarCell.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 |
--------------------------------------------------------------------------------
/Navi/Avatar.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Avatar.swift
3 | // Navi
4 | //
5 | // Created by NIX on 15/9/26.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public enum AvatarStyle {
12 |
13 | case original
14 | case rectangle(size: CGSize)
15 | case roundedRectangle(size: CGSize, cornerRadius: CGFloat, borderWidth: CGFloat)
16 |
17 | public typealias Transform = (UIImage) -> UIImage?
18 | case freeform(name: String, transform: Transform)
19 | }
20 |
21 | extension AvatarStyle {
22 |
23 | var hashString: String {
24 |
25 | switch self {
26 |
27 | case .original:
28 | return "Original-"
29 |
30 | case .rectangle(let size):
31 | return "Rectangle-\(size)-"
32 |
33 | case .roundedRectangle(let size, let cornerRadius, let borderWidth):
34 | return "RoundedRectangle-\(size)-\(cornerRadius)-\(borderWidth)-"
35 |
36 | case .freeform(let name, _):
37 | return "Freeform-\(name)-"
38 | }
39 | }
40 | }
41 |
42 | extension AvatarStyle: Equatable {
43 |
44 | public static func ==(lhs: AvatarStyle, rhs: AvatarStyle) -> Bool {
45 |
46 | switch (lhs, rhs) {
47 |
48 | case (.original, .original):
49 | return true
50 |
51 | case (.rectangle(let sizeA), .rectangle(let sizeB)) where sizeA == sizeB:
52 | return true
53 |
54 | case (.roundedRectangle(let sizeA, let cornerRadiusA, let borderWidthA), .roundedRectangle(let sizeB, let cornerRadiusB, let borderWidthB)) where (sizeA == sizeB && cornerRadiusA == cornerRadiusB && borderWidthA == borderWidthB):
55 | return true
56 |
57 | case (.freeform(let nameA, _), .freeform(let nameB, _)) where nameA == nameB:
58 | return true
59 |
60 | default:
61 | return false
62 | }
63 | }
64 | }
65 |
66 | public protocol Avatar {
67 |
68 | var url: URL? { get }
69 | var style: AvatarStyle { get }
70 | var placeholderImage: UIImage? { get }
71 | var localOriginalImage: UIImage? { get }
72 | var localStyledImage: UIImage? { get }
73 |
74 | func save(originalImage: UIImage, styledImage: UIImage)
75 | }
76 |
77 | public extension Avatar {
78 |
79 | public var key: String {
80 | return style.hashString + (url?.absoluteString ?? "")
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/Chidori/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Chidori/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Chidori.xcodeproj/xcshareddata/xcschemes/Navi.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/Chidori/ViewControllers/AvatarsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AvatarsViewController.swift
3 | // Chidori
4 | //
5 | // Created by NIX on 15/9/26.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Navi
11 |
12 | struct YepAvatar {
13 |
14 | let avatarURL: URL
15 | }
16 |
17 | extension YepAvatar: Navi.Avatar {
18 |
19 | var url: URL? {
20 | return avatarURL
21 | }
22 | var style: AvatarStyle {
23 | return .roundedRectangle(
24 | size: CGSize(width: 60, height: 60),
25 | cornerRadius: 30,
26 | borderWidth: 0
27 | )
28 | }
29 | var placeholderImage: UIImage? {
30 | return UIImage(named: "round_avatar_placeholder")
31 | }
32 | var localOriginalImage: UIImage? {
33 | return nil
34 | }
35 | var localStyledImage: UIImage? {
36 | return nil
37 | }
38 |
39 | func save(originalImage: UIImage, styledImage: UIImage) {
40 | // TODO: save images
41 | }
42 | }
43 |
44 | class AvatarsViewController: UICollectionViewController {
45 |
46 | let yepAvatarURLStrings = [
47 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/84c9a0a9-c6eb-4495-9b50-0d551749956a",
48 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/7cf09c38-355b-4daa-b733-5fede0181e5f",
49 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/76daf547-a38f-410f-88fb-c7aece4fb1c8",
50 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/0e47196b-1656-4b79-8953-457afaca6f7b",
51 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/e2b84ebe-533d-4845-a842-774de98c8504",
52 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/e24117db-d360-4c0b-8159-c908bf216e38",
53 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/0738b75f-b223-4e34-a61c-add693f99f74",
54 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/d88b7c3d-7252-41d5-a7bd-068980257eff",
55 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/134f80a5-d273-4e7c-b490-f0de862c4ac4",
56 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/d0c29846-e064-4b4c-b4aa-bd0bd2d8d435",
57 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/d124dcfe-07ec-4ac6-aaf3-5ba6afd131ad",
58 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/70f6f156-7707-471d-8c98-fcb7d2a6edb1",
59 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/24795538-fc57-428b-843e-211e6b89a00c",
60 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/70a3d702-7769-4616-8410-0a7f5d39d883",
61 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/14902752-2e43-45a1-901b-3a534b1d32b4",
62 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/db49a8c6-dd2f-464d-8d06-03e7268c7fb4",
63 | "https://yep-avatars.s3.cn-north-1.amazonaws.com.cn/4c59a970-2e3d-452a-aa2b-00f46ac0512f",
64 | ]
65 |
66 | let alphaAvatarURLStrings = [
67 | "http://7xkdk4.com2.z0.glb.qiniucdn.com/pics/avatars/u5561381442825024.jpg?imageView2/1/w/128/h/128",
68 | "http://7xkszy.com2.z0.glb.qiniucdn.com/pics/avatars/u8516711441533445.jpg?imageView2/1/w/128/h/128",
69 | "http://q.qlogo.cn/qqapp/1103866037/C31B48C64369A93E57E6B971F41246DE/100",
70 | ]
71 |
72 | fileprivate let avatarCellID = "AvatarCell"
73 |
74 | deinit {
75 | NotificationCenter.default.removeObserver(self)
76 | }
77 |
78 | override func viewDidLoad() {
79 | super.viewDidLoad()
80 |
81 | title = "Avatars"
82 |
83 | collectionView!.backgroundColor = UIColor.white
84 | collectionView!.register(UINib(nibName: avatarCellID, bundle: nil), forCellWithReuseIdentifier: avatarCellID)
85 | collectionView!.dataSource = self
86 | collectionView!.alwaysBounceVertical = true
87 |
88 | NotificationCenter.default.addObserver(self, selector: #selector(AvatarsViewController.updateCollectionView(_:)), name: NSNotification.Name(rawValue: Config.Notification.newUsers), object: nil)
89 | }
90 |
91 | // MARK: Actions
92 |
93 | @objc func updateCollectionView(_ notification: Notification) {
94 | collectionView?.reloadData()
95 | }
96 |
97 | // MARK: - UICollectionView
98 |
99 | enum Section: Int {
100 | case yep
101 | case alpha
102 | }
103 |
104 | override func numberOfSections(in collectionView: UICollectionView) -> Int {
105 |
106 | return 2
107 | }
108 |
109 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
110 |
111 | switch section {
112 |
113 | case Section.yep.rawValue:
114 | return yepAvatarURLStrings.count
115 |
116 | case Section.alpha.rawValue:
117 | return alphaAvatarURLStrings.count
118 |
119 | default:
120 | return 0
121 | }
122 | }
123 |
124 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
125 |
126 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: avatarCellID, for: indexPath) as! AvatarCell
127 |
128 | return cell
129 | }
130 |
131 | override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
132 |
133 | configureCell(cell as! AvatarCell, atIndexPath: indexPath)
134 | }
135 |
136 | fileprivate func configureCell(_ cell: AvatarCell, atIndexPath indexPath: IndexPath) {
137 |
138 | switch (indexPath as NSIndexPath).section {
139 |
140 | case Section.yep.rawValue:
141 | let avatarURLString = yepAvatarURLStrings[(indexPath as NSIndexPath).item]
142 | let yepAvatar = YepAvatar(avatarURL: URL(string: avatarURLString)!)
143 | cell.configureWithAvatar(yepAvatar)
144 |
145 | case Section.alpha.rawValue:
146 | let avatarURLString = alphaAvatarURLStrings[(indexPath as NSIndexPath).item]
147 | let yepAvatar = YepAvatar(avatarURL: URL(string: avatarURLString)!)
148 | cell.configureWithAvatar(yepAvatar)
149 |
150 | default:
151 | break
152 | }
153 | }
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/Navi/AvatarPod.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AvatarPod.swift
3 | // Navi
4 | //
5 | // Created by NIX on 15/9/26.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | final public class AvatarPod {
12 |
13 | private static let sharedInstance = AvatarPod()
14 |
15 | private let cache = NSCache()
16 |
17 | private lazy var session = URLSession(configuration: URLSessionConfiguration.default)
18 |
19 | public enum CacheType {
20 | case memory
21 | case disk
22 | case cloud
23 | }
24 |
25 | public typealias Completion = (_ finished: Bool, _ image: UIImage, _ cacheType: CacheType) -> Void
26 |
27 | private struct Request {
28 |
29 | let avatar: Avatar
30 | let completion: Completion
31 |
32 | var url: URL? {
33 | return avatar.url
34 | }
35 |
36 | var key: String {
37 | return avatar.key
38 | }
39 | }
40 |
41 | private class RequestTank {
42 |
43 | let url: URL
44 | var requests: [Request] = []
45 |
46 | init(url: URL) {
47 | self.url = url
48 | }
49 | }
50 |
51 | private class RequestPool {
52 |
53 | fileprivate var requestTanks = [URL: RequestTank]()
54 |
55 | func addRequest(_ request: Request) {
56 |
57 | guard let url = request.url else {
58 | return
59 | }
60 |
61 | if let requestTank = requestTanks[url] {
62 | requestTank.requests.append(request)
63 |
64 | } else {
65 | let requestTank = RequestTank(url: url)
66 | requestTanks[url] = requestTank
67 | requestTank.requests.append(request)
68 | }
69 | }
70 |
71 | func requestsWithURL(_ URL: Foundation.URL) -> [Request] {
72 |
73 | guard let requestTank = requestTanks[URL] else {
74 | return []
75 | }
76 |
77 | return requestTank.requests
78 | }
79 |
80 | func removeRequestsWithURL(_ URL: Foundation.URL) {
81 |
82 | requestTanks.removeValue(forKey: URL)
83 | }
84 |
85 | func removeAllRequests() {
86 | requestTanks.removeAll()
87 | }
88 | }
89 |
90 | private var requestPool = RequestPool()
91 |
92 | private let requestQueue = DispatchQueue(label: "com.nixWork.Navi.requestQueue", attributes: [])
93 | private let cacheQueue = DispatchQueue.global(qos: .background)
94 |
95 | private func completeRequest(_ request: Request, withStyledImage styledImage: UIImage, cacheType: CacheType) {
96 |
97 | DispatchQueue.main.async {
98 | request.completion(true, styledImage, cacheType)
99 | }
100 |
101 | cache.setObject(styledImage, forKey: request.key as NSString)
102 | }
103 |
104 | private func completeRequestsWithURL(_ URL: Foundation.URL, image: UIImage, cacheType: CacheType) {
105 |
106 | requestQueue.async {
107 |
108 | let requests = self.requestPool.requestsWithURL(URL)
109 |
110 | self.cacheQueue.async {
111 |
112 | requests.forEach({ request in
113 |
114 | // if can find styledImage in cache, no need to generate it again or save
115 |
116 | if let styledImage = self.cache.object(forKey: request.key as NSString) {
117 | self.completeRequest(request, withStyledImage: styledImage, cacheType: cacheType)
118 |
119 | } else {
120 | let styledImage = image.navi_avatarImageWithStyle(request.avatar.style)
121 |
122 | self.completeRequest(request, withStyledImage: styledImage, cacheType: cacheType)
123 |
124 | // save images to local
125 |
126 | request.avatar.save(originalImage: image, styledImage: styledImage)
127 | }
128 | })
129 | }
130 |
131 | self.requestPool.removeRequestsWithURL(URL)
132 | }
133 | }
134 |
135 | // MARK: - API
136 |
137 | public class func wakeAvatar(_ avatar: Avatar, completion: @escaping Completion) {
138 |
139 | guard let url = avatar.url else {
140 | completion(false, avatar.placeholderImage ?? UIImage(), .memory)
141 | return
142 | }
143 |
144 | let request = Request(avatar: avatar, completion: completion)
145 |
146 | if let image = sharedInstance.cache.object(forKey: request.key as NSString) {
147 | completion(true, image, .memory)
148 |
149 | } else {
150 | if let placeholderImage = avatar.placeholderImage {
151 | completion(false, placeholderImage, .memory)
152 | }
153 |
154 | sharedInstance.cacheQueue.async {
155 |
156 | if let styledImage = avatar.localStyledImage {
157 | sharedInstance.completeRequest(request, withStyledImage: styledImage, cacheType: .disk)
158 |
159 | } else {
160 | sharedInstance.requestQueue.async {
161 |
162 | sharedInstance.requestPool.addRequest(request)
163 |
164 | if sharedInstance.requestPool.requestsWithURL(url).count > 1 {
165 | // do nothing
166 |
167 | } else {
168 | sharedInstance.cacheQueue.async {
169 |
170 | if let image = avatar.localOriginalImage {
171 | sharedInstance.completeRequestsWithURL(url, image: image, cacheType: .disk)
172 |
173 | } else {
174 | let task = sharedInstance.session.dataTask(with: url, completionHandler: { data, response, error in
175 |
176 | guard error == nil, let data = data, let image = UIImage(data: data) else {
177 | sharedInstance.requestQueue.async {
178 | sharedInstance.requestPool.removeRequestsWithURL(url)
179 | }
180 |
181 | return
182 | }
183 |
184 | sharedInstance.completeRequestsWithURL(url, image: image, cacheType: .cloud)
185 | })
186 |
187 | task.resume()
188 | }
189 | }
190 | }
191 | }
192 | }
193 | }
194 | }
195 | }
196 |
197 | public class func clear() {
198 |
199 | sharedInstance.requestPool.removeAllRequests()
200 |
201 | sharedInstance.cache.removeAllObjects()
202 | }
203 | }
204 |
205 |
--------------------------------------------------------------------------------
/Navi/UIImage+Navi.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Navi.swift
3 | // Navi
4 | //
5 | // Created by NIX on 15/9/27.
6 | // Copyright © 2015年 nixWork. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | // ref http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/
12 | // but with better scale logic
13 |
14 | private let screenScale = UIScreen.main.scale
15 |
16 | // MARK: - API
17 |
18 | public extension UIImage {
19 |
20 | public func navi_avatarImageWithStyle(_ avatarStyle: AvatarStyle) -> UIImage {
21 |
22 | var avatarImage: UIImage?
23 |
24 | switch avatarStyle {
25 |
26 | case .original:
27 | return self
28 |
29 | case .rectangle(let size):
30 | avatarImage = navi_centerCropWithSize(size)
31 |
32 | case .roundedRectangle(let size, let cornerRadius, let borderWidth):
33 | avatarImage = navi_centerCropWithSize(size)?.navi_roundWithCornerRadius(cornerRadius, borderWidth: borderWidth)
34 |
35 | case .freeform(_, let transform):
36 | avatarImage = transform(self)
37 | }
38 |
39 | return avatarImage ?? self
40 | }
41 | }
42 |
43 | // MARK: - Resize
44 |
45 | public extension UIImage {
46 |
47 | public func navi_resizeToSize(_ size: CGSize, withTransform transform: CGAffineTransform, drawTransposed: Bool, interpolationQuality: CGInterpolationQuality) -> UIImage? {
48 |
49 | let pixelSize = CGSize(width: size.width * screenScale, height: size.height * screenScale)
50 |
51 | let newRect = CGRect(origin: CGPoint.zero, size: pixelSize).integral
52 | let transposedRect = CGRect(origin: CGPoint.zero, size: CGSize(width: pixelSize.height, height: pixelSize.width))
53 |
54 | guard let cgImage = cgImage else {
55 | return nil
56 | }
57 | guard let colorSpace = cgImage.colorSpace else {
58 | return nil
59 | }
60 | guard let bitmapContext = CGContext(data: nil, width: Int(newRect.width), height: Int(newRect.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: cgImage.bitmapInfo.rawValue) else {
61 | return nil
62 | }
63 |
64 | bitmapContext.concatenate(transform)
65 |
66 | bitmapContext.interpolationQuality = interpolationQuality
67 |
68 | bitmapContext.draw(cgImage, in: drawTransposed ? transposedRect : newRect)
69 |
70 | guard let newCGImage = bitmapContext.makeImage() else {
71 | return nil
72 | }
73 |
74 | let image = UIImage(cgImage: newCGImage, scale: screenScale, orientation: imageOrientation)
75 | return image
76 | }
77 |
78 | public func navi_transformForOrientationWithSize(_ size: CGSize) -> CGAffineTransform {
79 |
80 | var transform = CGAffineTransform.identity
81 |
82 | switch imageOrientation {
83 |
84 | case .down, .downMirrored:
85 | transform = transform.translatedBy(x: size.width, y: size.height)
86 | transform = transform.rotated(by: .pi)
87 |
88 | case .left, .leftMirrored:
89 | transform = transform.translatedBy(x: size.width, y: 0)
90 | transform = transform.rotated(by: .pi / 2)
91 |
92 | case .right, .rightMirrored:
93 | transform = transform.translatedBy(x: 0, y: size.height)
94 | transform = transform.rotated(by: .pi / -2)
95 |
96 | default:
97 | break
98 | }
99 |
100 | switch imageOrientation {
101 |
102 | case .upMirrored, .downMirrored:
103 | transform = transform.translatedBy(x: size.width, y: 0)
104 | transform = transform.scaledBy(x: -1, y: 1)
105 |
106 | case .leftMirrored, .rightMirrored:
107 | transform = transform.translatedBy(x: size.height, y: 0)
108 | transform = transform.scaledBy(x: -1, y: 1)
109 |
110 | default:
111 | break
112 | }
113 |
114 | return transform
115 | }
116 |
117 | public func navi_resizeToSize(_ size: CGSize, withInterpolationQuality interpolationQuality: CGInterpolationQuality) -> UIImage? {
118 |
119 | let drawTransposed: Bool
120 |
121 | switch imageOrientation {
122 | case .left, .leftMirrored, .right, .rightMirrored:
123 | drawTransposed = true
124 | default:
125 | drawTransposed = false
126 | }
127 |
128 | let image = navi_resizeToSize(size, withTransform: navi_transformForOrientationWithSize(size), drawTransposed: drawTransposed, interpolationQuality: interpolationQuality)
129 | return image
130 | }
131 |
132 | public func navi_cropWithBounds(_ bounds: CGRect) -> UIImage? {
133 |
134 | guard let cgImage = cgImage else {
135 | return nil
136 | }
137 | guard let newCGImage = cgImage.cropping(to: bounds) else {
138 | return nil
139 |
140 | }
141 |
142 | let image = UIImage(cgImage: newCGImage, scale: screenScale, orientation: imageOrientation)
143 | return image
144 | }
145 |
146 | public func navi_centerCropWithSize(_ size: CGSize) -> UIImage? {
147 |
148 | let pixelSize = CGSize(width: size.width * screenScale, height: size.height * screenScale)
149 |
150 | let horizontalRatio = pixelSize.width / self.size.width
151 | let verticalRatio = pixelSize.height / self.size.height
152 |
153 | let ratio: CGFloat
154 |
155 | let originalX: CGFloat
156 | let originalY: CGFloat
157 |
158 | if horizontalRatio > verticalRatio {
159 | ratio = horizontalRatio
160 |
161 | originalX = 0
162 | originalY = (self.size.height - pixelSize.height / ratio) / 2
163 |
164 | } else {
165 | ratio = verticalRatio
166 |
167 | originalX = (self.size.width - pixelSize.width / ratio) / 2
168 | originalY = 0
169 | }
170 |
171 | let bounds = CGRect(x: originalX, y: originalY, width: pixelSize.width / ratio, height: pixelSize.height / ratio)
172 |
173 | let image = navi_cropWithBounds(bounds)?.navi_resizeToSize(size, withInterpolationQuality: .default)
174 | return image
175 | }
176 | }
177 |
178 | // MARK: - Round
179 |
180 | public extension UIImage {
181 |
182 | fileprivate func navi_cgContextAddRoundedRect(_ context: CGContext, rect: CGRect, ovalWidth: CGFloat, ovalHeight: CGFloat) {
183 |
184 | if ovalWidth <= 0 || ovalHeight <= 0 {
185 | context.addRect(rect)
186 |
187 | } else {
188 | context.saveGState()
189 |
190 | context.translateBy(x: rect.minX, y: rect.minY)
191 |
192 | context.scaleBy(x: ovalWidth, y: ovalHeight)
193 |
194 | let fw = rect.width / ovalWidth
195 | let fh = rect.height / ovalHeight
196 |
197 | context.move(to: CGPoint(x: fw, y: fh/2))
198 | context.addArc(tangent1End: CGPoint(x: fw, y: fh), tangent2End: CGPoint(x: fw/2, y: fh), radius: 1)
199 | context.addArc(tangent1End: CGPoint(x: 0, y: fh), tangent2End: CGPoint(x: 0, y: fh/2), radius: 1)
200 | context.addArc(tangent1End: CGPoint(x: 0, y: 0), tangent2End: CGPoint(x: fw/2, y: 0), radius: 1)
201 | context.addArc(tangent1End: CGPoint(x: fw, y: 0), tangent2End: CGPoint(x: fw, y: fh/2), radius: 1)
202 | context.closePath()
203 |
204 | context.restoreGState()
205 | }
206 | }
207 |
208 | public func navi_roundWithCornerRadius(_ cornerRadius: CGFloat, borderWidth: CGFloat) -> UIImage? {
209 |
210 | let image = navi_imageWithAlpha()
211 |
212 | let cornerRadius = cornerRadius * screenScale
213 | let borderWidth = borderWidth * screenScale
214 |
215 | let pixelSize = CGSize(width: image.size.width * screenScale, height: image.size.height * screenScale)
216 |
217 | guard let cgImage = image.cgImage else {
218 | return nil
219 | }
220 | guard let colorSpace = cgImage.colorSpace else {
221 | return nil
222 | }
223 | guard let bitmapContext = CGContext(data: nil, width: Int(pixelSize.width), height: Int(pixelSize.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: cgImage.bitmapInfo.rawValue) else {
224 | return nil
225 | }
226 |
227 | bitmapContext.beginPath()
228 |
229 | let rect = CGRect(x: borderWidth, y: borderWidth, width: pixelSize.width - borderWidth * 2, height: pixelSize.height - borderWidth * 2)
230 | navi_cgContextAddRoundedRect(bitmapContext, rect: rect, ovalWidth: cornerRadius, ovalHeight: cornerRadius)
231 |
232 | bitmapContext.closePath()
233 |
234 | bitmapContext.clip()
235 |
236 | let imageRect = CGRect(origin: CGPoint.zero, size: pixelSize)
237 | bitmapContext.draw(cgImage, in: imageRect)
238 |
239 | if let newCGImage = bitmapContext.makeImage() {
240 | let image = UIImage(cgImage: newCGImage, scale: screenScale, orientation: imageOrientation)
241 | return image
242 | }
243 |
244 | return nil
245 | }
246 | }
247 |
248 | // MARK: - Alpha
249 |
250 | public extension UIImage {
251 |
252 | public func navi_hasAlpha() -> Bool {
253 |
254 | guard let cgImage = cgImage else {
255 | return false
256 | }
257 |
258 | let alpha = cgImage.alphaInfo
259 |
260 | switch alpha {
261 |
262 | case .first, .last, .premultipliedFirst, .premultipliedLast:
263 | return true
264 |
265 | default:
266 | return false
267 | }
268 | }
269 |
270 | public func navi_imageWithAlpha() -> UIImage {
271 |
272 | if navi_hasAlpha() {
273 | return self
274 | }
275 |
276 | guard let cgImage = cgImage else {
277 | return self
278 | }
279 |
280 | let pixelSize = CGSize(width: self.size.width * screenScale, height: self.size.height * screenScale)
281 |
282 | let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo().rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
283 |
284 | guard let offscreenContext = CGContext(data: nil, width: Int(pixelSize.width), height: Int(pixelSize.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: bitmapInfo.rawValue) else {
285 | return self
286 | }
287 |
288 | offscreenContext.draw(cgImage, in: CGRect(origin: CGPoint.zero, size: pixelSize))
289 |
290 | if let alphaCGImage = offscreenContext.makeImage() {
291 | let image = UIImage(cgImage: alphaCGImage, scale: screenScale, orientation: imageOrientation)
292 | return image
293 |
294 | } else {
295 | return self
296 | }
297 | }
298 | }
299 |
300 |
--------------------------------------------------------------------------------
/Chidori.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 502A2D4B1BB7A19300B3A6B1 /* UIImage+Navi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502A2D4A1BB7A19300B3A6B1 /* UIImage+Navi.swift */; };
11 | 5057A2921BBFE5C700D3A876 /* UIFont+Chidori.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5057A2911BBFE5C700D3A876 /* UIFont+Chidori.swift */; };
12 | 5057A29B1BC13D8100D3A876 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5057A29A1BC13D8100D3A876 /* Config.swift */; };
13 | 505A55DF1BB63CFD00159CD0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505A55DE1BB63CFD00159CD0 /* AppDelegate.swift */; };
14 | 505A55E41BB63CFD00159CD0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 505A55E21BB63CFD00159CD0 /* Main.storyboard */; };
15 | 505A55E61BB63CFD00159CD0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 505A55E51BB63CFD00159CD0 /* Assets.xcassets */; };
16 | 505A55E91BB63CFD00159CD0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 505A55E71BB63CFD00159CD0 /* LaunchScreen.storyboard */; };
17 | 505A55F81BB63F2E00159CD0 /* Navi.h in Headers */ = {isa = PBXBuildFile; fileRef = 505A55F71BB63F2E00159CD0 /* Navi.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | 505A560A1BB63F2E00159CD0 /* Navi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 505A55F51BB63F2E00159CD0 /* Navi.framework */; };
19 | 505A560B1BB63F2E00159CD0 /* Navi.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 505A55F51BB63F2E00159CD0 /* Navi.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
20 | 505A56141BB6404800159CD0 /* AvatarPod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505A56131BB6404800159CD0 /* AvatarPod.swift */; };
21 | 505A56181BB640E600159CD0 /* Avatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505A56171BB640E500159CD0 /* Avatar.swift */; };
22 | 505A561A1BB6559800159CD0 /* AvatarsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505A56191BB6559800159CD0 /* AvatarsViewController.swift */; };
23 | 505A561E1BB6566F00159CD0 /* AvatarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505A561C1BB6566F00159CD0 /* AvatarCell.swift */; };
24 | 505A561F1BB6566F00159CD0 /* AvatarCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 505A561D1BB6566F00159CD0 /* AvatarCell.xib */; };
25 | 50970C9C1BBD252D001BFB19 /* UIImageView+Navi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50970C9B1BBD252D001BFB19 /* UIImageView+Navi.swift */; };
26 | 50970CB11BBE9ECA001BFB19 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50970CB01BBE9ECA001BFB19 /* Filter.swift */; };
27 | /* End PBXBuildFile section */
28 |
29 | /* Begin PBXContainerItemProxy section */
30 | 505A56081BB63F2E00159CD0 /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = 505A55D31BB63CFD00159CD0 /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = 505A55F41BB63F2E00159CD0;
35 | remoteInfo = Navi;
36 | };
37 | /* End PBXContainerItemProxy section */
38 |
39 | /* Begin PBXCopyFilesBuildPhase section */
40 | 505A56111BB63F2E00159CD0 /* Embed Frameworks */ = {
41 | isa = PBXCopyFilesBuildPhase;
42 | buildActionMask = 2147483647;
43 | dstPath = "";
44 | dstSubfolderSpec = 10;
45 | files = (
46 | 505A560B1BB63F2E00159CD0 /* Navi.framework in Embed Frameworks */,
47 | );
48 | name = "Embed Frameworks";
49 | runOnlyForDeploymentPostprocessing = 0;
50 | };
51 | /* End PBXCopyFilesBuildPhase section */
52 |
53 | /* Begin PBXFileReference section */
54 | 502A2D4A1BB7A19300B3A6B1 /* UIImage+Navi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Navi.swift"; sourceTree = ""; };
55 | 5057A2911BBFE5C700D3A876 /* UIFont+Chidori.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIFont+Chidori.swift"; path = "Extensions/UIFont+Chidori.swift"; sourceTree = ""; };
56 | 5057A29A1BC13D8100D3A876 /* Config.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Config.swift; path = Helpers/Config.swift; sourceTree = ""; };
57 | 505A55DB1BB63CFD00159CD0 /* Chidori.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Chidori.app; sourceTree = BUILT_PRODUCTS_DIR; };
58 | 505A55DE1BB63CFD00159CD0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
59 | 505A55E31BB63CFD00159CD0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
60 | 505A55E51BB63CFD00159CD0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
61 | 505A55E81BB63CFD00159CD0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
62 | 505A55EA1BB63CFD00159CD0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | 505A55F51BB63F2E00159CD0 /* Navi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Navi.framework; sourceTree = BUILT_PRODUCTS_DIR; };
64 | 505A55F71BB63F2E00159CD0 /* Navi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Navi.h; sourceTree = ""; };
65 | 505A55F91BB63F2E00159CD0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
66 | 505A56131BB6404800159CD0 /* AvatarPod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarPod.swift; sourceTree = ""; };
67 | 505A56171BB640E500159CD0 /* Avatar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Avatar.swift; sourceTree = ""; };
68 | 505A56191BB6559800159CD0 /* AvatarsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AvatarsViewController.swift; path = ViewControllers/AvatarsViewController.swift; sourceTree = ""; };
69 | 505A561C1BB6566F00159CD0 /* AvatarCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AvatarCell.swift; path = Views/Cells/Avatar/AvatarCell.swift; sourceTree = ""; };
70 | 505A561D1BB6566F00159CD0 /* AvatarCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AvatarCell.xib; path = Views/Cells/Avatar/AvatarCell.xib; sourceTree = ""; };
71 | 50970C9B1BBD252D001BFB19 /* UIImageView+Navi.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImageView+Navi.swift"; sourceTree = ""; };
72 | 50970CB01BBE9ECA001BFB19 /* Filter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = Helpers/Filter.swift; sourceTree = ""; };
73 | /* End PBXFileReference section */
74 |
75 | /* Begin PBXFrameworksBuildPhase section */
76 | 505A55D81BB63CFD00159CD0 /* Frameworks */ = {
77 | isa = PBXFrameworksBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | 505A560A1BB63F2E00159CD0 /* Navi.framework in Frameworks */,
81 | );
82 | runOnlyForDeploymentPostprocessing = 0;
83 | };
84 | 505A55F11BB63F2E00159CD0 /* Frameworks */ = {
85 | isa = PBXFrameworksBuildPhase;
86 | buildActionMask = 2147483647;
87 | files = (
88 | );
89 | runOnlyForDeploymentPostprocessing = 0;
90 | };
91 | /* End PBXFrameworksBuildPhase section */
92 |
93 | /* Begin PBXGroup section */
94 | 5057A2931BBFE5CC00D3A876 /* Extensions */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 5057A2911BBFE5C700D3A876 /* UIFont+Chidori.swift */,
98 | );
99 | name = Extensions;
100 | sourceTree = "";
101 | };
102 | 505A55D21BB63CFC00159CD0 = {
103 | isa = PBXGroup;
104 | children = (
105 | 505A55DD1BB63CFD00159CD0 /* Chidori */,
106 | 505A55F61BB63F2E00159CD0 /* Navi */,
107 | 505A55DC1BB63CFD00159CD0 /* Products */,
108 | );
109 | sourceTree = "";
110 | };
111 | 505A55DC1BB63CFD00159CD0 /* Products */ = {
112 | isa = PBXGroup;
113 | children = (
114 | 505A55DB1BB63CFD00159CD0 /* Chidori.app */,
115 | 505A55F51BB63F2E00159CD0 /* Navi.framework */,
116 | );
117 | name = Products;
118 | sourceTree = "";
119 | };
120 | 505A55DD1BB63CFD00159CD0 /* Chidori */ = {
121 | isa = PBXGroup;
122 | children = (
123 | 505A55DE1BB63CFD00159CD0 /* AppDelegate.swift */,
124 | 50970CB21BBE9ECE001BFB19 /* Helpers */,
125 | 5057A2931BBFE5CC00D3A876 /* Extensions */,
126 | 505A56201BB6567200159CD0 /* Views */,
127 | 505A561B1BB6559D00159CD0 /* ViewControllers */,
128 | 505A55E21BB63CFD00159CD0 /* Main.storyboard */,
129 | 505A55E51BB63CFD00159CD0 /* Assets.xcassets */,
130 | 505A55E71BB63CFD00159CD0 /* LaunchScreen.storyboard */,
131 | 505A55EA1BB63CFD00159CD0 /* Info.plist */,
132 | );
133 | path = Chidori;
134 | sourceTree = "";
135 | };
136 | 505A55F61BB63F2E00159CD0 /* Navi */ = {
137 | isa = PBXGroup;
138 | children = (
139 | 505A55F71BB63F2E00159CD0 /* Navi.h */,
140 | 505A56171BB640E500159CD0 /* Avatar.swift */,
141 | 505A56131BB6404800159CD0 /* AvatarPod.swift */,
142 | 502A2D4A1BB7A19300B3A6B1 /* UIImage+Navi.swift */,
143 | 50970C9B1BBD252D001BFB19 /* UIImageView+Navi.swift */,
144 | 505A55F91BB63F2E00159CD0 /* Info.plist */,
145 | );
146 | path = Navi;
147 | sourceTree = "";
148 | };
149 | 505A561B1BB6559D00159CD0 /* ViewControllers */ = {
150 | isa = PBXGroup;
151 | children = (
152 | 505A56191BB6559800159CD0 /* AvatarsViewController.swift */,
153 | );
154 | name = ViewControllers;
155 | sourceTree = "";
156 | };
157 | 505A56201BB6567200159CD0 /* Views */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 505A56211BB6567B00159CD0 /* Cells */,
161 | );
162 | name = Views;
163 | sourceTree = "";
164 | };
165 | 505A56211BB6567B00159CD0 /* Cells */ = {
166 | isa = PBXGroup;
167 | children = (
168 | 505A56221BB6568700159CD0 /* Avatar */,
169 | );
170 | name = Cells;
171 | sourceTree = "";
172 | };
173 | 505A56221BB6568700159CD0 /* Avatar */ = {
174 | isa = PBXGroup;
175 | children = (
176 | 505A561C1BB6566F00159CD0 /* AvatarCell.swift */,
177 | 505A561D1BB6566F00159CD0 /* AvatarCell.xib */,
178 | );
179 | name = Avatar;
180 | sourceTree = "";
181 | };
182 | 50970CB21BBE9ECE001BFB19 /* Helpers */ = {
183 | isa = PBXGroup;
184 | children = (
185 | 50970CB01BBE9ECA001BFB19 /* Filter.swift */,
186 | 5057A29A1BC13D8100D3A876 /* Config.swift */,
187 | );
188 | name = Helpers;
189 | sourceTree = "";
190 | };
191 | /* End PBXGroup section */
192 |
193 | /* Begin PBXHeadersBuildPhase section */
194 | 505A55F21BB63F2E00159CD0 /* Headers */ = {
195 | isa = PBXHeadersBuildPhase;
196 | buildActionMask = 2147483647;
197 | files = (
198 | 505A55F81BB63F2E00159CD0 /* Navi.h in Headers */,
199 | );
200 | runOnlyForDeploymentPostprocessing = 0;
201 | };
202 | /* End PBXHeadersBuildPhase section */
203 |
204 | /* Begin PBXNativeTarget section */
205 | 505A55DA1BB63CFD00159CD0 /* Chidori */ = {
206 | isa = PBXNativeTarget;
207 | buildConfigurationList = 505A55ED1BB63CFD00159CD0 /* Build configuration list for PBXNativeTarget "Chidori" */;
208 | buildPhases = (
209 | 505A55D71BB63CFD00159CD0 /* Sources */,
210 | 505A55D81BB63CFD00159CD0 /* Frameworks */,
211 | 505A55D91BB63CFD00159CD0 /* Resources */,
212 | 505A56111BB63F2E00159CD0 /* Embed Frameworks */,
213 | );
214 | buildRules = (
215 | );
216 | dependencies = (
217 | 505A56091BB63F2E00159CD0 /* PBXTargetDependency */,
218 | );
219 | name = Chidori;
220 | productName = Chidori;
221 | productReference = 505A55DB1BB63CFD00159CD0 /* Chidori.app */;
222 | productType = "com.apple.product-type.application";
223 | };
224 | 505A55F41BB63F2E00159CD0 /* Navi */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = 505A56101BB63F2E00159CD0 /* Build configuration list for PBXNativeTarget "Navi" */;
227 | buildPhases = (
228 | 505A55F01BB63F2E00159CD0 /* Sources */,
229 | 505A55F11BB63F2E00159CD0 /* Frameworks */,
230 | 505A55F21BB63F2E00159CD0 /* Headers */,
231 | 505A55F31BB63F2E00159CD0 /* Resources */,
232 | );
233 | buildRules = (
234 | );
235 | dependencies = (
236 | );
237 | name = Navi;
238 | productName = Navi;
239 | productReference = 505A55F51BB63F2E00159CD0 /* Navi.framework */;
240 | productType = "com.apple.product-type.framework";
241 | };
242 | /* End PBXNativeTarget section */
243 |
244 | /* Begin PBXProject section */
245 | 505A55D31BB63CFD00159CD0 /* Project object */ = {
246 | isa = PBXProject;
247 | attributes = {
248 | LastSwiftUpdateCheck = 0700;
249 | LastUpgradeCheck = 0900;
250 | ORGANIZATIONNAME = nixWork;
251 | TargetAttributes = {
252 | 505A55DA1BB63CFD00159CD0 = {
253 | CreatedOnToolsVersion = 7.0;
254 | DevelopmentTeam = 8D957V42M6;
255 | LastSwiftMigration = 0800;
256 | };
257 | 505A55F41BB63F2E00159CD0 = {
258 | CreatedOnToolsVersion = 7.0;
259 | LastSwiftMigration = 0800;
260 | };
261 | };
262 | };
263 | buildConfigurationList = 505A55D61BB63CFD00159CD0 /* Build configuration list for PBXProject "Chidori" */;
264 | compatibilityVersion = "Xcode 3.2";
265 | developmentRegion = English;
266 | hasScannedForEncodings = 0;
267 | knownRegions = (
268 | en,
269 | Base,
270 | );
271 | mainGroup = 505A55D21BB63CFC00159CD0;
272 | productRefGroup = 505A55DC1BB63CFD00159CD0 /* Products */;
273 | projectDirPath = "";
274 | projectRoot = "";
275 | targets = (
276 | 505A55DA1BB63CFD00159CD0 /* Chidori */,
277 | 505A55F41BB63F2E00159CD0 /* Navi */,
278 | );
279 | };
280 | /* End PBXProject section */
281 |
282 | /* Begin PBXResourcesBuildPhase section */
283 | 505A55D91BB63CFD00159CD0 /* Resources */ = {
284 | isa = PBXResourcesBuildPhase;
285 | buildActionMask = 2147483647;
286 | files = (
287 | 505A55E91BB63CFD00159CD0 /* LaunchScreen.storyboard in Resources */,
288 | 505A55E61BB63CFD00159CD0 /* Assets.xcassets in Resources */,
289 | 505A561F1BB6566F00159CD0 /* AvatarCell.xib in Resources */,
290 | 505A55E41BB63CFD00159CD0 /* Main.storyboard in Resources */,
291 | );
292 | runOnlyForDeploymentPostprocessing = 0;
293 | };
294 | 505A55F31BB63F2E00159CD0 /* Resources */ = {
295 | isa = PBXResourcesBuildPhase;
296 | buildActionMask = 2147483647;
297 | files = (
298 | );
299 | runOnlyForDeploymentPostprocessing = 0;
300 | };
301 | /* End PBXResourcesBuildPhase section */
302 |
303 | /* Begin PBXSourcesBuildPhase section */
304 | 505A55D71BB63CFD00159CD0 /* Sources */ = {
305 | isa = PBXSourcesBuildPhase;
306 | buildActionMask = 2147483647;
307 | files = (
308 | 5057A29B1BC13D8100D3A876 /* Config.swift in Sources */,
309 | 505A55DF1BB63CFD00159CD0 /* AppDelegate.swift in Sources */,
310 | 5057A2921BBFE5C700D3A876 /* UIFont+Chidori.swift in Sources */,
311 | 505A561E1BB6566F00159CD0 /* AvatarCell.swift in Sources */,
312 | 50970CB11BBE9ECA001BFB19 /* Filter.swift in Sources */,
313 | 505A561A1BB6559800159CD0 /* AvatarsViewController.swift in Sources */,
314 | );
315 | runOnlyForDeploymentPostprocessing = 0;
316 | };
317 | 505A55F01BB63F2E00159CD0 /* Sources */ = {
318 | isa = PBXSourcesBuildPhase;
319 | buildActionMask = 2147483647;
320 | files = (
321 | 505A56181BB640E600159CD0 /* Avatar.swift in Sources */,
322 | 505A56141BB6404800159CD0 /* AvatarPod.swift in Sources */,
323 | 50970C9C1BBD252D001BFB19 /* UIImageView+Navi.swift in Sources */,
324 | 502A2D4B1BB7A19300B3A6B1 /* UIImage+Navi.swift in Sources */,
325 | );
326 | runOnlyForDeploymentPostprocessing = 0;
327 | };
328 | /* End PBXSourcesBuildPhase section */
329 |
330 | /* Begin PBXTargetDependency section */
331 | 505A56091BB63F2E00159CD0 /* PBXTargetDependency */ = {
332 | isa = PBXTargetDependency;
333 | target = 505A55F41BB63F2E00159CD0 /* Navi */;
334 | targetProxy = 505A56081BB63F2E00159CD0 /* PBXContainerItemProxy */;
335 | };
336 | /* End PBXTargetDependency section */
337 |
338 | /* Begin PBXVariantGroup section */
339 | 505A55E21BB63CFD00159CD0 /* Main.storyboard */ = {
340 | isa = PBXVariantGroup;
341 | children = (
342 | 505A55E31BB63CFD00159CD0 /* Base */,
343 | );
344 | name = Main.storyboard;
345 | sourceTree = "";
346 | };
347 | 505A55E71BB63CFD00159CD0 /* LaunchScreen.storyboard */ = {
348 | isa = PBXVariantGroup;
349 | children = (
350 | 505A55E81BB63CFD00159CD0 /* Base */,
351 | );
352 | name = LaunchScreen.storyboard;
353 | sourceTree = "";
354 | };
355 | /* End PBXVariantGroup section */
356 |
357 | /* Begin XCBuildConfiguration section */
358 | 505A55EB1BB63CFD00159CD0 /* Debug */ = {
359 | isa = XCBuildConfiguration;
360 | buildSettings = {
361 | ALWAYS_SEARCH_USER_PATHS = NO;
362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
363 | CLANG_CXX_LIBRARY = "libc++";
364 | CLANG_ENABLE_MODULES = YES;
365 | CLANG_ENABLE_OBJC_ARC = YES;
366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
367 | CLANG_WARN_BOOL_CONVERSION = YES;
368 | CLANG_WARN_COMMA = YES;
369 | CLANG_WARN_CONSTANT_CONVERSION = YES;
370 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
371 | CLANG_WARN_EMPTY_BODY = YES;
372 | CLANG_WARN_ENUM_CONVERSION = YES;
373 | CLANG_WARN_INFINITE_RECURSION = YES;
374 | CLANG_WARN_INT_CONVERSION = YES;
375 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
376 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
377 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
378 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
379 | CLANG_WARN_STRICT_PROTOTYPES = YES;
380 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
381 | CLANG_WARN_UNREACHABLE_CODE = YES;
382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
384 | COPY_PHASE_STRIP = NO;
385 | DEBUG_INFORMATION_FORMAT = dwarf;
386 | ENABLE_STRICT_OBJC_MSGSEND = YES;
387 | ENABLE_TESTABILITY = YES;
388 | GCC_C_LANGUAGE_STANDARD = gnu99;
389 | GCC_DYNAMIC_NO_PIC = NO;
390 | GCC_NO_COMMON_BLOCKS = YES;
391 | GCC_OPTIMIZATION_LEVEL = 0;
392 | GCC_PREPROCESSOR_DEFINITIONS = (
393 | "DEBUG=1",
394 | "$(inherited)",
395 | );
396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
398 | GCC_WARN_UNDECLARED_SELECTOR = YES;
399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
400 | GCC_WARN_UNUSED_FUNCTION = YES;
401 | GCC_WARN_UNUSED_VARIABLE = YES;
402 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
403 | MTL_ENABLE_DEBUG_INFO = YES;
404 | ONLY_ACTIVE_ARCH = YES;
405 | SDKROOT = iphoneos;
406 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
407 | SWIFT_VERSION = 4.0;
408 | TARGETED_DEVICE_FAMILY = "1,2";
409 | };
410 | name = Debug;
411 | };
412 | 505A55EC1BB63CFD00159CD0 /* Release */ = {
413 | isa = XCBuildConfiguration;
414 | buildSettings = {
415 | ALWAYS_SEARCH_USER_PATHS = NO;
416 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
417 | CLANG_CXX_LIBRARY = "libc++";
418 | CLANG_ENABLE_MODULES = YES;
419 | CLANG_ENABLE_OBJC_ARC = YES;
420 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
421 | CLANG_WARN_BOOL_CONVERSION = YES;
422 | CLANG_WARN_COMMA = YES;
423 | CLANG_WARN_CONSTANT_CONVERSION = YES;
424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
425 | CLANG_WARN_EMPTY_BODY = YES;
426 | CLANG_WARN_ENUM_CONVERSION = YES;
427 | CLANG_WARN_INFINITE_RECURSION = YES;
428 | CLANG_WARN_INT_CONVERSION = YES;
429 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
430 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
431 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
432 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
433 | CLANG_WARN_STRICT_PROTOTYPES = YES;
434 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
435 | CLANG_WARN_UNREACHABLE_CODE = YES;
436 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
437 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
438 | COPY_PHASE_STRIP = NO;
439 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
440 | ENABLE_NS_ASSERTIONS = NO;
441 | ENABLE_STRICT_OBJC_MSGSEND = YES;
442 | GCC_C_LANGUAGE_STANDARD = gnu99;
443 | GCC_NO_COMMON_BLOCKS = YES;
444 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
445 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
446 | GCC_WARN_UNDECLARED_SELECTOR = YES;
447 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
448 | GCC_WARN_UNUSED_FUNCTION = YES;
449 | GCC_WARN_UNUSED_VARIABLE = YES;
450 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
451 | MTL_ENABLE_DEBUG_INFO = NO;
452 | SDKROOT = iphoneos;
453 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
454 | SWIFT_VERSION = 4.0;
455 | TARGETED_DEVICE_FAMILY = "1,2";
456 | VALIDATE_PRODUCT = YES;
457 | };
458 | name = Release;
459 | };
460 | 505A55EE1BB63CFD00159CD0 /* Debug */ = {
461 | isa = XCBuildConfiguration;
462 | buildSettings = {
463 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
464 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
465 | DEVELOPMENT_TEAM = 8D957V42M6;
466 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
467 | INFOPLIST_FILE = Chidori/Info.plist;
468 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
469 | PRODUCT_BUNDLE_IDENTIFIER = com.nixWork.Chidori;
470 | PRODUCT_NAME = "$(TARGET_NAME)";
471 | SWIFT_VERSION = 4.0;
472 | TARGETED_DEVICE_FAMILY = 1;
473 | };
474 | name = Debug;
475 | };
476 | 505A55EF1BB63CFD00159CD0 /* Release */ = {
477 | isa = XCBuildConfiguration;
478 | buildSettings = {
479 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
480 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
481 | DEVELOPMENT_TEAM = 8D957V42M6;
482 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
483 | INFOPLIST_FILE = Chidori/Info.plist;
484 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
485 | PRODUCT_BUNDLE_IDENTIFIER = com.nixWork.Chidori;
486 | PRODUCT_NAME = "$(TARGET_NAME)";
487 | SWIFT_VERSION = 4.0;
488 | TARGETED_DEVICE_FAMILY = 1;
489 | };
490 | name = Release;
491 | };
492 | 505A560C1BB63F2E00159CD0 /* Debug */ = {
493 | isa = XCBuildConfiguration;
494 | buildSettings = {
495 | APPLICATION_EXTENSION_API_ONLY = YES;
496 | CLANG_ENABLE_MODULES = YES;
497 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
498 | CURRENT_PROJECT_VERSION = 1;
499 | DEFINES_MODULE = YES;
500 | DYLIB_COMPATIBILITY_VERSION = 1;
501 | DYLIB_CURRENT_VERSION = 1;
502 | DYLIB_INSTALL_NAME_BASE = "@rpath";
503 | INFOPLIST_FILE = Navi/Info.plist;
504 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
505 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
506 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
507 | PRODUCT_BUNDLE_IDENTIFIER = com.nixWork.Navi;
508 | PRODUCT_NAME = "$(TARGET_NAME)";
509 | SKIP_INSTALL = YES;
510 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
511 | SWIFT_VERSION = 4.0;
512 | VERSIONING_SYSTEM = "apple-generic";
513 | VERSION_INFO_PREFIX = "";
514 | };
515 | name = Debug;
516 | };
517 | 505A560D1BB63F2E00159CD0 /* Release */ = {
518 | isa = XCBuildConfiguration;
519 | buildSettings = {
520 | APPLICATION_EXTENSION_API_ONLY = YES;
521 | CLANG_ENABLE_MODULES = YES;
522 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
523 | CURRENT_PROJECT_VERSION = 1;
524 | DEFINES_MODULE = YES;
525 | DYLIB_COMPATIBILITY_VERSION = 1;
526 | DYLIB_CURRENT_VERSION = 1;
527 | DYLIB_INSTALL_NAME_BASE = "@rpath";
528 | INFOPLIST_FILE = Navi/Info.plist;
529 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
530 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
531 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
532 | PRODUCT_BUNDLE_IDENTIFIER = com.nixWork.Navi;
533 | PRODUCT_NAME = "$(TARGET_NAME)";
534 | SKIP_INSTALL = YES;
535 | SWIFT_VERSION = 4.0;
536 | VERSIONING_SYSTEM = "apple-generic";
537 | VERSION_INFO_PREFIX = "";
538 | };
539 | name = Release;
540 | };
541 | /* End XCBuildConfiguration section */
542 |
543 | /* Begin XCConfigurationList section */
544 | 505A55D61BB63CFD00159CD0 /* Build configuration list for PBXProject "Chidori" */ = {
545 | isa = XCConfigurationList;
546 | buildConfigurations = (
547 | 505A55EB1BB63CFD00159CD0 /* Debug */,
548 | 505A55EC1BB63CFD00159CD0 /* Release */,
549 | );
550 | defaultConfigurationIsVisible = 0;
551 | defaultConfigurationName = Release;
552 | };
553 | 505A55ED1BB63CFD00159CD0 /* Build configuration list for PBXNativeTarget "Chidori" */ = {
554 | isa = XCConfigurationList;
555 | buildConfigurations = (
556 | 505A55EE1BB63CFD00159CD0 /* Debug */,
557 | 505A55EF1BB63CFD00159CD0 /* Release */,
558 | );
559 | defaultConfigurationIsVisible = 0;
560 | defaultConfigurationName = Release;
561 | };
562 | 505A56101BB63F2E00159CD0 /* Build configuration list for PBXNativeTarget "Navi" */ = {
563 | isa = XCConfigurationList;
564 | buildConfigurations = (
565 | 505A560C1BB63F2E00159CD0 /* Debug */,
566 | 505A560D1BB63F2E00159CD0 /* Release */,
567 | );
568 | defaultConfigurationIsVisible = 0;
569 | defaultConfigurationName = Release;
570 | };
571 | /* End XCConfigurationList section */
572 | };
573 | rootObject = 505A55D31BB63CFD00159CD0 /* Project object */;
574 | }
575 |
--------------------------------------------------------------------------------