├── Screenshots
└── screenshot1.PNG
├── Example
├── Example
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.swift
│ ├── AppDelegate.swift
│ ├── Info.plist
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
└── Example.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── Jay.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ ├── xcuserdata
│ └── Jay.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── project.pbxproj
├── SwiftyFeedback.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── Jay.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── Jay.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
├── SwiftyFeedback
├── SwiftyFeedback.h
├── SwiftyFeedbackEmail.swift
├── SwiftyFeedback.swift
├── Info.plist
├── SwiftyFeedbackAttachmentCell.swift
├── SwiftyFeedbackCell.swift
├── SwiftyFeedbackExtensions.swift
└── SwiftyFeedbackController.swift
├── SwiftyFeedback.podspec
├── LICENSE.md
└── README.md
/Screenshots/screenshot1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juanpablofernandez/SwiftyFeedback/HEAD/Screenshots/screenshot1.PNG
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftyFeedback.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwiftyFeedback.xcodeproj/project.xcworkspace/xcuserdata/Jay.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juanpablofernandez/SwiftyFeedback/HEAD/SwiftyFeedback.xcodeproj/project.xcworkspace/xcuserdata/Jay.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/Jay.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/juanpablofernandez/SwiftyFeedback/HEAD/Example/Example.xcodeproj/project.xcworkspace/xcuserdata/Jay.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwiftyFeedback.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/xcuserdata/Jay.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Example.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/SwiftyFeedback.xcodeproj/xcuserdata/Jay.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwiftyFeedback.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Example/Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Example
4 | //
5 | // Created by Juan Pablo on 6/29/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyFeedback
11 |
12 | class ViewController: UIViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 |
17 | }
18 | @IBAction func contactTapped(_ sender: Any) {
19 | SwiftyFeedback.shared.present(self)
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedback.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedback.h
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/29/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SwiftyFeedback.
12 | FOUNDATION_EXPORT double SwiftyFeedbackVersionNumber;
13 |
14 | //! Project version string for SwiftyFeedback.
15 | FOUNDATION_EXPORT const unsigned char SwiftyFeedbackVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Example/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Example
4 | //
5 | // Created by Juan Pablo on 6/29/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftyFeedback
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 |
18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
19 | SwiftyFeedback.shared.recipients = ["test@gmail.com"]
20 | return true
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedbackEmail.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedbackEmail.swift
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/28/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class EmailModel {
12 |
13 | var subject: String = ""
14 | var body: String = ""
15 | var attachments: [UIImage] = []
16 |
17 | var deviceModel: String = UIDevice.modelName
18 | var deviceOs: String = UIDevice.current.systemVersion
19 |
20 | var appName: String = Bundle.main.name
21 | var appVersion: String = Bundle.main.releaseVersionNumber
22 | var appBuild: String = Bundle.main.buildVersionNumber
23 | }
24 |
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedback.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedback.swift
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/29/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class SwiftyFeedback {
12 |
13 | static public let shared: SwiftyFeedback = SwiftyFeedback()
14 |
15 | public var recipients: [String] = []
16 | public var title: String = "Contact Us"
17 | public var sendButtonTitle = "Send"
18 | public var cancelButtonTitle = "Cancel"
19 | public var navigationController = UINavigationController()
20 |
21 | public func present(_ sender: UIViewController) {
22 | navigationController.viewControllers = [SwiftyFeedbackViewController()]
23 | sender.present(navigationController, animated: true, completion: nil)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SwiftyFeedback/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SwiftyFeedback.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "SwiftyFeedback"
4 | s.version = "1.0.1"
5 | s.summary = "A lightweight framework that allows users to contact developers."
6 | s.description = <<-DESC
7 | SwiftyFeedback makes it easy to add a contact screen to any of your apps. This allows users to contact you through email, all in a lightweight framework.
8 | DESC
9 | s.homepage = "https://github.com/juanpablofernandez/SwiftyFeedback"
10 | s.license = { :type => 'MIT', :file => 'LICENSE.md' }
11 | s.author = "Juan Pablo Fernandez"
12 | s.social_media_url = "https://github.com/juanpablofernandez"
13 | s.ios.deployment_target = '9.0'
14 | s.source = { :git => "https://github.com/juanpablofernandez/SwiftyFeedback.git", :tag => "#{s.version}" }
15 | s.source_files = "SwiftyFeedback", "SwiftyFeedback/**/*.{swift}"
16 | s.swift_version = '4.0'
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Juan Pablo Fernandez
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 |
--------------------------------------------------------------------------------
/Example/Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Example/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedbackAttachmentCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedbackAttachmentCell.swift
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/28/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal class AttachmentTableViewCell: UITableViewCell {
12 |
13 | var attachmentImageView: UIImageView = {
14 | let view = UIImageView()
15 | view.contentMode = .scaleAspectFill
16 | view.clipsToBounds = true
17 | view.layer.borderColor = UIColor.lightGray.cgColor
18 | view.layer.borderWidth = 1
19 | view.layer.masksToBounds = true
20 | // view.layer.cornerRadius = 18
21 | view.translatesAutoresizingMaskIntoConstraints = false
22 | return view
23 | }()
24 |
25 | var attachmentLabel: UILabel = {
26 | let label = UILabel()
27 | label.translatesAutoresizingMaskIntoConstraints = false
28 | return label
29 | }()
30 |
31 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
32 | super.init(style: style, reuseIdentifier: reuseIdentifier)
33 | setup()
34 | }
35 |
36 | required init?(coder aDecoder: NSCoder) {
37 | fatalError("init(coder:) has not been implemented")
38 | }
39 |
40 | private func setup() {
41 |
42 | //ImageView
43 | self.addSubview(attachmentImageView)
44 | attachmentImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 15).isActive = true
45 | attachmentImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
46 | attachmentImageView.widthAnchor.constraint(equalToConstant: 36).isActive = true
47 | attachmentImageView.heightAnchor.constraint(equalToConstant: 36).isActive = true
48 |
49 | //Label
50 | self.addSubview(attachmentLabel)
51 | attachmentLabel.leftAnchor.constraint(equalTo: attachmentImageView.rightAnchor, constant: 10).isActive = true
52 | attachmentLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true
53 | attachmentLabel.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 1).isActive = true
54 | attachmentImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Example/Example/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedbackCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedbackCell.swift
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/29/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | internal class FeedbackTableViewCell: UITableViewCell {
12 |
13 | var textView: UITextView = {
14 | let view = UITextView()
15 | view.font = UIFont.systemFont(ofSize: 17)
16 | view.sizeToFit()
17 | view.isScrollEnabled = false
18 | view.translatesAutoresizingMaskIntoConstraints = false
19 | return view
20 | }()
21 |
22 | var placeholderView: UITextView = {
23 | let view = UITextView()
24 | view.text = "Describe your question."
25 | view.textColor = UIColor.lightGray
26 | view.font = UIFont.systemFont(ofSize: 17)
27 | view.sizeToFit()
28 | view.isScrollEnabled = false
29 | view.isUserInteractionEnabled = false
30 | view.translatesAutoresizingMaskIntoConstraints = false
31 | return view
32 | }()
33 |
34 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
35 | super.init(style: style, reuseIdentifier: reuseIdentifier)
36 | setup()
37 | }
38 |
39 | required init?(coder aDecoder: NSCoder) {
40 | fatalError("init(coder:) has not been implemented")
41 | }
42 |
43 | func setup() {
44 |
45 | //FeedbackTextView Setup
46 | textView.delegate = self
47 | self.addSubview(textView)
48 | let cellMargins = self.layoutMarginsGuide
49 | textView.leftAnchor.constraint(equalTo: cellMargins.leftAnchor).isActive = true
50 | textView.rightAnchor.constraint(equalTo: cellMargins.rightAnchor).isActive = true
51 | textView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
52 | textView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -44).isActive = true
53 | textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44.0).isActive = true
54 |
55 | //Feedback Placeholder
56 | textView.insertSubview(placeholderView, at: 0)
57 | placeholderView.isHidden = !textView.text.isEmpty
58 | textView.leftAnchor.constraint(equalTo: placeholderView.leftAnchor).isActive = true
59 | textView.rightAnchor.constraint(equalTo: placeholderView.rightAnchor).isActive = true
60 | textView.topAnchor.constraint(equalTo: placeholderView.topAnchor).isActive = true
61 | textView.bottomAnchor.constraint(equalTo: placeholderView.bottomAnchor).isActive = true
62 | }
63 | }
64 |
65 | extension FeedbackTableViewCell: UITextViewDelegate {
66 |
67 | func textViewDidChange(_ textView: UITextView) {
68 | placeholderView.isHidden = !textView.text.isEmpty
69 | NotificationCenter.default.post(name: Notification.Name("UpdatedFeedbackTextView"), object: nil)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwiftyFeedback
2 | > A lightweight pure-Swift library that allows users to send feedback.
3 |
4 | [![Swift Version][swift-image]][swift-url]
5 | [![Build Status][travis-image]][travis-url]
6 | [![License][license-image]][license-url]
7 | [](https://cocoapods.org/pods/SwiftyFeedback)
8 | [](https://cocoapods.org/pods/SwiftyFeedback)
9 |
10 |
11 | SwiftyFeedback is a lightweight pure-Swift library based on the [CTFeedback](https://github.com/rizumita/CTFeedback) library.
12 |
13 | SwiftyFeedback makes it easy to add a simple feedback template to any of your apps.
14 |
15 | 
16 |
17 | ## Contents
18 |
19 | * [Requirements](#requirements)
20 | * [Installation](#installation)
21 | * [CocoaPods](#cocoapods)
22 | * [Manually](#manually)
23 | * [Usage](#usage)
24 | * [Notes](#notes)
25 | * [Contribute](#contribute)
26 | * [License](#license)
27 |
28 | ## Requirements
29 |
30 | - iOS 9.0+
31 | - Xcode 7.3+
32 | - Swift 4.0+
33 |
34 | ## Installation
35 |
36 | #### CocoaPods
37 | You can use [CocoaPods](http://cocoapods.org/) to install `SwiftyFeedback` by adding this to your `Podfile`:
38 |
39 | ```ruby
40 | use_frameworks!
41 | pod 'SwiftyFeedback'
42 | ```
43 | If you get the ``Unable to find a specification for `SwiftyFeedback`.`` error after running `pod install`.
44 |
45 | Run the following commands on your project directory:
46 | ```
47 | pod repo update
48 | ```
49 | ```
50 | pod install
51 | ```
52 | #### Manually
53 | 1. Drag and drop ```SwiftyFeedback.swift``` and the rest of the ```.swift``` files into your project.
54 | 2. That's it!
55 |
56 | ## Usage
57 | 1. Import `SwiftyFeedback` module to your `AppDelegate` class
58 | ```swift
59 | import SwiftyFeedback
60 | ```
61 | 2. In your `AppDelegate` class, add the recipients array to the SwiftyFeedback singleton.
62 | ```swift
63 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
64 | SwiftyFeedback.shared.recipients = ["test@gmail.com"]
65 | return true
66 | }
67 | ```
68 | 3. Import `SwiftyFeedback` module to your `ViewController` class
69 | ```swift
70 | import SwiftyFeedback
71 | ```
72 | 4. Present the `SwiftyFeedback` view on your `ViewController` e.g.
73 | ```swift
74 | class ViewController: UIViewController {
75 |
76 | @IBAction func contactTapped(_ sender: Any) {
77 | SwiftyFeedback.shared.present(self)
78 | }
79 | }
80 | ```
81 | 5. `SwiftyFeedback` works with default implementation. Override it to customize its behavior
82 |
83 |
84 |
85 | ## Notes
86 | * Landscape mode is not supported
87 |
88 | ## Contribute
89 | Contributions are welcomed! There are however certain guidelines you must follow when you contribute:
90 | * Have descriptive commit messages.
91 | * Make a pull request for every feature (Don't make a pull request that adds 3 new features. Make an individual pull request for each of those features, with a descriptive message).
92 | * Don't update the example project, or any other irrelevant files.
93 |
94 |
95 | ## License
96 |
97 | Distributed under the MIT license. See ``LICENSE`` for more information.
98 |
99 | [swift-image]:https://img.shields.io/badge/swift-3.0-orange.svg
100 | [swift-url]: https://swift.org/
101 | [license-image]: https://img.shields.io/badge/License-MIT-blue.svg
102 | [license-url]: LICENSE
103 | [travis-image]: https://img.shields.io/travis/dbader/node-datadog-metrics/master.svg?style=flat-square
104 | [travis-url]: https://travis-ci.org/dbader/node-datadog-metrics
105 | [codebeat-image]: https://codebeat.co/badges/c19b47ea-2f9d-45df-8458-b2d952fe9dad
106 | [codebeat-url]: https://codebeat.co/projects/github-com-vsouza-awesomeios-com
107 |
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedbackExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedbackExtensions.swift
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/28/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension Bundle {
13 | var releaseVersionNumber: String {
14 | return infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
15 | }
16 |
17 | var buildVersionNumber: String {
18 | return infoDictionary?["CFBundleVersion"] as? String ?? ""
19 | }
20 |
21 | var displayName: String {
22 | return object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? ""
23 | }
24 |
25 | var name: String {
26 | return object(forInfoDictionaryKey: "CFBundleName") as? String ?? ""
27 | }
28 | }
29 |
30 | public extension UIDevice {
31 |
32 | static let modelName: String = {
33 | var systemInfo = utsname()
34 | uname(&systemInfo)
35 | let machineMirror = Mirror(reflecting: systemInfo.machine)
36 | let identifier = machineMirror.children.reduce("") { identifier, element in
37 | guard let value = element.value as? Int8, value != 0 else { return identifier }
38 | return identifier + String(UnicodeScalar(UInt8(value)))
39 | }
40 |
41 | func mapToDevice(identifier: String) -> String { // swiftlint:disable:this cyclomatic_complexity
42 | #if os(iOS)
43 | switch identifier {
44 | case "iPod5,1": return "iPod Touch 5"
45 | case "iPod7,1": return "iPod Touch 6"
46 | case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
47 | case "iPhone4,1": return "iPhone 4s"
48 | case "iPhone5,1", "iPhone5,2": return "iPhone 5"
49 | case "iPhone5,3", "iPhone5,4": return "iPhone 5c"
50 | case "iPhone6,1", "iPhone6,2": return "iPhone 5s"
51 | case "iPhone7,2": return "iPhone 6"
52 | case "iPhone7,1": return "iPhone 6 Plus"
53 | case "iPhone8,1": return "iPhone 6s"
54 | case "iPhone8,2": return "iPhone 6s Plus"
55 | case "iPhone9,1", "iPhone9,3": return "iPhone 7"
56 | case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus"
57 | case "iPhone8,4": return "iPhone SE"
58 | case "iPhone10,1", "iPhone10,4": return "iPhone 8"
59 | case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus"
60 | case "iPhone10,3", "iPhone10,6": return "iPhone X"
61 | case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
62 | case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3"
63 | case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4"
64 | case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
65 | case "iPad5,3", "iPad5,4": return "iPad Air 2"
66 | case "iPad6,11", "iPad6,12": return "iPad 5"
67 | case "iPad7,5", "iPad7,6": return "iPad 6"
68 | case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini"
69 | case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2"
70 | case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3"
71 | case "iPad5,1", "iPad5,2": return "iPad Mini 4"
72 | case "iPad6,3", "iPad6,4": return "iPad Pro 9.7 Inch"
73 | case "iPad6,7", "iPad6,8": return "iPad Pro 12.9 Inch"
74 | case "iPad7,1", "iPad7,2": return "iPad Pro 12.9 Inch 2. Generation"
75 | case "iPad7,3", "iPad7,4": return "iPad Pro 10.5 Inch"
76 | case "AppleTV5,3": return "Apple TV"
77 | case "AppleTV6,2": return "Apple TV 4K"
78 | case "AudioAccessory1,1": return "HomePod"
79 | case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))"
80 | default: return identifier
81 | }
82 | #elseif os(tvOS)
83 | switch identifier {
84 | case "AppleTV5,3": return "Apple TV 4"
85 | case "AppleTV6,2": return "Apple TV 4K"
86 | case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))"
87 | default: return identifier
88 | }
89 | #endif
90 | }
91 |
92 | return mapToDevice(identifier: identifier)
93 | }()
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/SwiftyFeedback/SwiftyFeedbackController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftyFeedbackController.swift
3 | // SwiftyFeedback
4 | //
5 | // Created by Juan Pablo on 6/28/18.
6 | // Copyright © 2018 Juan Pablo Fernandez. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Photos
11 | import MessageUI
12 |
13 | internal class SwiftyFeedbackViewController: UITableViewController {
14 |
15 | // MARK: Cells
16 |
17 | private var topicCell: UITableViewCell = UITableViewCell(style: .value1 , reuseIdentifier: nil)
18 | private var feedbackCell: FeedbackTableViewCell = FeedbackTableViewCell()
19 | private var attachmentCell: UITableViewCell = UITableViewCell()
20 | private var deviceCell: UITableViewCell = UITableViewCell(style: .value1 , reuseIdentifier: nil)
21 | private var iosCell: UITableViewCell = UITableViewCell(style: .value1 , reuseIdentifier: nil)
22 | private var nameCell: UITableViewCell = UITableViewCell(style: .value1 , reuseIdentifier: nil)
23 | private var versionCell: UITableViewCell = UITableViewCell(style: .value1 , reuseIdentifier: nil)
24 | private var buildCell: UITableViewCell = UITableViewCell(style: .value1 , reuseIdentifier: nil)
25 |
26 |
27 | // MARK: Variables
28 |
29 | private var imagePicker = UIImagePickerController()
30 | private var attachments: [UIImage] = []
31 | private var selectedAttachment: IndexPath = IndexPath(row: 1, section: 1)
32 | private var email: EmailModel = EmailModel()
33 |
34 |
35 | // MARK: Setup
36 |
37 | override internal func viewDidLoad() {
38 | super.viewDidLoad()
39 | setup()
40 | tableViewSetup()
41 | }
42 |
43 | deinit {
44 | NotificationCenter.default.removeObserver(self)
45 | }
46 |
47 | private func setup() {
48 | title = "Contact Us"
49 | UIApplication.shared.statusBarStyle = .default
50 | navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Send", style: .plain, target: self, action: #selector(sendEmail))
51 |
52 | navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(handleDismiss))
53 | NotificationCenter.default.addObserver(self, selector: #selector(updateTableViewContentOffsetForTextView), name: Notification.Name("UpdatedFeedbackTextView"), object: nil)
54 | }
55 |
56 | @objc private func handleDismiss() {
57 | self.dismiss(animated: true, completion: nil)
58 | }
59 |
60 | @objc private func sendEmail() {
61 | email.attachments = attachments
62 | email.subject = "\(email.appName) - \(topicCell.detailTextLabel!.text!)"
63 | email.body = feedbackCell.textView.text
64 | composeEmail()
65 | }
66 |
67 |
68 | // MARK: TableView Setup
69 |
70 | private func tableViewSetup() {
71 |
72 | self.tableView = UITableView(frame: self.tableView.frame, style: .grouped)
73 | tableView.estimatedRowHeight = 44.0
74 | tableView.rowHeight = UITableViewAutomaticDimension
75 | tableView.keyboardDismissMode = .onDrag
76 |
77 | let cells = [topicCell, feedbackCell, attachmentCell, deviceCell, iosCell, nameCell, versionCell, buildCell]
78 | let cellsText = ["Select topic", "" , "Attach Photo", "Device", "iOS", "Name", "Version", "Build"]
79 |
80 | for index in cells.indices {
81 | let cell = cells[index]
82 | cell.selectionStyle = .none
83 | cell.textLabel?.text = cellsText[index]
84 | }
85 |
86 | topicCell.detailTextLabel?.text = "Question"
87 | topicCell.accessoryType = .disclosureIndicator
88 | topicCell.selectionStyle = .default
89 |
90 | attachmentCell.accessoryType = .disclosureIndicator
91 | attachmentCell.selectionStyle = .default
92 |
93 | //Device Info
94 | deviceCell.detailTextLabel?.text = email.deviceModel
95 | iosCell.detailTextLabel?.text = email.deviceOs
96 |
97 | //App Info
98 | nameCell.detailTextLabel?.text = email.appName
99 | versionCell.detailTextLabel?.text = email.appVersion
100 | buildCell.detailTextLabel?.text = email.appBuild
101 | }
102 |
103 | @objc private func updateTableViewContentOffsetForTextView() {
104 | let currentOffset = tableView.contentOffset
105 | UIView.setAnimationsEnabled(false)
106 | tableView.beginUpdates()
107 | tableView.endUpdates()
108 | UIView.setAnimationsEnabled(true)
109 | tableView.setContentOffset(currentOffset, animated: false)
110 | tableView.updateConstraintsIfNeeded()
111 | }
112 |
113 |
114 | // MARK: Subject Options
115 |
116 | private func presentSubjects() {
117 | let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
118 | alertController.addAction(UIAlertAction(title: "Question", style: .default, handler: selectedTopic))
119 | alertController.addAction(UIAlertAction(title: "Request", style: .default, handler: selectedTopic))
120 | alertController.addAction(UIAlertAction(title: "Bug Report", style: .default, handler: selectedTopic))
121 | alertController.addAction(UIAlertAction(title: "Other", style: .default, handler: selectedTopic))
122 | alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
123 | self.present(alertController, animated: true, completion: nil)
124 | }
125 |
126 | private func selectedTopic(action: UIAlertAction) {
127 | guard let text = action.title else { return }
128 | topicCell.detailTextLabel?.text = text
129 | email.subject = text
130 | feedbackCell.placeholderView.text = "Describe your \(text.lowercased())."
131 | }
132 |
133 |
134 | // MARK: Attachment Options
135 |
136 | private func presentAttachmentOptions(indexPath: IndexPath) {
137 | selectedAttachment = indexPath
138 | let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
139 | alertController.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: deleteAttachment))
140 | alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
141 | self.present(alertController, animated: true, completion: nil)
142 | }
143 |
144 | private func deleteAttachment(action: UIAlertAction) {
145 | tableView.beginUpdates()
146 | attachments.remove(at: selectedAttachment.row)
147 | tableView.deleteRows(at: [selectedAttachment], with: .automatic)
148 | tableView.endUpdates()
149 | }
150 | }
151 |
152 | extension SwiftyFeedbackViewController {
153 |
154 | // MARK: Tableview Delegate:
155 |
156 | internal override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
157 |
158 | if indexPath.section == 0 && indexPath.row == 1 {
159 | return UITableViewAutomaticDimension
160 | }
161 |
162 | return 44.0
163 | }
164 |
165 | // MARK: TableView Datasource
166 |
167 | internal override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
168 | switch(section) {
169 | case 0: return "Topic"
170 | case 1: return "Attachments"
171 | case 2: return "Device Info"
172 | case 3: return "App Info"
173 | default: fatalError("Unknown section")
174 | }
175 | }
176 |
177 | internal override func numberOfSections(in tableView: UITableView) -> Int {
178 | return 4
179 | }
180 |
181 | internal override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
182 | switch(section) {
183 | case 0: return 2
184 | case 1: return attachments.count + 1
185 | case 2: return 2
186 | case 3: return 3
187 | default: fatalError("Unknown number of sections")
188 | }
189 | }
190 |
191 | internal override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
192 | tableView.deselectRow(at: indexPath, animated: true)
193 |
194 | if indexPath.section == 0 && indexPath.row == 0 {
195 | presentSubjects()
196 | } else if indexPath.section == 1 && indexPath.row == attachments.count {
197 | openPhotos()
198 | } else if indexPath.section == 1 && indexPath.row != attachments.count {
199 | presentAttachmentOptions(indexPath: indexPath)
200 | }
201 | }
202 |
203 | internal override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
204 | switch(indexPath.section) {
205 | case 0:
206 | switch(indexPath.row) {
207 | case 0: return self.topicCell
208 | case 1: return self.feedbackCell
209 | default: fatalError("Unknown row in section 0")
210 | }
211 | case 1:
212 | if attachments.count == 0 { return attachmentCell }
213 | if indexPath.row == attachments.count { return attachmentCell}
214 | let cell = AttachmentTableViewCell()
215 | cell.attachmentLabel.text = "Attachment \(indexPath.row + 1)"
216 | cell.attachmentImageView.image = attachments[indexPath.row]
217 | return cell
218 |
219 | case 2:
220 | switch(indexPath.row) {
221 | case 0: return self.deviceCell
222 | case 1: return self.iosCell
223 | default: fatalError("Unknown row in section 2")
224 | }
225 | case 3:
226 | switch(indexPath.row) {
227 | case 0: return self.nameCell
228 | case 1: return self.versionCell
229 | case 2: return self.buildCell
230 | default: fatalError("Unknown row in section 3")
231 | }
232 | default: fatalError("Unknown section")
233 | }
234 | }
235 | }
236 |
237 | extension SwiftyFeedbackViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
238 |
239 | private func openPhotos() {
240 | if attachments.count >= 5 { return }
241 | if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){
242 | print("Button capture")
243 |
244 | imagePicker.delegate = self
245 | imagePicker.sourceType = .savedPhotosAlbum;
246 | imagePicker.allowsEditing = false
247 |
248 | self.present(imagePicker, animated: true, completion: nil)
249 | }
250 | }
251 |
252 | internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
253 | if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
254 | attachments.append(pickedImage)
255 | }
256 |
257 | tableView.reloadData()
258 | dismiss(animated: true, completion: nil)
259 | }
260 |
261 | internal func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
262 | dismiss(animated: true, completion:nil)
263 | }
264 | }
265 |
266 | extension SwiftyFeedbackViewController: MFMailComposeViewControllerDelegate {
267 |
268 | private func composeEmail() {
269 |
270 | let composeVC = MFMailComposeViewController()
271 | composeVC.mailComposeDelegate = self
272 |
273 | // Configure the fields of the interface.
274 | composeVC.setToRecipients(SwiftyFeedback.shared.recipients)
275 | composeVC.setSubject(email.subject)
276 |
277 | let info = "Device: \(email.deviceModel)\n" + "iOS: \(email.deviceOs)\n" + "App Name: \(email.appName)\n" + "App Version: \(email.appVersion)\n" + "App Build: \(email.appBuild)\n"
278 |
279 | let body = "\(email.body)\n\n" + info
280 |
281 | composeVC.setMessageBody(body, isHTML: false)
282 |
283 | for index in email.attachments.indices {
284 | let attachment = email.attachments[index]
285 | composeVC.addAttachmentData(UIImageJPEGRepresentation(attachment, CGFloat(1.0))!, mimeType: "image/jpeg", fileName: "attachment\(index+1).jpeg")
286 | }
287 |
288 | // Present the view controller modally.
289 | self.present(composeVC, animated: true, completion: nil)
290 | }
291 |
292 | internal func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
293 |
294 | if result == .sent {
295 | controller.dismiss(animated: true, completion: nil)
296 | self.dismiss(animated: true, completion: nil)
297 | } else {
298 | controller.dismiss(animated: true, completion: nil)
299 | }
300 | }
301 | }
302 |
303 |
304 |
305 |
306 |
--------------------------------------------------------------------------------
/SwiftyFeedback.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 693DBCF220E6DE6E00202D14 /* SwiftyFeedback.h in Headers */ = {isa = PBXBuildFile; fileRef = 693DBCF020E6DE6E00202D14 /* SwiftyFeedback.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 69E23BE220E6E09600BD3AAE /* SwiftyFeedbackEmail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693DBCF820E6DE8B00202D14 /* SwiftyFeedbackEmail.swift */; };
12 | 69E23BE320E6E09600BD3AAE /* SwiftyFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693DBCFA20E6DE8C00202D14 /* SwiftyFeedback.swift */; };
13 | 69E23BE420E6E09600BD3AAE /* SwiftyFeedbackController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693DBCFB20E6DE8C00202D14 /* SwiftyFeedbackController.swift */; };
14 | 69E23BE520E6E09600BD3AAE /* SwiftyFeedbackAttachmentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693DBCF920E6DE8C00202D14 /* SwiftyFeedbackAttachmentCell.swift */; };
15 | 69E23BE620E6E09600BD3AAE /* SwiftyFeedbackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693DBCFC20E6DE8C00202D14 /* SwiftyFeedbackCell.swift */; };
16 | 69E23BE720E6E09600BD3AAE /* SwiftyFeedbackExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693DBCFD20E6DE8C00202D14 /* SwiftyFeedbackExtensions.swift */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | 693DBCED20E6DE6E00202D14 /* SwiftyFeedback.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyFeedback.framework; sourceTree = BUILT_PRODUCTS_DIR; };
21 | 693DBCF020E6DE6E00202D14 /* SwiftyFeedback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftyFeedback.h; sourceTree = ""; };
22 | 693DBCF120E6DE6E00202D14 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
23 | 693DBCF820E6DE8B00202D14 /* SwiftyFeedbackEmail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyFeedbackEmail.swift; sourceTree = ""; };
24 | 693DBCF920E6DE8C00202D14 /* SwiftyFeedbackAttachmentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyFeedbackAttachmentCell.swift; sourceTree = ""; };
25 | 693DBCFA20E6DE8C00202D14 /* SwiftyFeedback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyFeedback.swift; sourceTree = ""; };
26 | 693DBCFB20E6DE8C00202D14 /* SwiftyFeedbackController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyFeedbackController.swift; sourceTree = ""; };
27 | 693DBCFC20E6DE8C00202D14 /* SwiftyFeedbackCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyFeedbackCell.swift; sourceTree = ""; };
28 | 693DBCFD20E6DE8C00202D14 /* SwiftyFeedbackExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyFeedbackExtensions.swift; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 693DBCE920E6DE6E00202D14 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 693DBCE320E6DE6E00202D14 = {
43 | isa = PBXGroup;
44 | children = (
45 | 693DBCEF20E6DE6E00202D14 /* SwiftyFeedback */,
46 | 693DBCEE20E6DE6E00202D14 /* Products */,
47 | );
48 | sourceTree = "";
49 | };
50 | 693DBCEE20E6DE6E00202D14 /* Products */ = {
51 | isa = PBXGroup;
52 | children = (
53 | 693DBCED20E6DE6E00202D14 /* SwiftyFeedback.framework */,
54 | );
55 | name = Products;
56 | sourceTree = "";
57 | };
58 | 693DBCEF20E6DE6E00202D14 /* SwiftyFeedback */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 693DBCF020E6DE6E00202D14 /* SwiftyFeedback.h */,
62 | 693DBCF820E6DE8B00202D14 /* SwiftyFeedbackEmail.swift */,
63 | 693DBCFA20E6DE8C00202D14 /* SwiftyFeedback.swift */,
64 | 693DBCFB20E6DE8C00202D14 /* SwiftyFeedbackController.swift */,
65 | 693DBCF920E6DE8C00202D14 /* SwiftyFeedbackAttachmentCell.swift */,
66 | 693DBCFC20E6DE8C00202D14 /* SwiftyFeedbackCell.swift */,
67 | 693DBCFD20E6DE8C00202D14 /* SwiftyFeedbackExtensions.swift */,
68 | 693DBCF120E6DE6E00202D14 /* Info.plist */,
69 | );
70 | path = SwiftyFeedback;
71 | sourceTree = "";
72 | };
73 | /* End PBXGroup section */
74 |
75 | /* Begin PBXHeadersBuildPhase section */
76 | 693DBCEA20E6DE6E00202D14 /* Headers */ = {
77 | isa = PBXHeadersBuildPhase;
78 | buildActionMask = 2147483647;
79 | files = (
80 | 693DBCF220E6DE6E00202D14 /* SwiftyFeedback.h in Headers */,
81 | );
82 | runOnlyForDeploymentPostprocessing = 0;
83 | };
84 | /* End PBXHeadersBuildPhase section */
85 |
86 | /* Begin PBXNativeTarget section */
87 | 693DBCEC20E6DE6E00202D14 /* SwiftyFeedback */ = {
88 | isa = PBXNativeTarget;
89 | buildConfigurationList = 693DBCF520E6DE6E00202D14 /* Build configuration list for PBXNativeTarget "SwiftyFeedback" */;
90 | buildPhases = (
91 | 693DBCE820E6DE6E00202D14 /* Sources */,
92 | 693DBCE920E6DE6E00202D14 /* Frameworks */,
93 | 693DBCEA20E6DE6E00202D14 /* Headers */,
94 | 693DBCEB20E6DE6E00202D14 /* Resources */,
95 | );
96 | buildRules = (
97 | );
98 | dependencies = (
99 | );
100 | name = SwiftyFeedback;
101 | productName = SwiftyFeedback;
102 | productReference = 693DBCED20E6DE6E00202D14 /* SwiftyFeedback.framework */;
103 | productType = "com.apple.product-type.framework";
104 | };
105 | /* End PBXNativeTarget section */
106 |
107 | /* Begin PBXProject section */
108 | 693DBCE420E6DE6E00202D14 /* Project object */ = {
109 | isa = PBXProject;
110 | attributes = {
111 | LastUpgradeCheck = 0930;
112 | ORGANIZATIONNAME = "Juan Pablo Fernandez";
113 | TargetAttributes = {
114 | 693DBCEC20E6DE6E00202D14 = {
115 | CreatedOnToolsVersion = 9.3;
116 | };
117 | };
118 | };
119 | buildConfigurationList = 693DBCE720E6DE6E00202D14 /* Build configuration list for PBXProject "SwiftyFeedback" */;
120 | compatibilityVersion = "Xcode 9.3";
121 | developmentRegion = en;
122 | hasScannedForEncodings = 0;
123 | knownRegions = (
124 | en,
125 | );
126 | mainGroup = 693DBCE320E6DE6E00202D14;
127 | productRefGroup = 693DBCEE20E6DE6E00202D14 /* Products */;
128 | projectDirPath = "";
129 | projectRoot = "";
130 | targets = (
131 | 693DBCEC20E6DE6E00202D14 /* SwiftyFeedback */,
132 | );
133 | };
134 | /* End PBXProject section */
135 |
136 | /* Begin PBXResourcesBuildPhase section */
137 | 693DBCEB20E6DE6E00202D14 /* Resources */ = {
138 | isa = PBXResourcesBuildPhase;
139 | buildActionMask = 2147483647;
140 | files = (
141 | );
142 | runOnlyForDeploymentPostprocessing = 0;
143 | };
144 | /* End PBXResourcesBuildPhase section */
145 |
146 | /* Begin PBXSourcesBuildPhase section */
147 | 693DBCE820E6DE6E00202D14 /* Sources */ = {
148 | isa = PBXSourcesBuildPhase;
149 | buildActionMask = 2147483647;
150 | files = (
151 | 69E23BE620E6E09600BD3AAE /* SwiftyFeedbackCell.swift in Sources */,
152 | 69E23BE720E6E09600BD3AAE /* SwiftyFeedbackExtensions.swift in Sources */,
153 | 69E23BE520E6E09600BD3AAE /* SwiftyFeedbackAttachmentCell.swift in Sources */,
154 | 69E23BE320E6E09600BD3AAE /* SwiftyFeedback.swift in Sources */,
155 | 69E23BE220E6E09600BD3AAE /* SwiftyFeedbackEmail.swift in Sources */,
156 | 69E23BE420E6E09600BD3AAE /* SwiftyFeedbackController.swift in Sources */,
157 | );
158 | runOnlyForDeploymentPostprocessing = 0;
159 | };
160 | /* End PBXSourcesBuildPhase section */
161 |
162 | /* Begin XCBuildConfiguration section */
163 | 693DBCF320E6DE6E00202D14 /* Debug */ = {
164 | isa = XCBuildConfiguration;
165 | buildSettings = {
166 | ALWAYS_SEARCH_USER_PATHS = NO;
167 | CLANG_ANALYZER_NONNULL = YES;
168 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
169 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
170 | CLANG_CXX_LIBRARY = "libc++";
171 | CLANG_ENABLE_MODULES = YES;
172 | CLANG_ENABLE_OBJC_ARC = YES;
173 | CLANG_ENABLE_OBJC_WEAK = YES;
174 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
175 | CLANG_WARN_BOOL_CONVERSION = YES;
176 | CLANG_WARN_COMMA = YES;
177 | CLANG_WARN_CONSTANT_CONVERSION = YES;
178 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
179 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181 | CLANG_WARN_EMPTY_BODY = YES;
182 | CLANG_WARN_ENUM_CONVERSION = YES;
183 | CLANG_WARN_INFINITE_RECURSION = YES;
184 | CLANG_WARN_INT_CONVERSION = YES;
185 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
186 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
187 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
189 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
190 | CLANG_WARN_STRICT_PROTOTYPES = YES;
191 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
192 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
193 | CLANG_WARN_UNREACHABLE_CODE = YES;
194 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
195 | CODE_SIGN_IDENTITY = "iPhone Developer";
196 | COPY_PHASE_STRIP = NO;
197 | CURRENT_PROJECT_VERSION = 1;
198 | DEBUG_INFORMATION_FORMAT = dwarf;
199 | ENABLE_STRICT_OBJC_MSGSEND = YES;
200 | ENABLE_TESTABILITY = YES;
201 | GCC_C_LANGUAGE_STANDARD = gnu11;
202 | GCC_DYNAMIC_NO_PIC = NO;
203 | GCC_NO_COMMON_BLOCKS = YES;
204 | GCC_OPTIMIZATION_LEVEL = 0;
205 | GCC_PREPROCESSOR_DEFINITIONS = (
206 | "DEBUG=1",
207 | "$(inherited)",
208 | );
209 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
210 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
211 | GCC_WARN_UNDECLARED_SELECTOR = YES;
212 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
213 | GCC_WARN_UNUSED_FUNCTION = YES;
214 | GCC_WARN_UNUSED_VARIABLE = YES;
215 | IPHONEOS_DEPLOYMENT_TARGET = 11.3;
216 | MTL_ENABLE_DEBUG_INFO = YES;
217 | ONLY_ACTIVE_ARCH = YES;
218 | SDKROOT = iphoneos;
219 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
220 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
221 | VERSIONING_SYSTEM = "apple-generic";
222 | VERSION_INFO_PREFIX = "";
223 | };
224 | name = Debug;
225 | };
226 | 693DBCF420E6DE6E00202D14 /* Release */ = {
227 | isa = XCBuildConfiguration;
228 | buildSettings = {
229 | ALWAYS_SEARCH_USER_PATHS = NO;
230 | CLANG_ANALYZER_NONNULL = YES;
231 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
232 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
233 | CLANG_CXX_LIBRARY = "libc++";
234 | CLANG_ENABLE_MODULES = YES;
235 | CLANG_ENABLE_OBJC_ARC = YES;
236 | CLANG_ENABLE_OBJC_WEAK = YES;
237 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
238 | CLANG_WARN_BOOL_CONVERSION = YES;
239 | CLANG_WARN_COMMA = YES;
240 | CLANG_WARN_CONSTANT_CONVERSION = YES;
241 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
243 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
244 | CLANG_WARN_EMPTY_BODY = YES;
245 | CLANG_WARN_ENUM_CONVERSION = YES;
246 | CLANG_WARN_INFINITE_RECURSION = YES;
247 | CLANG_WARN_INT_CONVERSION = YES;
248 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
249 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
250 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
252 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
253 | CLANG_WARN_STRICT_PROTOTYPES = YES;
254 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
255 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
256 | CLANG_WARN_UNREACHABLE_CODE = YES;
257 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
258 | CODE_SIGN_IDENTITY = "iPhone Developer";
259 | COPY_PHASE_STRIP = NO;
260 | CURRENT_PROJECT_VERSION = 1;
261 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
262 | ENABLE_NS_ASSERTIONS = NO;
263 | ENABLE_STRICT_OBJC_MSGSEND = YES;
264 | GCC_C_LANGUAGE_STANDARD = gnu11;
265 | GCC_NO_COMMON_BLOCKS = YES;
266 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
267 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
268 | GCC_WARN_UNDECLARED_SELECTOR = YES;
269 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
270 | GCC_WARN_UNUSED_FUNCTION = YES;
271 | GCC_WARN_UNUSED_VARIABLE = YES;
272 | IPHONEOS_DEPLOYMENT_TARGET = 11.3;
273 | MTL_ENABLE_DEBUG_INFO = NO;
274 | SDKROOT = iphoneos;
275 | SWIFT_COMPILATION_MODE = wholemodule;
276 | SWIFT_OPTIMIZATION_LEVEL = "-O";
277 | VALIDATE_PRODUCT = YES;
278 | VERSIONING_SYSTEM = "apple-generic";
279 | VERSION_INFO_PREFIX = "";
280 | };
281 | name = Release;
282 | };
283 | 693DBCF620E6DE6E00202D14 /* Debug */ = {
284 | isa = XCBuildConfiguration;
285 | buildSettings = {
286 | CODE_SIGN_IDENTITY = "";
287 | CODE_SIGN_STYLE = Automatic;
288 | DEFINES_MODULE = YES;
289 | DEVELOPMENT_TEAM = V92SZ8966T;
290 | DYLIB_COMPATIBILITY_VERSION = 1;
291 | DYLIB_CURRENT_VERSION = 1;
292 | DYLIB_INSTALL_NAME_BASE = "@rpath";
293 | INFOPLIST_FILE = SwiftyFeedback/Info.plist;
294 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
295 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
296 | LD_RUNPATH_SEARCH_PATHS = (
297 | "$(inherited)",
298 | "@executable_path/Frameworks",
299 | "@loader_path/Frameworks",
300 | );
301 | PRODUCT_BUNDLE_IDENTIFIER = com.juanpablofernandez.SwiftyFeedback;
302 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
303 | SKIP_INSTALL = YES;
304 | SWIFT_VERSION = 4.0;
305 | TARGETED_DEVICE_FAMILY = "1,2";
306 | };
307 | name = Debug;
308 | };
309 | 693DBCF720E6DE6E00202D14 /* Release */ = {
310 | isa = XCBuildConfiguration;
311 | buildSettings = {
312 | CODE_SIGN_IDENTITY = "";
313 | CODE_SIGN_STYLE = Automatic;
314 | DEFINES_MODULE = YES;
315 | DEVELOPMENT_TEAM = V92SZ8966T;
316 | DYLIB_COMPATIBILITY_VERSION = 1;
317 | DYLIB_CURRENT_VERSION = 1;
318 | DYLIB_INSTALL_NAME_BASE = "@rpath";
319 | INFOPLIST_FILE = SwiftyFeedback/Info.plist;
320 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
321 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
322 | LD_RUNPATH_SEARCH_PATHS = (
323 | "$(inherited)",
324 | "@executable_path/Frameworks",
325 | "@loader_path/Frameworks",
326 | );
327 | PRODUCT_BUNDLE_IDENTIFIER = com.juanpablofernandez.SwiftyFeedback;
328 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
329 | SKIP_INSTALL = YES;
330 | SWIFT_VERSION = 4.0;
331 | TARGETED_DEVICE_FAMILY = "1,2";
332 | };
333 | name = Release;
334 | };
335 | /* End XCBuildConfiguration section */
336 |
337 | /* Begin XCConfigurationList section */
338 | 693DBCE720E6DE6E00202D14 /* Build configuration list for PBXProject "SwiftyFeedback" */ = {
339 | isa = XCConfigurationList;
340 | buildConfigurations = (
341 | 693DBCF320E6DE6E00202D14 /* Debug */,
342 | 693DBCF420E6DE6E00202D14 /* Release */,
343 | );
344 | defaultConfigurationIsVisible = 0;
345 | defaultConfigurationName = Release;
346 | };
347 | 693DBCF520E6DE6E00202D14 /* Build configuration list for PBXNativeTarget "SwiftyFeedback" */ = {
348 | isa = XCConfigurationList;
349 | buildConfigurations = (
350 | 693DBCF620E6DE6E00202D14 /* Debug */,
351 | 693DBCF720E6DE6E00202D14 /* Release */,
352 | );
353 | defaultConfigurationIsVisible = 0;
354 | defaultConfigurationName = Release;
355 | };
356 | /* End XCConfigurationList section */
357 | };
358 | rootObject = 693DBCE420E6DE6E00202D14 /* Project object */;
359 | }
360 |
--------------------------------------------------------------------------------
/Example/Example.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 693A6F2C20E6F51000B63AA6 /* SwiftyFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 693A6F2B20E6F50800B63AA6 /* SwiftyFeedback.framework */; };
11 | 693A6F2D20E6F51000B63AA6 /* SwiftyFeedback.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 693A6F2B20E6F50800B63AA6 /* SwiftyFeedback.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
12 | 69E23BF820E6E0F100BD3AAE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E23BF720E6E0F100BD3AAE /* AppDelegate.swift */; };
13 | 69E23BFA20E6E0F100BD3AAE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69E23BF920E6E0F100BD3AAE /* ViewController.swift */; };
14 | 69E23BFD20E6E0F100BD3AAE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 69E23BFB20E6E0F100BD3AAE /* Main.storyboard */; };
15 | 69E23BFF20E6E0F200BD3AAE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 69E23BFE20E6E0F200BD3AAE /* Assets.xcassets */; };
16 | 69E23C0220E6E0F200BD3AAE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 69E23C0020E6E0F200BD3AAE /* LaunchScreen.storyboard */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXContainerItemProxy section */
20 | 693A6F2A20E6F50800B63AA6 /* PBXContainerItemProxy */ = {
21 | isa = PBXContainerItemProxy;
22 | containerPortal = 693A6F2620E6F50800B63AA6 /* SwiftyFeedback.xcodeproj */;
23 | proxyType = 2;
24 | remoteGlobalIDString = 693DBCED20E6DE6E00202D14;
25 | remoteInfo = SwiftyFeedback;
26 | };
27 | 693A6F2E20E6F51000B63AA6 /* PBXContainerItemProxy */ = {
28 | isa = PBXContainerItemProxy;
29 | containerPortal = 693A6F2620E6F50800B63AA6 /* SwiftyFeedback.xcodeproj */;
30 | proxyType = 1;
31 | remoteGlobalIDString = 693DBCEC20E6DE6E00202D14;
32 | remoteInfo = SwiftyFeedback;
33 | };
34 | /* End PBXContainerItemProxy section */
35 |
36 | /* Begin PBXCopyFilesBuildPhase section */
37 | 69E23C1220E6E11200BD3AAE /* Embed Frameworks */ = {
38 | isa = PBXCopyFilesBuildPhase;
39 | buildActionMask = 2147483647;
40 | dstPath = "";
41 | dstSubfolderSpec = 10;
42 | files = (
43 | 693A6F2D20E6F51000B63AA6 /* SwiftyFeedback.framework in Embed Frameworks */,
44 | );
45 | name = "Embed Frameworks";
46 | runOnlyForDeploymentPostprocessing = 0;
47 | };
48 | /* End PBXCopyFilesBuildPhase section */
49 |
50 | /* Begin PBXFileReference section */
51 | 693A6F2620E6F50800B63AA6 /* SwiftyFeedback.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftyFeedback.xcodeproj; path = ../SwiftyFeedback.xcodeproj; sourceTree = ""; };
52 | 69E23BF420E6E0F100BD3AAE /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 69E23BF720E6E0F100BD3AAE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
54 | 69E23BF920E6E0F100BD3AAE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
55 | 69E23BFC20E6E0F100BD3AAE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
56 | 69E23BFE20E6E0F200BD3AAE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
57 | 69E23C0120E6E0F200BD3AAE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
58 | 69E23C0320E6E0F200BD3AAE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
59 | /* End PBXFileReference section */
60 |
61 | /* Begin PBXFrameworksBuildPhase section */
62 | 69E23BF120E6E0F100BD3AAE /* Frameworks */ = {
63 | isa = PBXFrameworksBuildPhase;
64 | buildActionMask = 2147483647;
65 | files = (
66 | 693A6F2C20E6F51000B63AA6 /* SwiftyFeedback.framework in Frameworks */,
67 | );
68 | runOnlyForDeploymentPostprocessing = 0;
69 | };
70 | /* End PBXFrameworksBuildPhase section */
71 |
72 | /* Begin PBXGroup section */
73 | 693A6F2720E6F50800B63AA6 /* Products */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 693A6F2B20E6F50800B63AA6 /* SwiftyFeedback.framework */,
77 | );
78 | name = Products;
79 | sourceTree = "";
80 | };
81 | 69E23BEB20E6E0F100BD3AAE = {
82 | isa = PBXGroup;
83 | children = (
84 | 693A6F2620E6F50800B63AA6 /* SwiftyFeedback.xcodeproj */,
85 | 69E23BF620E6E0F100BD3AAE /* Example */,
86 | 69E23BF520E6E0F100BD3AAE /* Products */,
87 | );
88 | sourceTree = "";
89 | };
90 | 69E23BF520E6E0F100BD3AAE /* Products */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 69E23BF420E6E0F100BD3AAE /* Example.app */,
94 | );
95 | name = Products;
96 | sourceTree = "";
97 | };
98 | 69E23BF620E6E0F100BD3AAE /* Example */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 69E23BF720E6E0F100BD3AAE /* AppDelegate.swift */,
102 | 69E23BF920E6E0F100BD3AAE /* ViewController.swift */,
103 | 69E23BFB20E6E0F100BD3AAE /* Main.storyboard */,
104 | 69E23BFE20E6E0F200BD3AAE /* Assets.xcassets */,
105 | 69E23C0020E6E0F200BD3AAE /* LaunchScreen.storyboard */,
106 | 69E23C0320E6E0F200BD3AAE /* Info.plist */,
107 | );
108 | path = Example;
109 | sourceTree = "";
110 | };
111 | /* End PBXGroup section */
112 |
113 | /* Begin PBXNativeTarget section */
114 | 69E23BF320E6E0F100BD3AAE /* Example */ = {
115 | isa = PBXNativeTarget;
116 | buildConfigurationList = 69E23C0620E6E0F200BD3AAE /* Build configuration list for PBXNativeTarget "Example" */;
117 | buildPhases = (
118 | 69E23BF020E6E0F100BD3AAE /* Sources */,
119 | 69E23BF120E6E0F100BD3AAE /* Frameworks */,
120 | 69E23BF220E6E0F100BD3AAE /* Resources */,
121 | 69E23C1220E6E11200BD3AAE /* Embed Frameworks */,
122 | );
123 | buildRules = (
124 | );
125 | dependencies = (
126 | 693A6F2F20E6F51000B63AA6 /* PBXTargetDependency */,
127 | );
128 | name = Example;
129 | productName = Example;
130 | productReference = 69E23BF420E6E0F100BD3AAE /* Example.app */;
131 | productType = "com.apple.product-type.application";
132 | };
133 | /* End PBXNativeTarget section */
134 |
135 | /* Begin PBXProject section */
136 | 69E23BEC20E6E0F100BD3AAE /* Project object */ = {
137 | isa = PBXProject;
138 | attributes = {
139 | LastSwiftUpdateCheck = 0930;
140 | LastUpgradeCheck = 0930;
141 | ORGANIZATIONNAME = "Juan Pablo Fernandez";
142 | TargetAttributes = {
143 | 69E23BF320E6E0F100BD3AAE = {
144 | CreatedOnToolsVersion = 9.3;
145 | };
146 | };
147 | };
148 | buildConfigurationList = 69E23BEF20E6E0F100BD3AAE /* Build configuration list for PBXProject "Example" */;
149 | compatibilityVersion = "Xcode 9.3";
150 | developmentRegion = en;
151 | hasScannedForEncodings = 0;
152 | knownRegions = (
153 | en,
154 | Base,
155 | );
156 | mainGroup = 69E23BEB20E6E0F100BD3AAE;
157 | productRefGroup = 69E23BF520E6E0F100BD3AAE /* Products */;
158 | projectDirPath = "";
159 | projectReferences = (
160 | {
161 | ProductGroup = 693A6F2720E6F50800B63AA6 /* Products */;
162 | ProjectRef = 693A6F2620E6F50800B63AA6 /* SwiftyFeedback.xcodeproj */;
163 | },
164 | );
165 | projectRoot = "";
166 | targets = (
167 | 69E23BF320E6E0F100BD3AAE /* Example */,
168 | );
169 | };
170 | /* End PBXProject section */
171 |
172 | /* Begin PBXReferenceProxy section */
173 | 693A6F2B20E6F50800B63AA6 /* SwiftyFeedback.framework */ = {
174 | isa = PBXReferenceProxy;
175 | fileType = wrapper.framework;
176 | path = SwiftyFeedback.framework;
177 | remoteRef = 693A6F2A20E6F50800B63AA6 /* PBXContainerItemProxy */;
178 | sourceTree = BUILT_PRODUCTS_DIR;
179 | };
180 | /* End PBXReferenceProxy section */
181 |
182 | /* Begin PBXResourcesBuildPhase section */
183 | 69E23BF220E6E0F100BD3AAE /* Resources */ = {
184 | isa = PBXResourcesBuildPhase;
185 | buildActionMask = 2147483647;
186 | files = (
187 | 69E23C0220E6E0F200BD3AAE /* LaunchScreen.storyboard in Resources */,
188 | 69E23BFF20E6E0F200BD3AAE /* Assets.xcassets in Resources */,
189 | 69E23BFD20E6E0F100BD3AAE /* Main.storyboard in Resources */,
190 | );
191 | runOnlyForDeploymentPostprocessing = 0;
192 | };
193 | /* End PBXResourcesBuildPhase section */
194 |
195 | /* Begin PBXSourcesBuildPhase section */
196 | 69E23BF020E6E0F100BD3AAE /* Sources */ = {
197 | isa = PBXSourcesBuildPhase;
198 | buildActionMask = 2147483647;
199 | files = (
200 | 69E23BFA20E6E0F100BD3AAE /* ViewController.swift in Sources */,
201 | 69E23BF820E6E0F100BD3AAE /* AppDelegate.swift in Sources */,
202 | );
203 | runOnlyForDeploymentPostprocessing = 0;
204 | };
205 | /* End PBXSourcesBuildPhase section */
206 |
207 | /* Begin PBXTargetDependency section */
208 | 693A6F2F20E6F51000B63AA6 /* PBXTargetDependency */ = {
209 | isa = PBXTargetDependency;
210 | name = SwiftyFeedback;
211 | targetProxy = 693A6F2E20E6F51000B63AA6 /* PBXContainerItemProxy */;
212 | };
213 | /* End PBXTargetDependency section */
214 |
215 | /* Begin PBXVariantGroup section */
216 | 69E23BFB20E6E0F100BD3AAE /* Main.storyboard */ = {
217 | isa = PBXVariantGroup;
218 | children = (
219 | 69E23BFC20E6E0F100BD3AAE /* Base */,
220 | );
221 | name = Main.storyboard;
222 | sourceTree = "";
223 | };
224 | 69E23C0020E6E0F200BD3AAE /* LaunchScreen.storyboard */ = {
225 | isa = PBXVariantGroup;
226 | children = (
227 | 69E23C0120E6E0F200BD3AAE /* Base */,
228 | );
229 | name = LaunchScreen.storyboard;
230 | sourceTree = "";
231 | };
232 | /* End PBXVariantGroup section */
233 |
234 | /* Begin XCBuildConfiguration section */
235 | 69E23C0420E6E0F200BD3AAE /* Debug */ = {
236 | isa = XCBuildConfiguration;
237 | buildSettings = {
238 | ALWAYS_SEARCH_USER_PATHS = NO;
239 | CLANG_ANALYZER_NONNULL = YES;
240 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
242 | CLANG_CXX_LIBRARY = "libc++";
243 | CLANG_ENABLE_MODULES = YES;
244 | CLANG_ENABLE_OBJC_ARC = YES;
245 | CLANG_ENABLE_OBJC_WEAK = YES;
246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
247 | CLANG_WARN_BOOL_CONVERSION = YES;
248 | CLANG_WARN_COMMA = YES;
249 | CLANG_WARN_CONSTANT_CONVERSION = YES;
250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
252 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
253 | CLANG_WARN_EMPTY_BODY = YES;
254 | CLANG_WARN_ENUM_CONVERSION = YES;
255 | CLANG_WARN_INFINITE_RECURSION = YES;
256 | CLANG_WARN_INT_CONVERSION = YES;
257 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
258 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
259 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
261 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
262 | CLANG_WARN_STRICT_PROTOTYPES = YES;
263 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
264 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
265 | CLANG_WARN_UNREACHABLE_CODE = YES;
266 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
267 | CODE_SIGN_IDENTITY = "iPhone Developer";
268 | COPY_PHASE_STRIP = NO;
269 | DEBUG_INFORMATION_FORMAT = dwarf;
270 | ENABLE_STRICT_OBJC_MSGSEND = YES;
271 | ENABLE_TESTABILITY = YES;
272 | GCC_C_LANGUAGE_STANDARD = gnu11;
273 | GCC_DYNAMIC_NO_PIC = NO;
274 | GCC_NO_COMMON_BLOCKS = YES;
275 | GCC_OPTIMIZATION_LEVEL = 0;
276 | GCC_PREPROCESSOR_DEFINITIONS = (
277 | "DEBUG=1",
278 | "$(inherited)",
279 | );
280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
282 | GCC_WARN_UNDECLARED_SELECTOR = YES;
283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
284 | GCC_WARN_UNUSED_FUNCTION = YES;
285 | GCC_WARN_UNUSED_VARIABLE = YES;
286 | IPHONEOS_DEPLOYMENT_TARGET = 11.3;
287 | MTL_ENABLE_DEBUG_INFO = YES;
288 | ONLY_ACTIVE_ARCH = YES;
289 | SDKROOT = iphoneos;
290 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
291 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
292 | };
293 | name = Debug;
294 | };
295 | 69E23C0520E6E0F200BD3AAE /* Release */ = {
296 | isa = XCBuildConfiguration;
297 | buildSettings = {
298 | ALWAYS_SEARCH_USER_PATHS = NO;
299 | CLANG_ANALYZER_NONNULL = YES;
300 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
301 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
302 | CLANG_CXX_LIBRARY = "libc++";
303 | CLANG_ENABLE_MODULES = YES;
304 | CLANG_ENABLE_OBJC_ARC = YES;
305 | CLANG_ENABLE_OBJC_WEAK = YES;
306 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
307 | CLANG_WARN_BOOL_CONVERSION = YES;
308 | CLANG_WARN_COMMA = YES;
309 | CLANG_WARN_CONSTANT_CONVERSION = YES;
310 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
311 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
312 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
313 | CLANG_WARN_EMPTY_BODY = YES;
314 | CLANG_WARN_ENUM_CONVERSION = YES;
315 | CLANG_WARN_INFINITE_RECURSION = YES;
316 | CLANG_WARN_INT_CONVERSION = YES;
317 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
318 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
319 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
322 | CLANG_WARN_STRICT_PROTOTYPES = YES;
323 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
324 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
325 | CLANG_WARN_UNREACHABLE_CODE = YES;
326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
327 | CODE_SIGN_IDENTITY = "iPhone Developer";
328 | COPY_PHASE_STRIP = NO;
329 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
330 | ENABLE_NS_ASSERTIONS = NO;
331 | ENABLE_STRICT_OBJC_MSGSEND = YES;
332 | GCC_C_LANGUAGE_STANDARD = gnu11;
333 | GCC_NO_COMMON_BLOCKS = YES;
334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
336 | GCC_WARN_UNDECLARED_SELECTOR = YES;
337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
338 | GCC_WARN_UNUSED_FUNCTION = YES;
339 | GCC_WARN_UNUSED_VARIABLE = YES;
340 | IPHONEOS_DEPLOYMENT_TARGET = 11.3;
341 | MTL_ENABLE_DEBUG_INFO = NO;
342 | SDKROOT = iphoneos;
343 | SWIFT_COMPILATION_MODE = wholemodule;
344 | SWIFT_OPTIMIZATION_LEVEL = "-O";
345 | VALIDATE_PRODUCT = YES;
346 | };
347 | name = Release;
348 | };
349 | 69E23C0720E6E0F200BD3AAE /* Debug */ = {
350 | isa = XCBuildConfiguration;
351 | buildSettings = {
352 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
354 | CODE_SIGN_STYLE = Automatic;
355 | DEVELOPMENT_TEAM = V92SZ8966T;
356 | INFOPLIST_FILE = Example/Info.plist;
357 | LD_RUNPATH_SEARCH_PATHS = (
358 | "$(inherited)",
359 | "@executable_path/Frameworks",
360 | );
361 | PRODUCT_BUNDLE_IDENTIFIER = com.juanpablofernandez.Example;
362 | PRODUCT_NAME = "$(TARGET_NAME)";
363 | SWIFT_VERSION = 4.0;
364 | TARGETED_DEVICE_FAMILY = "1,2";
365 | };
366 | name = Debug;
367 | };
368 | 69E23C0820E6E0F200BD3AAE /* Release */ = {
369 | isa = XCBuildConfiguration;
370 | buildSettings = {
371 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
372 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
373 | CODE_SIGN_STYLE = Automatic;
374 | DEVELOPMENT_TEAM = V92SZ8966T;
375 | INFOPLIST_FILE = Example/Info.plist;
376 | LD_RUNPATH_SEARCH_PATHS = (
377 | "$(inherited)",
378 | "@executable_path/Frameworks",
379 | );
380 | PRODUCT_BUNDLE_IDENTIFIER = com.juanpablofernandez.Example;
381 | PRODUCT_NAME = "$(TARGET_NAME)";
382 | SWIFT_VERSION = 4.0;
383 | TARGETED_DEVICE_FAMILY = "1,2";
384 | };
385 | name = Release;
386 | };
387 | /* End XCBuildConfiguration section */
388 |
389 | /* Begin XCConfigurationList section */
390 | 69E23BEF20E6E0F100BD3AAE /* Build configuration list for PBXProject "Example" */ = {
391 | isa = XCConfigurationList;
392 | buildConfigurations = (
393 | 69E23C0420E6E0F200BD3AAE /* Debug */,
394 | 69E23C0520E6E0F200BD3AAE /* Release */,
395 | );
396 | defaultConfigurationIsVisible = 0;
397 | defaultConfigurationName = Release;
398 | };
399 | 69E23C0620E6E0F200BD3AAE /* Build configuration list for PBXNativeTarget "Example" */ = {
400 | isa = XCConfigurationList;
401 | buildConfigurations = (
402 | 69E23C0720E6E0F200BD3AAE /* Debug */,
403 | 69E23C0820E6E0F200BD3AAE /* Release */,
404 | );
405 | defaultConfigurationIsVisible = 0;
406 | defaultConfigurationName = Release;
407 | };
408 | /* End XCConfigurationList section */
409 | };
410 | rootObject = 69E23BEC20E6E0F100BD3AAE /* Project object */;
411 | }
412 |
--------------------------------------------------------------------------------