├── .gitignore
├── .idea
├── CTFeedbackSwift.iml
├── encodings.xml
├── modules.xml
├── runConfigurations
│ ├── CTFeedbackSwift.xml
│ ├── CTFeedbackSwiftTests.xml
│ └── Demo.xml
├── vcs.xml
├── workspace 2.xml
└── xcode.xml
├── .swift-version
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── CTFeedbackDemo
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
├── MainViewController.swift
├── ar.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── bs.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── cs-CZ.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── da.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── de.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── fa-IR.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── fr.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── hr-HR.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── it.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── ja.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── ko.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── nl.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── ru.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── sk.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── sr.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── sv-SE.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── tr.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── ur.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── zh-Hans.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
└── zh-Hant.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
├── CTFeedbackSwift.png
├── CTFeedbackSwift.podspec
├── CTFeedbackSwift.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── xcshareddata
│ └── xcschemes
│ │ ├── CTFeedbackSwift.xcscheme
│ │ ├── CTFeedbackSwiftTests.xcscheme
│ │ └── Demo.xcscheme
└── xcuserdata
│ └── rizumita.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── CTFeedbackSwift
├── Bundle+Extensions.swift
├── CTFeedbackSwift.h
├── CellFactory.swift
├── DrawUpPresentationController.swift
├── Feedback.swift
├── FeedbackConfiguration.swift
├── FeedbackEditing
│ ├── CTFeedbackError.swift
│ ├── FeedbackEditingItemsRepositoryProtocol.swift
│ ├── FeedbackEditingService.swift
│ └── FeedbackGenerator.swift
├── FeedbackItemProtocol.swift
├── FeedbackItemsDataSource.swift
├── FeedbackViewController.swift
├── FeedbackWireframe.swift
├── Functions.swift
├── Info.plist
├── Items
│ ├── AppBuild
│ │ ├── AppBuildCell.swift
│ │ └── AppBuildItem.swift
│ ├── AppName
│ │ ├── AppNameCell.swift
│ │ └── AppNameItem.swift
│ ├── AppVersion
│ │ ├── AppVersionCell.swift
│ │ └── AppVersionItem.swift
│ ├── Attachment
│ │ ├── AttachmentCell.swift
│ │ ├── AttachmentItem.swift
│ │ └── Media.swift
│ ├── Body
│ │ ├── BodyCell.swift
│ │ └── BodyItem.swift
│ ├── DeviceName
│ │ ├── DeviceNameCell.swift
│ │ └── DeviceNameItem.swift
│ ├── SystemVersion
│ │ ├── SystemVersionCell.swift
│ │ └── SystemVersionItem.swift
│ ├── Topic
│ │ ├── Topic.swift
│ │ ├── TopicCell.swift
│ │ └── TopicItem.swift
│ └── UserEmail
│ │ ├── UserEmailCell.swift
│ │ └── UserEmailItem.swift
├── Resources
│ ├── PlatformNames.plist
│ ├── ar.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── bs.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── cs-CZ.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── da.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── de.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── en.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── fa-IR.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── fr.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── hr-HR.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── it.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── ja.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── ko.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── nl.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── ru.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── sk.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── sr.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── sv-SE.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── tr.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── ur.lproj
│ │ └── CTFeedbackLocalizable.strings
│ ├── zh-Hans.lproj
│ │ └── CTFeedbackLocalizable.strings
│ └── zh-Hant.lproj
│ │ └── CTFeedbackLocalizable.strings
└── TopicsViewController.swift
├── CTFeedbackSwiftTests
├── Bundle+ExtensionsTests.swift
├── CellFactoryTests.swift
├── FeedbackEditing
│ ├── FeedbackEditingServiceTests.swift
│ └── FeedbackGeneratorTests.swift
├── FeedbackItemsDataSourceTests.swift
├── FunctionsTests.swift
├── Info.plist
└── Items
│ ├── AppBuild
│ └── AppBuildCellTests.swift
│ ├── AppName
│ └── AppNameCellTests.swift
│ ├── AppVersion
│ └── AppVersionCellTests.swift
│ ├── Attachment
│ ├── AttachmentCellTests.swift
│ └── AttachmentItemTests.swift
│ ├── Body
│ └── BodyCellTests.swift
│ ├── DeviceName
│ ├── DeviceNameCellTests.swift
│ └── DeviceNameItemTests.swift
│ ├── SystemVersion
│ ├── SystemVersionCellTests.swift
│ └── SystemVersionItemTests.swift
│ ├── Topic
│ ├── TopicCellTests.swift
│ └── TopicItemTests.swift
│ └── UserEmail
│ └── UserEmailCellTests.swift
├── LICENSE
├── Package.swift
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ### https://raw.github.com/github/gitignore/055194192edb9ace9bedf5e6bf6e49f6ab824c6e/Global/macOS.gitignore
2 |
3 | # General
4 | *.DS_Store
5 | .AppleDouble
6 | .LSOverride
7 |
8 | # Icon must end with two \r
9 | Icon
10 |
11 | # Thumbnails
12 | ._*
13 |
14 | # Files that might appear in the root of a volume
15 | .DocumentRevisions-V100
16 | .fseventsd
17 | .Spotlight-V100
18 | .TemporaryItems
19 | .Trashes
20 | .VolumeIcon.icns
21 | .com.apple.timemachine.donotpresent
22 |
23 | # Directories potentially created on remote AFP share
24 | .AppleDB
25 | .AppleDesktop
26 | Network Trash Folder
27 | Temporary Items
28 | .apdisk
29 |
30 |
31 | ### https://raw.github.com/github/gitignore/055194192edb9ace9bedf5e6bf6e49f6ab824c6e/Swift.gitignore
32 |
33 | # Xcode
34 | #
35 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
36 |
37 | ## Build generated
38 | build/
39 | DerivedData/
40 |
41 | ## Various settings
42 | *.pbxuser
43 | !default.pbxuser
44 | *.mode1v3
45 | !default.mode1v3
46 | *.mode2v3
47 | !default.mode2v3
48 | *.perspectivev3
49 | !default.perspectivev3
50 | xcuserdata/
51 |
52 | ## Other
53 | *.moved-aside
54 | *.xccheckout
55 | *.xcscmblueprint
56 |
57 | ## Obj-C/Swift specific
58 | *.hmap
59 | *.ipa
60 | *.dSYM.zip
61 | *.dSYM
62 |
63 | ## Playgrounds
64 | timeline.xctimeline
65 | playground.xcworkspace
66 |
67 | # Swift Package Manager
68 | #
69 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
70 | # Packages/
71 | # Package.pins
72 | # Package.resolved
73 | .build/
74 |
75 | # CocoaPods
76 | #
77 | # We recommend against adding the Pods directory to your .gitignore. However
78 | # you should judge for yourself, the pros and cons are mentioned at:
79 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
80 | #
81 | # Pods/
82 |
83 | # Carthage
84 | #
85 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
86 | # Carthage/Checkouts
87 |
88 | Carthage/Build
89 |
90 | # fastlane
91 | #
92 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
93 | # screenshots whenever they are needed.
94 | # For more information about the recommended setup visit:
95 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
96 |
97 | fastlane/report.xml
98 | fastlane/Preview.html
99 | fastlane/screenshots
100 | fastlane/test_output
101 |
102 |
103 | ### https://raw.github.com/github/gitignore/055194192edb9ace9bedf5e6bf6e49f6ab824c6e/Global/JetBrains.gitignore
104 |
105 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
106 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
107 |
108 | # User-specific stuff:
109 | .idea/**/workspace.xml
110 | .idea/**/tasks.xml
111 | .idea/dictionaries
112 |
113 | # Sensitive or high-churn files:
114 | .idea/**/dataSources/
115 | .idea/**/dataSources.ids
116 | .idea/**/dataSources.xml
117 | .idea/**/dataSources.local.xml
118 | .idea/**/sqlDataSources.xml
119 | .idea/**/dynamic.xml
120 | .idea/**/uiDesigner.xml
121 |
122 | # Gradle:
123 | .idea/**/gradle.xml
124 | .idea/**/libraries
125 |
126 | # CMake
127 | cmake-build-debug/
128 |
129 | # Mongo Explorer plugin:
130 | .idea/**/mongoSettings.xml
131 |
132 | ## File-based project format:
133 | *.iws
134 |
135 | ## Plugin-specific files:
136 |
137 | # IntelliJ
138 | out/
139 |
140 | # mpeltonen/sbt-idea plugin
141 | .idea_modules/
142 |
143 | # JIRA plugin
144 | atlassian-ide-plugin.xml
145 |
146 | # Cursive Clojure plugin
147 | .idea/replstate.xml
148 |
149 | # Crashlytics plugin (for Android Studio and IntelliJ)
150 | com_crashlytics_export_strings.xml
151 | crashlytics.properties
152 | crashlytics-build.properties
153 | fabric.properties
154 |
155 |
156 |
--------------------------------------------------------------------------------
/.idea/CTFeedbackSwift.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CTFeedbackSwift.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/CTFeedbackSwiftTests.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Demo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/xcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.0
2 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // CTFeedbackDemo
4 | //
5 | // Created by 和泉田 領一 on 2017/09/07.
6 | // Copyright © 2017年 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/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 | }
--------------------------------------------------------------------------------
/CTFeedbackDemo/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 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/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 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/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 | NSCameraUsageDescription
24 | Demo app uses camera
25 | NSMicrophoneUsageDescription
26 | Demo app uses microphone
27 | NSPhotoLibraryUsageDescription
28 | Demo app uses photo library
29 | UILaunchStoryboardName
30 | LaunchScreen
31 | UIMainStoryboardFile
32 | Main
33 | UIRequiredDeviceCapabilities
34 |
35 | armv7
36 |
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationLandscapeLeft
41 | UIInterfaceOrientationLandscapeRight
42 |
43 | UISupportedInterfaceOrientations~ipad
44 |
45 | UIInterfaceOrientationPortrait
46 | UIInterfaceOrientationPortraitUpsideDown
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/MainViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewController.swift
3 | // CTFeedbackDemo
4 | //
5 | // Created by 和泉田 領一 on 2017/09/07.
6 | // Copyright © 2017年 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CTFeedbackSwift
11 |
12 | class MainViewController: UITableViewController {
13 | enum PresentationType: String {
14 | case feedback = "Feedback"
15 | case feedbackCustom = "Feedback Custom"
16 | case feedbackSimple = "Feedback Simple"
17 | case feedbackModal = "Feedback Modal"
18 | }
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 |
23 | title = "Main"
24 | }
25 |
26 | override func didReceiveMemoryWarning() {
27 | super.didReceiveMemoryWarning()
28 | // Dispose of any resources that can be recreated.
29 | }
30 |
31 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
32 | guard let cell = tableView.cellForRow(at: indexPath),
33 | let identifier = cell.reuseIdentifier,
34 | let type = PresentationType(rawValue: identifier)
35 | else { fatalError() }
36 |
37 | switch type {
38 | case .feedback: showFeedback()
39 | case .feedbackCustom: ()
40 | case .feedbackSimple: ()
41 | case .feedbackModal: showFeedbackByModal()
42 | }
43 | }
44 |
45 | private func showFeedback() {
46 | let configuration = FeedbackConfiguration(toRecipients: ["test@example.com"],
47 | usesHTML: true)
48 | let controller = FeedbackViewController(configuration: configuration)
49 | navigationController?.pushViewController(controller, animated: true)
50 | }
51 |
52 | private func showFeedbackByModal() {
53 | let configuration = FeedbackConfiguration(toRecipients: ["test@example.com"],
54 | usesHTML: true)
55 | let controller = FeedbackViewController(configuration: configuration)
56 | let nav = UINavigationController(rootViewController: controller)
57 | navigationController?.present(nav, animated: true)
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ar.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/bs.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/bs.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/cs-CZ.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/cs-CZ.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/da.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/da.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/de.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/de.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/fa-IR.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/fa-IR.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/fr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/fr.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/hr-HR.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/hr-HR.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/it.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/it.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ja.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ja.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ko.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ko.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/nl.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/nl.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ru.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ru.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/sk.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/sk.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/sr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/sr.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/sv-SE.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/sv-SE.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/tr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/tr.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ur.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/ur.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/zh-Hans.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/zh-Hans.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/zh-Hant.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/CTFeedbackDemo/zh-Hant.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UILabel"; text = "Feedback - Simple"; ObjectID = "9zk-o1-xhH"; */
3 | "9zk-o1-xhH.text" = "Feedback - Simple";
4 |
5 | /* Class = "UINavigationItem"; title = "Root View Controller"; ObjectID = "Pgf-xs-Oef"; */
6 | "Pgf-xs-Oef.title" = "Root View Controller";
7 |
8 | /* Class = "UILabel"; text = "Feedback - Modal"; ObjectID = "ZOH-G7-6NW"; */
9 | "ZOH-G7-6NW.text" = "Feedback - Modal";
10 |
11 | /* Class = "UILabel"; text = "Feedback"; ObjectID = "aYu-TA-cZQ"; */
12 | "aYu-TA-cZQ.text" = "Feedback";
13 |
14 | /* Class = "UILabel"; text = "Feedback - Custom"; ObjectID = "y1T-Yo-hKa"; */
15 | "y1T-Yo-hKa.text" = "Feedback - Custom";
16 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rizumita/CTFeedbackSwift/0f6f64c674555a47b65a4e87c078651dac7ea0b6/CTFeedbackSwift.png
--------------------------------------------------------------------------------
/CTFeedbackSwift.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "CTFeedbackSwift"
3 | s.version = "0.1.9"
4 | s.summary = "Feedback composer for iOS"
5 | s.homepage = "https://github.com/rizumita/CTFeedbackSwift"
6 | s.screenshots = "https://github.com/rizumita/CTFeedbackSwift/raw/master/CTFeedbackSwift.png"
7 | s.license = "MIT"
8 | s.author = { "Ryoichi Izumita" => "r.izumita@caph.jp" }
9 | s.social_media_url = "http://twitter.com/rizumita"
10 | s.platform = :ios, "9.0"
11 | s.source = { :git => "https://github.com/rizumita/CTFeedbackSwift.git", :tag => "v#{s.version}" }
12 | s.source_files = "CTFeedbackSwift", "CTFeedbackSwift/**/*.{h,m,swift}"
13 | s.resources = ["CTFeedbackSwift/Resources/*.lproj", "CTFeedbackSwift/Resources/PlatformNames.plist"]
14 | s.framework = 'MessageUI'
15 | end
16 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/xcshareddata/xcschemes/CTFeedbackSwift.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/xcshareddata/xcschemes/CTFeedbackSwiftTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
61 |
63 |
64 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/CTFeedbackSwift.xcodeproj/xcuserdata/rizumita.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | CTFeedbackDemo.xcscheme
8 |
9 | orderHint
10 | 2
11 |
12 | CTFeedbackSwift.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 0
16 |
17 | CTFeedbackSwiftTests.xcscheme_^#shared#^_
18 |
19 | orderHint
20 | 3
21 |
22 | Demo.xcscheme_^#shared#^_
23 |
24 | orderHint
25 | 1
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Bundle+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 | import Dispatch
8 |
9 | var _feedbackBundle: Bundle?
10 |
11 | extension Bundle {
12 | static var feedbackBundle: Bundle {
13 | if let bundle = _feedbackBundle { return bundle }
14 |
15 | let bundle = Bundle(for: FeedbackViewController.self)
16 | _feedbackBundle = bundle
17 | return bundle
18 | }
19 |
20 | static var platformNamesPlistPath: String? {
21 | #if SWIFT_PACKAGE && swift(>=5.3)
22 | let bundles: [Bundle] = [Bundle.main, Bundle.feedbackBundle, Bundle.module]
23 | #else
24 | let bundles: [Bundle] = [Bundle.main, Bundle.feedbackBundle]
25 | #endif
26 |
27 | for bundle in bundles {
28 | guard let path = bundle.path(forResource: "PlatformNames", ofType: "plist")
29 | else { continue }
30 | return path
31 | }
32 | if let path = Bundle.main.path(forResource: "PlatformNames", ofType: "plist") {
33 | return path
34 | }
35 | return .none
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/CTFeedbackSwift.h:
--------------------------------------------------------------------------------
1 | //
2 | // CTFeedbackSwift.h
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/07.
6 | // Copyright © 2017年 CAPH TECH. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for CTFeedbackSwift.
12 | FOUNDATION_EXPORT double CTFeedbackSwiftVersionNumber;
13 |
14 | //! Project version string for CTFeedbackSwift.
15 | FOUNDATION_EXPORT const unsigned char CTFeedbackSwiftVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/CellFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | protocol CellFactoryProtocol {
9 | associatedtype Item
10 | associatedtype Cell: UITableViewCell
11 | associatedtype EventHandler
12 |
13 | static var reuseIdentifier: String { get }
14 |
15 | static func configure(_ cell: Cell,
16 | with item: Item,
17 | for indexPath: IndexPath,
18 | eventHandler: EventHandler)
19 | }
20 |
21 | extension CellFactoryProtocol {
22 | static var reuseIdentifier: String { return String(describing: self) }
23 |
24 | static func suitable(for item: Any) -> Bool { return item is Item }
25 |
26 | static func configure(_ cell: UITableViewCell,
27 | with item: Any,
28 | for indexPath: IndexPath,
29 | eventHandler: Any?) -> UITableViewCell? {
30 | guard let cell = cell as? Cell,
31 | let item = item as? Item,
32 | let eventHandler = eventHandler as? EventHandler
33 | else { return .none }
34 | configure(cell, with: item, for: indexPath, eventHandler: eventHandler)
35 | return cell
36 | }
37 | }
38 |
39 | public class AnyCellFactory {
40 | let cellType: AnyClass
41 | let reuseIdentifier: String
42 | private let suitableClosure: (Any) -> Bool
43 | private let configureCellClosure: (UITableViewCell, Any, IndexPath, Any?) -> UITableViewCell?
44 |
45 | init(_ cellFactory: Factory.Type) {
46 | cellType = Factory.Cell.self
47 | reuseIdentifier = cellFactory.reuseIdentifier
48 | suitableClosure = cellFactory.suitable(for:)
49 | configureCellClosure = cellFactory.configure(_:with:for:eventHandler:)
50 | }
51 |
52 | func suitable(for item: Any) -> Bool { return suitableClosure(item) }
53 |
54 | func configure(_ cell: UITableViewCell,
55 | with item: Any,
56 | for indexPath: IndexPath,
57 | eventHandler: Any?) -> UITableViewCell? {
58 | return configureCellClosure(cell, item, indexPath, eventHandler)
59 | }
60 |
61 | static func cellFactoryFilter() -> (Any, [AnyCellFactory]) -> AnyCellFactory? {
62 | var cache = [String : AnyCellFactory]()
63 | return { item, factories in
64 | let itemType = String(describing: type(of: item))
65 | if let factory = cache[itemType] {
66 | return factory
67 | } else if let factory = _cellFactoryFilter(item, factories) {
68 | cache[itemType] = factory
69 | return factory
70 | } else {
71 | return .none
72 | }
73 | }
74 | }
75 | }
76 |
77 | extension UITableView {
78 | func register(with cellFactory: AnyCellFactory) {
79 | register(cellFactory.cellType, forCellReuseIdentifier: cellFactory.reuseIdentifier)
80 | }
81 |
82 | func dequeueCell(to item: Any,
83 | from cellFactories: [AnyCellFactory],
84 | for indexPath: IndexPath,
85 | filter: (Any, [AnyCellFactory]) -> AnyCellFactory? = _cellFactoryFilter,
86 | eventHandler: Any?) -> UITableViewCell {
87 | guard let cellFactory = filter(item, cellFactories) else { fatalError() }
88 | let cell = dequeueReusableCell(withIdentifier: cellFactory.reuseIdentifier, for: indexPath)
89 | guard let configured = cellFactory.configure(cell,
90 | with: item,
91 | for: indexPath,
92 | eventHandler: eventHandler)
93 | else { fatalError() }
94 | return configured
95 | }
96 | }
97 |
98 | let _cellFactoryFilter: (Any, [AnyCellFactory]) -> AnyCellFactory? = { item, factories in
99 | return factories.first { $0.suitable(for: item) }
100 | }
101 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/DrawUpPresentationController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/17.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | class DrawUpPresentationController: UIPresentationController {
9 | var overlayView: UIView!
10 |
11 | func createOverlayView(withFrame frame: CGRect) -> UIView {
12 | let view = UIView(frame: frame)
13 | let gestureRecognizer = UITapGestureRecognizer(target: self,
14 | action: #selector(overlayTouched(_:)))
15 | view.addGestureRecognizer(gestureRecognizer)
16 | view.backgroundColor = .black
17 | view.alpha = 0.0
18 | return view
19 | }
20 |
21 | override func presentationTransitionWillBegin() {
22 | guard let containerView = self.containerView else { return }
23 | overlayView = createOverlayView(withFrame: containerView.bounds)
24 | containerView.insertSubview(overlayView, at: 0)
25 | presentedViewController.transitionCoordinator?.animate(alongsideTransition: { [unowned self]
26 | context in
27 | self.overlayView.alpha = 0.5
28 | })
29 | }
30 |
31 | override func dismissalTransitionWillBegin() {
32 | presentedViewController.transitionCoordinator?.animate(alongsideTransition: { context in
33 | self.overlayView.alpha = 0.0
34 | })
35 | }
36 |
37 | override func dismissalTransitionDidEnd(_ completed: Bool) {
38 | guard completed else { return }
39 | overlayView.removeFromSuperview()
40 | overlayView = .none
41 | }
42 |
43 | override func size(forChildContentContainer container: UIContentContainer,
44 | withParentContainerSize parentSize: CGSize) -> CGSize {
45 | return CGSize(width: parentSize.width, height: parentSize.height / 2.0)
46 | }
47 |
48 | override var frameOfPresentedViewInContainerView: CGRect {
49 | guard let containerBounds = containerView?.bounds else { return CGRect.zero }
50 | var result = CGRect.zero
51 | result.size = size(forChildContentContainer: presentedViewController,
52 | withParentContainerSize: containerBounds.size)
53 | result.origin.y = containerBounds.height - result.height
54 | return result
55 | }
56 |
57 | override func containerViewWillLayoutSubviews() {
58 | guard let containerBounds = containerView?.bounds else { return }
59 | overlayView.frame = containerBounds
60 | presentedView?.frame = frameOfPresentedViewInContainerView
61 | }
62 |
63 | @objc func overlayTouched(_ sender: Any) { presentedViewController.dismiss(animated: true) }
64 | }
65 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Feedback.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/25.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public struct Feedback {
9 | public let email: String?
10 | public let to: [String]
11 | public let cc: [String]
12 | public let bcc: [String]
13 | public let subject: String
14 | public let body: String
15 | public let isHTML: Bool
16 | public let jpeg: Data?
17 | public let mp4: Data?
18 | }
19 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public class FeedbackConfiguration {
9 | public var subject: String?
10 | public var additionalDiagnosticContent: String?
11 | public var toRecipients: [String]
12 | public var ccRecipients: [String]
13 | public var bccRecipients: [String]
14 | public var usesHTML: Bool
15 | public var dataSource: FeedbackItemsDataSource
16 |
17 | /*
18 | If topics array contains no topics, topics cell is hidden.
19 | */
20 | public init(subject: String? = .none,
21 | additionalDiagnosticContent: String? = .none,
22 | topics: [TopicProtocol] = TopicItem.defaultTopics,
23 | toRecipients: [String],
24 | ccRecipients: [String] = [],
25 | bccRecipients: [String] = [],
26 | hidesUserEmailCell: Bool = true,
27 | hidesAttachmentCell: Bool = false,
28 | hidesAppInfoSection: Bool = false,
29 | usesHTML: Bool = false,
30 | appName: String? = nil) {
31 | self.subject = subject
32 | self.additionalDiagnosticContent = additionalDiagnosticContent
33 | self.toRecipients = toRecipients
34 | self.ccRecipients = ccRecipients
35 | self.bccRecipients = bccRecipients
36 | self.usesHTML = usesHTML
37 | self.dataSource = FeedbackItemsDataSource(topics: topics,
38 | hidesUserEmailCell: hidesUserEmailCell,
39 | hidesAttachmentCell: hidesAttachmentCell,
40 | hidesAppInfoSection: hidesAppInfoSection,
41 | appName: appName)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackEditing/CTFeedbackError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/25.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | enum CTFeedbackError: Error {
9 | case unknown
10 | }
11 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackEditing/FeedbackEditingItemsRepositoryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/09.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public protocol FeedbackEditingItemsRepositoryProtocol {
9 | func item- (of type: Item.Type) -> Item?
10 |
11 | @discardableResult
12 | func set(item: Item) -> IndexPath?
13 | }
14 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackEditing/FeedbackEditingService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/09.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public protocol FeedbackEditingEventProtocol {
9 | func updated(at indexPath: IndexPath)
10 | }
11 |
12 | public protocol FeedbackEditingServiceProtocol {
13 | var topics: [TopicProtocol] { get }
14 | var hasAttachedMedia: Bool { get }
15 | func update(userEmailText: String?)
16 | func update(bodyText: String?)
17 | func update(selectedTopic: TopicProtocol)
18 | func update(attachmentMedia: Media?)
19 | func generateFeedback(configuration: FeedbackConfiguration) throws -> Feedback
20 | }
21 |
22 | public class FeedbackEditingService {
23 | var editingItemsRepository: FeedbackEditingItemsRepositoryProtocol
24 | let feedbackEditingEventHandler: FeedbackEditingEventProtocol
25 |
26 | public init(editingItemsRepository: FeedbackEditingItemsRepositoryProtocol,
27 | feedbackEditingEventHandler: FeedbackEditingEventProtocol) {
28 | self.editingItemsRepository = editingItemsRepository
29 | self.feedbackEditingEventHandler = feedbackEditingEventHandler
30 | }
31 | }
32 |
33 | extension FeedbackEditingService: FeedbackEditingServiceProtocol {
34 | public var topics: [TopicProtocol] {
35 | guard let item = editingItemsRepository.item(of: TopicItem.self) else { return [] }
36 | return item.topics
37 | }
38 |
39 | public var hasAttachedMedia: Bool {
40 | guard let item = editingItemsRepository.item(of: AttachmentItem.self) else { return false }
41 | return item.media != .none
42 | }
43 |
44 | public func update(userEmailText: String?) {
45 | guard var item = editingItemsRepository.item(of: UserEmailItem.self) else { return }
46 | item.email = userEmailText
47 | editingItemsRepository.set(item: item)
48 | }
49 |
50 | public func update(bodyText: String?) {
51 | guard var item = editingItemsRepository.item(of: BodyItem.self) else { return }
52 | item.bodyText = bodyText
53 | editingItemsRepository.set(item: item)
54 | }
55 |
56 | public func update(selectedTopic: TopicProtocol) {
57 | guard var item = editingItemsRepository.item(of: TopicItem.self) else { return }
58 | item.selected = selectedTopic
59 | guard let indexPath = editingItemsRepository.set(item: item) else { return }
60 | feedbackEditingEventHandler.updated(at: indexPath)
61 | }
62 |
63 | public func update(attachmentMedia: Media?) {
64 | guard var item = editingItemsRepository.item(of: AttachmentItem.self) else { return }
65 | item.media = attachmentMedia
66 | guard let indexPath = editingItemsRepository.set(item: item) else { return }
67 | feedbackEditingEventHandler.updated(at: indexPath)
68 | }
69 |
70 | public func generateFeedback(configuration: FeedbackConfiguration) throws -> Feedback {
71 | return try FeedbackGenerator.generate(configuration: configuration,
72 | repository: editingItemsRepository)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackEditing/FeedbackGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/25.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct FeedbackGenerator {
9 | static func generate(configuration: FeedbackConfiguration,
10 | repository: FeedbackEditingItemsRepositoryProtocol) throws -> Feedback {
11 | guard let deviceName = repository.item(of: DeviceNameItem.self)?.deviceName,
12 | let systemVersion = repository.item(of: SystemVersionItem.self)?.version
13 | else { throw CTFeedbackError.unknown }
14 | let appName = repository.item(of: AppNameItem.self)?.name ?? ""
15 | let appVersion = repository.item(of: AppVersionItem.self)?.version ?? ""
16 | let appBuild = repository.item(of: AppBuildItem.self)?.buildString ?? ""
17 | let email = repository.item(of: UserEmailItem.self)?.email
18 | let topic = repository.item(of: TopicItem.self)?.selected
19 | let attachment = repository.item(of: AttachmentItem.self)?.media
20 | let body = repository.item(of: BodyItem.self)?.bodyText ?? ""
21 |
22 | let subject = configuration.subject ?? generateSubject(appName: appName, topic: topic)
23 |
24 | let format = configuration.usesHTML ? generateHTML : generateString
25 | let formattedBody = format(body,
26 | deviceName,
27 | systemVersion,
28 | appName,
29 | appVersion,
30 | appBuild,
31 | configuration.additionalDiagnosticContent)
32 |
33 | return Feedback(email: email,
34 | to: configuration.toRecipients,
35 | cc: configuration.ccRecipients,
36 | bcc: configuration.bccRecipients,
37 | subject: subject,
38 | body: formattedBody,
39 | isHTML: configuration.usesHTML,
40 | jpeg: attachment?.jpegData,
41 | mp4: attachment?.videoData)
42 | }
43 |
44 | private static func generateSubject(appName: String, topic: TopicProtocol?) -> String {
45 | return String(format: "%@: %@", appName, topic?.title ?? "")
46 | }
47 |
48 | private static func generateHTML(body: String,
49 | deviceName: String,
50 | systemVersion: String,
51 | appName: String,
52 | appVersion: String,
53 | appBuild: String,
54 | additionalDiagnosticContent: String?) -> String {
55 | var platform = "iOS"
56 | #if targetEnvironment(macCatalyst)
57 | platform="macOS"
58 | #endif
59 | let format = """
60 |
61 |
%@
62 |
63 | Device: | %@ |
64 | %@: | %@ |
65 | App: | %@ |
66 | Version: | %@ |
67 | Build: | %@ |
68 |
69 | """
70 | var content: String = String(format: format,
71 | body.replacingOccurrences(of: "\n", with: "
"),
72 | deviceName,
73 | platform,
74 | systemVersion,
75 | appName,
76 | appVersion,
77 | appBuild)
78 | if let additional = additionalDiagnosticContent { content.append(additional) }
79 | return content
80 | }
81 |
82 | private static func generateString(body: String,
83 | deviceName: String,
84 | systemVersion: String,
85 | appName: String,
86 | appVersion: String,
87 | appBuild: String,
88 | additionalDiagnosticContent: String?) -> String {
89 | var platform = "iOS"
90 | #if targetEnvironment(macCatalyst)
91 | platform="macOS"
92 | #endif
93 | var content: String
94 | = String(format: "%@\n\n\nDevice: %@\n%@: %@\nApp: %@\nVersion: %@\nBuild: %@",
95 | body,
96 | deviceName,
97 | platform,
98 | systemVersion,
99 | appName,
100 | appVersion,
101 | appBuild)
102 | if let additional = additionalDiagnosticContent { content.append(additional) }
103 | return content
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackItemProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public protocol FeedbackItemProtocol {
9 | var isHidden: Bool { get }
10 | }
11 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackItemsDataSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public class FeedbackItemsDataSource {
9 | var sections: [FeedbackItemsSection] = []
10 |
11 | var numberOfSections: Int {
12 | return filteredSections.count
13 | }
14 |
15 | public init(topics: [TopicProtocol],
16 | hidesUserEmailCell: Bool = true,
17 | hidesAttachmentCell: Bool = false,
18 | hidesAppInfoSection: Bool = false,
19 | appName: String? = nil) {
20 | sections.append(FeedbackItemsSection(title: CTLocalizedString("CTFeedback.UserDetail"),
21 | items: [UserEmailItem(isHidden: hidesUserEmailCell)]))
22 | sections.append(FeedbackItemsSection(items: [TopicItem(topics), BodyItem()]))
23 | sections.append(FeedbackItemsSection(title: CTLocalizedString("CTFeedback.AdditionalInfo"),
24 | items: [AttachmentItem(isHidden: hidesAttachmentCell)]))
25 | sections.append(FeedbackItemsSection(title: CTLocalizedString("CTFeedback.DeviceInfo"),
26 | items: [DeviceNameItem(),
27 | SystemVersionItem()]))
28 | sections.append(FeedbackItemsSection(title: CTLocalizedString("CTFeedback.AppInfo"),
29 | items: [AppNameItem(isHidden: hidesAppInfoSection, name: appName),
30 | AppVersionItem(isHidden: hidesAppInfoSection),
31 | AppBuildItem(isHidden: hidesAppInfoSection)]))
32 | }
33 |
34 | func section(at section: Int) -> FeedbackItemsSection {
35 | return filteredSections[section]
36 | }
37 | }
38 |
39 | extension FeedbackItemsDataSource {
40 | private var filteredSections: [FeedbackItemsSection] {
41 | return sections.filter { section in
42 | section.items.filter { !$0.isHidden }.isEmpty == false
43 | }
44 | }
45 |
46 | private subscript(indexPath: IndexPath) -> FeedbackItemProtocol {
47 | get { return filteredSections[indexPath.section][indexPath.item] }
48 | set { filteredSections[indexPath.section][indexPath.item] = newValue }
49 | }
50 |
51 | private func indexPath- (of type: Item.Type) -> IndexPath? {
52 | let filtered = filteredSections
53 | for section in filtered {
54 | guard let index = filtered.firstIndex(where: { $0 === section }),
55 | let subIndex = section.items.firstIndex(where: { $0 is Item })
56 | else { continue }
57 | return IndexPath(item: subIndex, section: index)
58 | }
59 | return .none
60 | }
61 | }
62 |
63 | extension FeedbackItemsDataSource: FeedbackEditingItemsRepositoryProtocol {
64 | public func item
- (of type: Item.Type) -> Item? {
65 | guard let indexPath = indexPath(of: type) else { return .none }
66 | return self[indexPath] as? Item
67 | }
68 |
69 | @discardableResult
70 | public func set(item: Item) -> IndexPath? {
71 | guard let indexPath = indexPath(of: Item.self) else { return .none }
72 | self[indexPath] = item
73 | return indexPath
74 | }
75 | }
76 |
77 | class FeedbackItemsSection {
78 | let title: String?
79 | var items: [FeedbackItemProtocol]
80 |
81 | init(title: String? = .none, items: [FeedbackItemProtocol]) {
82 | self.title = title
83 | self.items = items
84 | }
85 | }
86 |
87 | extension FeedbackItemsSection: Collection {
88 | var startIndex: Int { return items.startIndex }
89 | var endIndex: Int { return items.endIndex }
90 |
91 | subscript(position: Int) -> FeedbackItemProtocol {
92 | get { return items[position] }
93 | set { items[position] = newValue }
94 | }
95 |
96 | func index(after i: Int) -> Int { return items.index(after: i) }
97 | }
98 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/FeedbackWireframe.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/25.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 | import MobileCoreServices
8 | import MessageUI
9 |
10 | protocol FeedbackWireframeProtocol {
11 | func showTopicsView(with service: FeedbackEditingServiceProtocol)
12 | func showMailComposer(with feedback: Feedback)
13 | func showAttachmentActionSheet(cellRect: CGRect,
14 | authorizePhotoLibrary: @escaping (@escaping (Bool) -> ()) -> (),
15 | authorizeCamera: @escaping (@escaping (Bool) -> ()) -> (),
16 | deleteAction: (() -> ())?)
17 | func showFeedbackGenerationError()
18 | func showUnknownErrorAlert()
19 | func showMailComposingError(_ error: NSError)
20 | func dismiss(completion: (() -> ())?)
21 | func pop()
22 | }
23 |
24 | final class FeedbackWireframe {
25 | private weak var viewController: UIViewController?
26 | private weak var transitioningDelegate: UIViewControllerTransitioningDelegate?
27 | private weak var imagePickerDelegate: (UIImagePickerControllerDelegate & UINavigationControllerDelegate)?
28 | private weak var mailComposerDelegate: MFMailComposeViewControllerDelegate?
29 |
30 | init(viewController: UIViewController,
31 | transitioningDelegate: UIViewControllerTransitioningDelegate,
32 | imagePickerDelegate: UIImagePickerControllerDelegate & UINavigationControllerDelegate,
33 | mailComposerDelegate: MFMailComposeViewControllerDelegate) {
34 | self.viewController = viewController
35 | self.transitioningDelegate = transitioningDelegate
36 | self.imagePickerDelegate = imagePickerDelegate
37 | self.mailComposerDelegate = mailComposerDelegate
38 | }
39 | }
40 |
41 | extension FeedbackWireframe: FeedbackWireframeProtocol {
42 | func showTopicsView(with service: FeedbackEditingServiceProtocol) {
43 | let controller = TopicsViewController(service: service)
44 | controller.modalPresentationStyle = .custom
45 | controller.transitioningDelegate = transitioningDelegate
46 |
47 | DispatchQueue.main.async { self.viewController?.present(controller, animated: true) }
48 | }
49 |
50 | func showMailComposer(with feedback: Feedback) {
51 | guard MFMailComposeViewController.canSendMail() else { return showMailConfigurationError() }
52 | let controller: MFMailComposeViewController = MFMailComposeViewController()
53 | controller.mailComposeDelegate = mailComposerDelegate
54 | controller.setToRecipients(feedback.to)
55 | controller.setCcRecipients(feedback.cc)
56 | controller.setBccRecipients(feedback.bcc)
57 | controller.setSubject(feedback.subject)
58 | controller.setMessageBody(feedback.body, isHTML: feedback.isHTML)
59 | if let jpeg = feedback.jpeg {
60 | controller.addAttachmentData(jpeg, mimeType: "image/jpeg", fileName: "screenshot.jpg")
61 | } else if let mp4 = feedback.mp4 {
62 | controller.addAttachmentData(mp4, mimeType: "video/mp4", fileName: "screenshot.mp4")
63 | }
64 | viewController?.present(controller, animated: true)
65 | }
66 |
67 | func showAttachmentActionSheet(cellRect: CGRect,
68 | authorizePhotoLibrary: @escaping (@escaping (Bool) -> ()) -> (),
69 | authorizeCamera: @escaping (@escaping (Bool) -> ()) -> (),
70 | deleteAction: (() -> ())?) {
71 | let alertController = UIAlertController(title: .none,
72 | message: .none,
73 | preferredStyle: .actionSheet)
74 | if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
75 | alertController.addAction(
76 | UIAlertAction(title: CTLocalizedString("CTFeedback.PhotoLibrary"),
77 | style: .default) { _ in
78 | authorizePhotoLibrary { granted in
79 | if granted {
80 | self.showImagePicker(sourceType: .photoLibrary)
81 | } else {
82 | self.showPhotoLibraryAuthorizingAlert()
83 | }
84 | }
85 | })
86 | }
87 | if UIImagePickerController.isSourceTypeAvailable(.camera) {
88 | alertController.addAction(
89 | UIAlertAction(title: CTLocalizedString("CTFeedback.Camera"),
90 | style: .default) { _ in
91 | authorizeCamera { granted in
92 | if granted {
93 | self.showImagePicker(sourceType: .camera)
94 | } else {
95 | self.showCameraAuthorizingAlert()
96 | }
97 | }
98 | })
99 | }
100 |
101 | if let delete = deleteAction {
102 | alertController.addAction(
103 | UIAlertAction(title: CTLocalizedString("CTFeedback.Delete"),
104 | style: .destructive) { _ in delete() })
105 | }
106 |
107 | alertController.addAction(UIAlertAction(title: CTLocalizedString("CTFeedback.Cancel"),
108 | style: .cancel))
109 | let screenSize = UIScreen.main.bounds
110 | alertController.popoverPresentationController?.sourceView = viewController?.view
111 | alertController.popoverPresentationController?.sourceRect = cellRect
112 | alertController.popoverPresentationController?.permittedArrowDirections = .any
113 |
114 | viewController?.present(alertController, animated: true)
115 | }
116 |
117 | func showFeedbackGenerationError() {
118 | let alertController
119 | = UIAlertController(title: CTLocalizedString("CTFeedback.Error"),
120 | message:
121 | CTLocalizedString("CTFeedback.FeedbackGenerationErrorMessage"),
122 | preferredStyle: .alert)
123 | alertController.addAction(UIAlertAction(title: CTLocalizedString("CTFeedback.Dismiss"),
124 | style: .cancel))
125 | viewController?.present(alertController, animated: true)
126 | }
127 |
128 | func showUnknownErrorAlert() {
129 | let title = CTLocalizedString("CTFeedback.UnknownError")
130 | let alertController = UIAlertController(title: title,
131 | message: .none,
132 | preferredStyle: .alert)
133 | alertController.addAction(UIAlertAction(title: CTLocalizedString("CTFeedback.Dismiss"),
134 | style: .default))
135 | viewController?.present(alertController, animated: true)
136 | }
137 |
138 | func showMailComposingError(_ error: NSError) {
139 | let alertController = UIAlertController(title: CTLocalizedString("CTFeedback.Error"),
140 | message: error.localizedDescription,
141 | preferredStyle: .alert)
142 | alertController.addAction(UIAlertAction(title: CTLocalizedString("CTFeedback.Dismiss"),
143 | style: .cancel))
144 | viewController?.present(alertController, animated: true)
145 | }
146 |
147 | func dismiss(completion: (() -> ())?) {
148 | viewController?.dismiss(animated: true, completion: completion)
149 | }
150 |
151 | func pop() { viewController?.navigationController?.popViewController(animated: true) }
152 | }
153 |
154 | private extension FeedbackWireframe {
155 | func showMailConfigurationError() {
156 | let alertController
157 | = UIAlertController(title: CTLocalizedString("CTFeedback.Error"),
158 | message:
159 | CTLocalizedString("CTFeedback.MailConfigurationErrorMessage"),
160 | preferredStyle: .alert)
161 | alertController.addAction(UIAlertAction(title: CTLocalizedString("CTFeedback.Dismiss"),
162 | style: .cancel))
163 | viewController?.present(alertController, animated: true)
164 | }
165 |
166 | func showImagePicker(sourceType: UIImagePickerController.SourceType) {
167 | let imagePicker = UIImagePickerController()
168 | imagePicker.sourceType = sourceType
169 | imagePicker.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]
170 | imagePicker.allowsEditing = false
171 | imagePicker.delegate = imagePickerDelegate
172 | imagePicker.modalPresentationStyle = .formSheet
173 | let presentation = imagePicker.popoverPresentationController
174 | presentation?.permittedArrowDirections = .any
175 | presentation?.sourceView = viewController?.view
176 | presentation?.sourceRect = viewController?.view.frame ?? CGRect.zero
177 | viewController?.present(imagePicker, animated: true)
178 | }
179 |
180 | func showPhotoLibraryAuthorizingAlert() {
181 | let alert = UIAlertController(title: .none,
182 | message: CTLocalizedString("CTFeedback.requiredLibraryAccess"),
183 | preferredStyle: .alert)
184 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
185 | if let url = URL(string: UIApplication.openSettingsURLString) {
186 | UIApplication.shared.openURL(url)
187 | }
188 | }))
189 | viewController?.present(alert, animated: true)
190 | }
191 |
192 | func showCameraAuthorizingAlert() {
193 | let alert = UIAlertController(title: .none,
194 | message: CTLocalizedString("CTFeedback.requiredCameraAccess"),
195 | preferredStyle: .alert)
196 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
197 | if let url = URL(string: UIApplication.openSettingsURLString) {
198 | UIApplication.shared.openURL(url)
199 | }
200 | }))
201 | viewController?.present(alert, animated: true)
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Functions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 | import MobileCoreServices
8 | import AVFoundation
9 |
10 | func CTLocalizedString(_ key: String) -> String {
11 | #if SWIFT_PACKAGE && swift(>=5.3)
12 | let bundles: [Bundle] = [Bundle.main, Bundle.feedbackBundle, Bundle.module]
13 | #else
14 | let bundles: [Bundle] = [Bundle.main, Bundle.feedbackBundle]
15 | #endif
16 |
17 | for bundle in bundles {
18 | let string = NSLocalizedString(key,
19 | tableName: "CTFeedbackLocalizable",
20 | bundle: bundle,
21 | comment: "")
22 | if key != string { return string }
23 | }
24 | return key
25 | }
26 |
27 | func getMediaFromImagePickerInfo(_ info: [String : Any]) -> Media? {
28 | let imageType = kUTTypeImage as String
29 | let movieType = kUTTypeMovie as String
30 |
31 | switch info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaType)] as? String {
32 | case imageType?:
33 | guard let image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.originalImage)] as? UIImage
34 | else { return .none }
35 | return .image(image)
36 | case movieType?:
37 | guard let url = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaURL)] as? URL else { return .none }
38 | return getMediaFromURL(url)
39 | default:
40 | return .none
41 | }
42 | }
43 |
44 | func getMediaFromURL(_ url: URL) -> Media? {
45 | let asset = AVURLAsset(url: url)
46 | let generator = AVAssetImageGenerator(asset: asset)
47 | generator.appliesPreferredTrackTransform = true
48 | let time = CMTimeMake(value: 1, timescale: 1)
49 | guard let cgImage = try? generator.copyCGImage(at: time, actualTime: .none)
50 | else { return .none }
51 | return .video(UIImage(cgImage: cgImage), url)
52 | }
53 |
54 | func push
- (_ item: Item?) -> (((Item) -> ()) -> ())? {
55 | guard let item = item else { return .none }
56 | return { closure in closure(item) }
57 | }
58 |
59 | // Helper function inserted by Swift 4.2 migrator.
60 | fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
61 | return input.rawValue
62 | }
63 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/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 | $(MARKETING_VERSION)
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/AppBuild/AppBuildCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppBuildCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/24.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class AppBuildCell: UITableViewCell {
12 | override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
13 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
14 | }
15 |
16 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
17 | }
18 |
19 | extension AppBuildCell: CellFactoryProtocol {
20 | class func configure(_ cell: AppBuildCell,
21 | with item: AppBuildItem,
22 | for indexPath: IndexPath,
23 | eventHandler: Any?) {
24 | cell.textLabel?.text = CTLocalizedString("CTFeedback.Build")
25 | cell.detailTextLabel?.text = item.buildString
26 | cell.selectionStyle = .none
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/AppBuild/AppBuildItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct AppBuildItem: FeedbackItemProtocol {
9 | var buildString: String {
10 | guard let build = Bundle.main.object(forInfoDictionaryKey: kCFBundleVersionKey as String) as? String
11 | else { return "" }
12 | return build
13 | }
14 |
15 | let isHidden: Bool
16 |
17 | init(isHidden: Bool) { self.isHidden = isHidden }
18 | }
19 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/AppName/AppNameCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppNameCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/24.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class AppNameCell: UITableViewCell {
12 | override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
13 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
14 | }
15 |
16 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
17 | }
18 |
19 | extension AppNameCell: CellFactoryProtocol {
20 | class func configure(_ cell: AppNameCell,
21 | with item: AppNameItem,
22 | for indexPath: IndexPath,
23 | eventHandler: Any?) {
24 | cell.textLabel?.text = CTLocalizedString("CTFeedback.Name")
25 | cell.detailTextLabel?.text = item.name
26 | cell.selectionStyle = .none
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/AppName/AppNameItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct AppNameItem: FeedbackItemProtocol {
9 | var name: String {
10 | if let result = _name {
11 | return result
12 | }
13 | if let displayName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String {
14 | return displayName
15 | }
16 | if let bundleName = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String {
17 | return bundleName
18 | }
19 | return ""
20 | }
21 |
22 | private var _name: String?
23 |
24 | let isHidden: Bool
25 |
26 | init(isHidden: Bool, name: String? = nil) {
27 | self.isHidden = isHidden
28 | self._name = name
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/AppVersion/AppVersionCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppVersionCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/24.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class AppVersionCell: UITableViewCell {
12 | override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
13 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
14 | }
15 |
16 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
17 | }
18 |
19 | extension AppVersionCell: CellFactoryProtocol {
20 | class func configure(_ cell: AppVersionCell,
21 | with item: AppVersionItem,
22 | for indexPath: IndexPath,
23 | eventHandler: Any?) {
24 | cell.textLabel?.text = CTLocalizedString("CTFeedback.Version")
25 | cell.detailTextLabel?.text = item.version
26 | cell.selectionStyle = .none
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/AppVersion/AppVersionItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct AppVersionItem: FeedbackItemProtocol {
9 | var version: String {
10 | guard let shortVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
11 | else { return "" }
12 | return shortVersion
13 | }
14 |
15 | let isHidden: Bool
16 |
17 | init(isHidden: Bool) { self.isHidden = isHidden }
18 | }
19 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Attachment/AttachmentCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/18.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | protocol AttachmentCellEventProtocol {
9 | func showImage(of item: AttachmentItem)
10 | }
11 |
12 | class AttachmentCell: UITableViewCell {
13 | private struct Const {
14 | static let NoAttachedCellHeight: CGFloat = 44.0
15 | static let AttachedCellHeight: CGFloat = 65.0
16 | static let Margin: CGFloat = 15.0
17 | }
18 |
19 | private var eventHandler: AttachmentCellEventProtocol!
20 | private var item: AttachmentItem?
21 |
22 | private let attachmentImageView = UIImageView()
23 | private var attachmentImageViewHeightConstraint: NSLayoutConstraint?
24 | private var attachmentImageViewWidthConstraint: NSLayoutConstraint?
25 |
26 | private let attachmentLabel = UILabel()
27 | private var attachmentLabelLeadingWithImageViewConstraint: NSLayoutConstraint?
28 | private var attachmentLabelLeadingWithContentViewViewConstraint: NSLayoutConstraint?
29 |
30 | private let tapImageViewGestureRecognizer = UITapGestureRecognizer()
31 |
32 | override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
33 | super.init(style: style, reuseIdentifier: reuseIdentifier)
34 |
35 | attachmentImageView.translatesAutoresizingMaskIntoConstraints = false
36 | contentView.addSubview(attachmentImageView)
37 | attachmentImageView.isUserInteractionEnabled = true
38 | attachmentImageViewHeightConstraint = attachmentImageView.heightAnchor
39 | .constraint(equalToConstant: Const.NoAttachedCellHeight)
40 | attachmentImageViewHeightConstraint?.isActive = true
41 | contentView.topAnchor.constraint(equalTo: attachmentImageView.topAnchor).isActive = true
42 | contentView.bottomAnchor.constraint(equalTo: attachmentImageView.bottomAnchor).isActive = true
43 | attachmentImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,
44 | constant: Const.Margin).isActive = true
45 | attachmentImageViewWidthConstraint = attachmentImageView.widthAnchor
46 | .constraint(equalToConstant: 0.0)
47 | attachmentImageViewWidthConstraint?.isActive = true
48 | attachmentImageView.addGestureRecognizer(tapImageViewGestureRecognizer)
49 | tapImageViewGestureRecognizer.addTarget(self, action: #selector(imageViewTapped(_:)))
50 |
51 | attachmentLabel.translatesAutoresizingMaskIntoConstraints = false
52 | attachmentLabel.numberOfLines = 0
53 | contentView.addSubview(attachmentLabel)
54 | attachmentLabel.adjustsFontSizeToFitWidth = true
55 | attachmentLabelLeadingWithImageViewConstraint
56 | = attachmentLabel.leadingAnchor.constraint(equalTo: attachmentImageView.trailingAnchor,
57 | constant: Const.Margin)
58 | attachmentLabelLeadingWithContentViewViewConstraint
59 | = attachmentLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,
60 | constant: Const.Margin)
61 | contentView.trailingAnchor.constraint(equalTo: attachmentLabel.trailingAnchor,
62 | constant: 0.0).isActive = true
63 | contentView.centerYAnchor.constraint(equalTo: attachmentLabel.centerYAnchor).isActive = true
64 | attachmentLabel.text = CTLocalizedString("CTFeedback.AttachImageOrVideo")
65 |
66 | accessoryType = .disclosureIndicator
67 | }
68 |
69 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
70 | }
71 |
72 | extension AttachmentCell {
73 | @objc func imageViewTapped(_ gestureRecognizer: UITapGestureRecognizer) {
74 | guard let item = item, item.image != .none else { return }
75 | eventHandler.showImage(of: item)
76 | }
77 | }
78 |
79 | extension AttachmentCell: CellFactoryProtocol {
80 | class func configure(_ cell: AttachmentCell,
81 | with item: AttachmentItem,
82 | for indexPath: IndexPath,
83 | eventHandler: AttachmentCellEventProtocol) {
84 | cell.item = item
85 |
86 | cell.imageView?.image = item.image
87 | if let heightConstraint = cell.attachmentImageViewHeightConstraint {
88 | heightConstraint.constant = item.attached ? Const.AttachedCellHeight : Const.NoAttachedCellHeight
89 |
90 | if let image = cell.imageView?.image {
91 | cell.attachmentImageViewWidthConstraint?.constant = image.size.width
92 | * heightConstraint.constant
93 | / image.size.height
94 | cell.attachmentLabelLeadingWithContentViewViewConstraint?.isActive = false
95 | cell.attachmentLabelLeadingWithImageViewConstraint?.isActive = true
96 | } else {
97 | cell.attachmentImageViewWidthConstraint?.constant = 0.0
98 | cell.attachmentLabelLeadingWithImageViewConstraint?.isActive = false
99 | cell.attachmentLabelLeadingWithContentViewViewConstraint?.isActive = true
100 | }
101 | }
102 | cell.eventHandler = eventHandler
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Attachment/AttachmentItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/18.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | struct AttachmentItem: FeedbackItemProtocol {
9 | var attached: Bool { return media != .none }
10 | var media: Media?
11 | var image: UIImage? {
12 | switch media {
13 | case .image(let i)?: return i
14 | case .video(let i, _)?: return i
15 | default: return .none
16 | }
17 | }
18 | let isHidden: Bool
19 |
20 | init(isHidden: Bool) { self.isHidden = isHidden }
21 | }
22 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Attachment/Media.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/22.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public enum Media: Equatable {
9 | var jpegData: Data? {
10 | guard case let .image(image) = self else { return .none }
11 | return image.jpegData(compressionQuality: 0.5)
12 | }
13 | var videoData: Data? {
14 | guard case let .video(_, url) = self else { return .none }
15 | return try? Data(contentsOf: url)
16 | }
17 | case image(UIImage)
18 | case video(UIImage, URL)
19 |
20 | public static func ==(lhs: Media, rhs: Media) -> Bool {
21 | switch (lhs, rhs) {
22 | case (.image(let lImage), .image(let rImage)):
23 | return lImage == rImage
24 | case (.video(_, let lUrl), .video(_, let rUrl)):
25 | return lUrl == rUrl
26 | default:
27 | return false
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Body/BodyCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BodyCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/16.
6 | // Copyright © 2017年 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol BodyCellEventProtocol {
12 | func bodyCellHeightChanged()
13 | func bodyTextDidChange(_ text: String?)
14 | }
15 |
16 | class BodyCell: UITableViewCell {
17 | var eventHandler: BodyCellEventProtocol?
18 |
19 | let textView: UITextView = {
20 | let result = UITextView(frame: CGRect.zero)
21 | result.translatesAutoresizingMaskIntoConstraints = false
22 | result.isScrollEnabled = false
23 | result.font = .systemFont(ofSize: 14.0)
24 | result.backgroundColor = .clear
25 | return result
26 | }()
27 |
28 | let placeholederLabel: UILabel = {
29 | let result = UILabel()
30 | result.text = CTLocalizedString("CTFeedback.BodyPlaceholder")
31 | result.font = .systemFont(ofSize: 14.0)
32 | result.numberOfLines = 1
33 | result.isUserInteractionEnabled = false
34 | result.translatesAutoresizingMaskIntoConstraints = false
35 | return result
36 | }()
37 |
38 | var heightConstraint: NSLayoutConstraint?
39 |
40 | var height: CGFloat {
41 | let size = textView.sizeThatFits(CGSize(width: textView.frame.width,
42 | height: CGFloat.greatestFiniteMagnitude))
43 | return max(100.0, size.height)
44 | }
45 |
46 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
47 | super.init(style: style, reuseIdentifier: reuseIdentifier)
48 |
49 | textView.delegate = self
50 | contentView.addSubview(textView)
51 | contentView.addSubview(placeholederLabel)
52 | contentView.topAnchor.constraint(equalTo: textView.topAnchor).isActive = true
53 | contentView.bottomAnchor.constraint(equalTo: textView.bottomAnchor).isActive = true
54 | contentView.leadingAnchor.constraint(equalTo: textView.leadingAnchor, constant: -12.0).isActive = true
55 | contentView.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: -12.0).isActive = true
56 | heightConstraint = contentView.heightAnchor.constraint(equalToConstant: height)
57 | heightConstraint?.priority = .defaultHigh
58 | heightConstraint?.isActive = true
59 |
60 | contentView.topAnchor.constraint(
61 | equalTo: placeholederLabel.topAnchor,
62 | constant: -8.0
63 | ).isActive = true
64 |
65 | contentView.leadingAnchor.constraint(
66 | equalTo: placeholederLabel.leadingAnchor,
67 | constant: -16.0
68 | ).isActive = true
69 |
70 | contentView.trailingAnchor.constraint(
71 | equalTo: placeholederLabel.trailingAnchor,
72 | constant: -16.0
73 | ).isActive = true
74 | }
75 |
76 | required init?(coder aDecoder: NSCoder) { fatalError() }
77 | }
78 |
79 | extension BodyCell: UITextViewDelegate {
80 | func textViewDidChange(_ textView: UITextView) {
81 | placeholederLabel.isHidden = !textView.text.isEmpty
82 | heightConstraint?.constant = height
83 | eventHandler?.bodyCellHeightChanged()
84 | eventHandler?.bodyTextDidChange(textView.text)
85 | }
86 | }
87 |
88 | extension BodyCell: CellFactoryProtocol {
89 | static func configure(_ cell: BodyCell,
90 | with item: BodyItem,
91 | for indexPath: IndexPath,
92 | eventHandler: BodyCellEventProtocol) {
93 | cell.textView.text = item.bodyText
94 | cell.selectionStyle = .none
95 | cell.eventHandler = eventHandler
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Body/BodyItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct BodyItem: FeedbackItemProtocol {
9 | var bodyText: String?
10 | let isHidden: Bool = false
11 | }
12 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/DeviceName/DeviceNameCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DeviceNameCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/24.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class DeviceNameCell: UITableViewCell {
12 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
13 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
14 | }
15 |
16 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
17 | }
18 |
19 | extension DeviceNameCell: CellFactoryProtocol {
20 | static let reuseIdentifier: String = "DeviceNameCell"
21 |
22 | static func configure(_ cell: DeviceNameCell,
23 | with item: DeviceNameItem,
24 | for indexPath: IndexPath,
25 | eventHandler: Any?) {
26 | cell.textLabel?.text = CTLocalizedString("CTFeedback.Device")
27 | cell.detailTextLabel?.text = item.deviceName
28 | cell.selectionStyle = .none
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/DeviceName/DeviceNameItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public struct DeviceNameItem: FeedbackItemProtocol {
9 | var deviceName: String {
10 | guard let path = Bundle.platformNamesPlistPath,
11 | let dictionary = NSDictionary(contentsOfFile: path) as? [String: String]
12 | else { return "" }
13 |
14 | let rawPlatform = platform
15 | return dictionary[rawPlatform] ?? rawPlatform
16 | }
17 |
18 | private var platform: String {
19 | var systemInfo = utsname()
20 | uname(&systemInfo)
21 | guard let machine = withUnsafePointer(to: &systemInfo.machine, {
22 | $0.withMemoryRebound(to: CChar.self, capacity: 1) {
23 | ptr in
24 | String.init(validatingUTF8: ptr)
25 | }
26 | }) else { return "Unknown" }
27 | return String(validatingUTF8: machine) ?? "Unknown"
28 | }
29 |
30 | public let isHidden: Bool = false
31 | }
32 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/SystemVersion/SystemVersionCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SystemVersionCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/24.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SystemVersionCell: UITableViewCell {
12 | override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
13 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
14 | }
15 |
16 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
17 | }
18 |
19 | extension SystemVersionCell: CellFactoryProtocol {
20 | class func configure(_ cell: SystemVersionCell,
21 | with item: SystemVersionItem,
22 | for indexPath: IndexPath,
23 | eventHandler: Any?) {
24 | #if targetEnvironment(macCatalyst)
25 | cell.textLabel?.text = "macOS"
26 | #else
27 | cell.textLabel?.text = CTLocalizedString("CTFeedback.iOS")
28 | #endif
29 | cell.detailTextLabel?.text = item.version
30 | cell.selectionStyle = .none
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/SystemVersion/SystemVersionItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | struct SystemVersionItem: FeedbackItemProtocol {
9 | var version: String { return UIDevice.current.systemVersion }
10 | let isHidden: Bool = false
11 | }
12 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Topic/Topic.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public protocol TopicProtocol {
9 | var title: String { get }
10 | var localizedTitle: String { get }
11 | }
12 |
13 | enum Topic: String {
14 | case question = "Question"
15 | case request = "Request"
16 | case bugReport = "Bug Report"
17 | case other = "Other"
18 | }
19 |
20 | extension Topic: TopicProtocol {
21 | var title: String { return rawValue }
22 | var localizedTitle: String { return CTLocalizedString(title) }
23 | }
24 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Topic/TopicCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | final public class TopicCell: UITableViewCell {
9 | public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
10 | super.init(style: .value1, reuseIdentifier: TopicCell.reuseIdentifier)
11 | }
12 |
13 | public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
14 | }
15 |
16 | extension TopicCell: CellFactoryProtocol {
17 | static func configure(_ cell: TopicCell,
18 | with item: TopicItem,
19 | for indexPath: IndexPath,
20 | eventHandler: Any?) {
21 | cell.textLabel?.text = CTLocalizedString("CTFeedback.Topic")
22 | cell.detailTextLabel?.text = item.topicTitle
23 | cell.accessoryType = .disclosureIndicator
24 | cell.selectionStyle = .none
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/Topic/TopicItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/07.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public struct TopicItem: FeedbackItemProtocol {
9 | public static var defaultTopics: [TopicProtocol] {
10 | return [Topic.question,
11 | Topic.request,
12 | Topic.bugReport,
13 | Topic.other]
14 | }
15 |
16 | var topicTitle: String { return selected?.localizedTitle ?? topics.first?.localizedTitle ?? "" }
17 | var topics: [TopicProtocol] = []
18 | var selected: TopicProtocol? {
19 | get { return _selected ?? topics.first }
20 | set { _selected = newValue }
21 | }
22 | private var _selected: TopicProtocol?
23 | public let isHidden: Bool
24 |
25 | init(_ topics: [TopicProtocol]) {
26 | self.topics = topics
27 | self.isHidden = topics.isEmpty
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/UserEmail/UserEmailCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserEmailCell.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/24.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | protocol UserEmailCellEventProtocol {
12 | func userEmailTextDidChange(_ text: String?)
13 | }
14 |
15 | class UserEmailCell: UITableViewCell {
16 | private struct Const {
17 | static let FontSize: CGFloat = 14.0
18 | static let Margin: CGFloat = 15.0
19 | static let Height: CGFloat = 44.0
20 | }
21 |
22 | private var eventHandler: UserEmailCellEventProtocol!
23 |
24 | let textField = UITextField()
25 |
26 | override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
27 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
28 |
29 | textField.backgroundColor = .clear
30 | textField.delegate = self
31 | textField.placeholder = CTLocalizedString("CTFeedback.Mail")
32 | textField.keyboardType = .emailAddress
33 | contentView.addSubview(textField)
34 | textField.translatesAutoresizingMaskIntoConstraints = false
35 | textField.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
36 | textField.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
37 | textField.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,
38 | constant: Const.Margin).isActive = true
39 | textField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,
40 | constant: Const.Margin).isActive = true
41 | textField.heightAnchor.constraint(equalToConstant: Const.Height).isActive = true
42 | }
43 |
44 | required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }
45 | }
46 |
47 | extension UserEmailCell: UITextFieldDelegate {
48 | func textField(_ textField: UITextField,
49 | shouldChangeCharactersIn range: NSRange,
50 | replacementString string: String) -> Bool {
51 | eventHandler.userEmailTextDidChange(textField.text)
52 | return true
53 | }
54 | }
55 |
56 | extension UserEmailCell: CellFactoryProtocol {
57 | class func configure(_ cell: UserEmailCell,
58 | with item: UserEmailItem,
59 | for indexPath: IndexPath,
60 | eventHandler: UserEmailCellEventProtocol) {
61 | cell.eventHandler = eventHandler
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Items/UserEmail/UserEmailItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 和泉田 領一 on 2017/09/24.
3 | // Copyright (c) 2017 CAPH TECH. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | struct UserEmailItem: FeedbackItemProtocol {
9 | let isHidden: Bool
10 | var email: String? = .none
11 |
12 | init(isHidden: Bool) { self.isHidden = isHidden }
13 | }
14 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/PlatformNames.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | iPhone1,1
6 | iPhone 1G
7 | iPhone1,2
8 | iPhone 3G
9 | iPhone2,1
10 | iPhone 3GS
11 | iPhone3,1
12 | iPhone 4
13 | iPhone3,3
14 | Verizon iPhone 4
15 | iPhone4,1
16 | iPhone 4S
17 | iPhone5,1
18 | iPhone 5 (GSM)
19 | iPhone5,2
20 | iPhone 5 (GSM+CDMA)
21 | iPhone5,3
22 | iPhone 5c (GSM)
23 | iPhone5,4
24 | iPhone 5c (Global)
25 | iPhone6,1
26 | iPhone 5s (GSM)
27 | iPhone6,2
28 | iPhone 5s (Global)
29 | iPhone7,2
30 | iPhone 6
31 | iPhone7,1
32 | iPhone 6 Plus
33 | iPhone8,1
34 | iPhone 6s
35 | iPhone8,2
36 | iPhone 6s Plus
37 | iPhone8,4
38 | iPhone SE
39 | iPhone9,1
40 | iPhone 7 (Global)
41 | iPhone9,2
42 | iPhone 7 Plus (Global)
43 | iPhone9,3
44 | iPhone 7 (GSM)
45 | iPhone9,4
46 | iPhone 7 Plus (GSM)
47 | iPhone10,1
48 | iPhone 8 (Global)
49 | iPhone10,4
50 | iPhone 8 (GSM)
51 | iPhone10,2
52 | iPhone 8 Plus (Global)
53 | iPhone10,5
54 | iPhone 8 Plus (GSM)
55 | iPhone10,3
56 | iPhone X (Global)
57 | iPhone10,6
58 | iPhone X (GSM)
59 | iPhone11,2
60 | iPhone XS
61 | iPhone11,4
62 | iPhone XS Max
63 | iPhone11,6
64 | iPhone XS Max China
65 | iPhone11,8
66 | iPhone XR
67 | iPhone12,1
68 | iPhone 11
69 | iPhone12,3
70 | iPhone 11 Pro
71 | iPhone12,5
72 | iPhone 11 Pro Max
73 | iPhone12,8
74 | iPhone SE (2nd Gen)
75 | iPhone13,1
76 | iPhone 12 Mini
77 | iPhone13,2
78 | iPhone 12
79 | iPhone13,3
80 | iPhone 12 Pro
81 | iPhone13,4
82 | iPhone 12 Pro Max
83 | iPhone14,2
84 | iPhone 13 Pro
85 | iPhone14,3
86 | iPhone 13 Pro Max
87 | iPhone14,4
88 | iPhone 13 Mini
89 | iPhone14,5
90 | iPhone 13
91 | iPod1,1
92 | iPod Touch 1G
93 | iPod2,1
94 | iPod Touch 2G
95 | iPod3,1
96 | iPod Touch 3G
97 | iPod4,1
98 | iPod Touch 4G
99 | iPod5,1
100 | iPod Touch 5G
101 | iPod7,1
102 | iPod Touch 6G
103 | iPod9,1
104 | iPod Touch 7G
105 | iPad1,1
106 | iPad
107 | iPad2,1
108 | iPad 2 (W i)
109 | iPad2,2
110 | iPad 2 (GSM)
111 | iPad2,3
112 | iPad 2 (CDMA)
113 | iPad2,4
114 | iPad 2
115 | iPad3,1
116 | iPad-3G (W i)
117 | iPad3,2
118 | iPad-3G (4G)
119 | iPad3,3
120 | iPad-3G (4G)
121 | iPad3,4
122 | iPad-4G (W i)
123 | iPad3,5
124 | iPad-4G (GSM)
125 | iPad3,6
126 | iPad-4G (GSM+CDMA)
127 | iPad4,1
128 | iPad Air (W i)
129 | iPad4,2
130 | iPad Air (Cellular)
131 | iPad4,3
132 | iPad Air
133 | iPad5,3
134 | iPad Air 2
135 | iPad5,4
136 | iPad Air 2
137 | iPad2,5
138 | iPad mini-1G (W i)
139 | iPad2,6
140 | iPad mini-1G (GSM)
141 | iPad2,7
142 | iPad mini-1G (GSM+CDMA)
143 | iPad4,4
144 | iPad mini-2G (W i)
145 | iPad4,5
146 | iPad mini-2G (Cellular)
147 | iPad4,6
148 | iPad mini 2
149 | iPad4,7
150 | iPad mini 3
151 | iPad4,8
152 | iPad mini 3
153 | iPad4,9
154 | iPad mini 3
155 | iPad5,1
156 | iPad mini 4
157 | iPad5,2
158 | iPad mini 4
159 | iPad6,7
160 | iPad Pro (12.9)
161 | iPad6,8
162 | iPad Pro (12.9)
163 | iPad6,3
164 | iPad Pro (9.7)
165 | iPad6,4
166 | iPad Pro (9.7)
167 | iPad6,11
168 | iPad (5th generation)
169 | iPad6,12
170 | iPad (5th generation)
171 | iPad7,1
172 | iPad Pro (12.9, 2nd generation)
173 | iPad7,2
174 | iPad Pro (12.9, 2nd generation)
175 | iPad7,3
176 | iPad Pro (10.5)
177 | iPad7,4
178 | iPad Pro (10.5)
179 | iPad7,5
180 | iPad (6th generation)
181 | iPad7,6
182 | iPad (6th generation)
183 | iPad8,1
184 | iPad Pro (11 WiFi)
185 | iPad8,2
186 | iPad Pro (11 1TB WiFi)
187 | iPad8,3
188 | iPad Pro (11 Cellular)
189 | iPad8,4
190 | iPad Pro (11 1TB Cellular)
191 | iPad8,5
192 | iPad Pro (12.9 3rd generation WiFi)
193 | iPad8,6
194 | iPad Pro (12.9 3rd generation 1TB WiFi)
195 | iPad8,7
196 | iPad Pro (12.9 3rd generation Cellular)
197 | iPad8,8
198 | iPad Pro (12.9 3rd generation 1TB Cellular)
199 | iPad8,9
200 | iPad Pro (11 2nd generation WiFi)
201 | iPad8,10
202 | iPad Pro (11 2nd generation 1TB WiFi)
203 | iPad8,11
204 | iPad Pro (12.9 4th generation WiFi)
205 | iPad8,12
206 | iPad Pro (12.9 4th generation Cellular)
207 | iPad11,1
208 | iPad mini (5th generation WiFi)
209 | iPad11,2
210 | iPad mini (5th generation Cellular)
211 | iPad11,3
212 | iPad Air (3rd generation WiFi)
213 | iPad11,4
214 | iPad Air (3rd generation Cellular)
215 |
216 |
217 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/ar.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ehab Abdou on 2016/05/10.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "سؤال";
8 |
9 | "Request" = "طلب";
10 |
11 | "Bug Report" = "الإبلاغ عن خطأ";
12 |
13 | "Other" = "آخر";
14 |
15 | "CTFeedback.Device" = "الجهاز";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "الاسم";
20 |
21 | "CTFeedback.Version" = "الإصدار";
22 |
23 | "CTFeedback.Build" = "البنية";
24 |
25 | "CTFeedback.DeviceInfo" = "معلومات الجهاز";
26 |
27 | "CTFeedback.AppInfo" = "معلومات التطبيق";
28 |
29 | "CTFeedback.Feedback" = "رأيك";
30 |
31 | "CTFeedback.Topic" = "الموضوع";
32 |
33 | "CTFeedback.Topics" = "المواضيع";
34 |
35 | "CTFeedback.Error" = "خطأ";
36 |
37 | "CTFeedback.Mail" = "إرسال";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="لم يكن لديك حساب بريد إلكتروني صالح";
40 |
41 | "CTFeedback.Dismiss" ="صرف";
42 |
43 | "CTFeedback.AdditionalInfo"="معلومات إضافية";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="اختر مرفق رأيك (صورة)";
46 |
47 | "CTFeedback.Cancel" ="إلغاء";
48 |
49 | "CTFeedback.Camera" ="كاميرا";
50 |
51 | "CTFeedback.PhotoLibrary" ="اختر من الألبوم";
52 |
53 | "CTFeedback.UserDetail"="معلومات المستخدم";
54 |
55 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
56 | "CTFeedback.UnknownError" = "Unknown Error";
57 | "CTFeedback.Delete" = "Delete";
58 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
59 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
60 |
61 | "CTFeedback.BodyPlaceholder" = "أدخل النص هنا";
62 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/bs.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Pitanje";
8 |
9 | "Request" = "Zahtjev";
10 |
11 | "Bug Report" = "Greška";
12 |
13 | "Other" = "Drugo";
14 |
15 | "CTFeedback.Device" = "Uređaj";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Ime";
20 |
21 | "CTFeedback.Version" = "Verzija";
22 |
23 | "CTFeedback.Build" = "Podverzija";
24 |
25 | "CTFeedback.DeviceInfo" = "Informacije o uređaju";
26 |
27 | "CTFeedback.AppInfo" = "Informacije o aplikaciji";
28 |
29 | "CTFeedback.Feedback" = "Povratna informacija";
30 |
31 | "CTFeedback.Topic" = "Tema";
32 |
33 | "CTFeedback.Topics" = "Teme";
34 |
35 | "CTFeedback.Error" = "Greška";
36 |
37 | "CTFeedback.Mail" = "E-mail";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="Nemate podešen e-mail račun";
40 |
41 | "CTFeedback.Dismiss" ="Zatvori";
42 |
43 | "CTFeedback.AdditionalInfo"="Dodatne informacije";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Izaberite prilog (sliku)";
46 |
47 | "CTFeedback.Cancel" ="Otkaži";
48 |
49 | "CTFeedback.Camera" ="Kamera";
50 |
51 | "CTFeedback.PhotoLibrary" ="Izaberite iz albuma";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Ovdje unesite tekst ...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/cs-CZ.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | CTFeedbackSwiftLanguages
4 |
5 | Created by Sebastian Szöcs on 9/28/21.
6 |
7 | */
8 | "Question" = "Otázka";
9 |
10 | "Request" = "Žádost";
11 |
12 | "Bug Report" = "Hlášení chyby";
13 |
14 | "Other" = "Jiný";
15 |
16 | "CTFeedback.Device" = "Zařízení";
17 |
18 | "CTFeedback.iOS" = "iOS";
19 |
20 | "CTFeedback.Name" = "Aplikace";
21 |
22 | "CTFeedback.Version" = "Verze";
23 |
24 | "CTFeedback.Build" = "Build";
25 |
26 | "CTFeedback.DeviceInfo" = "Informace o zařízení";
27 |
28 | "CTFeedback.AppInfo" = "Informace o aplikaci";
29 |
30 | "CTFeedback.Feedback" = "Zpětná vazba";
31 |
32 | "CTFeedback.Topic" = "Téma";
33 |
34 | "CTFeedback.Topics" = "Témata";
35 |
36 | "CTFeedback.Error" = "Chyba";
37 |
38 | "CTFeedback.Mail" = "Mail";
39 |
40 | "CTFeedback.MailConfigurationErrorMessage" ="Nemáš platný e-mailový účet";
41 |
42 | "CTFeedback.Dismiss" ="Zrušit";
43 |
44 | "CTFeedback.AdditionalInfo"="Doplňující informace";
45 |
46 | "CTFeedback.AttachImageOrVideo" ="Vyber přílohu pro zpětnou vazbu (obrázek)";
47 |
48 | "CTFeedback.Cancel" ="Zrušit";
49 |
50 | "CTFeedback.Camera" ="Kamera";
51 |
52 | "CTFeedback.PhotoLibrary" ="Vybrat fotku z knihovny";
53 | "CTFeedback.UserDetail" = "Detail uživatele";
54 | "CTFeedback.FeedbackGenerationErrorMessage" = "Vyskytla se chyba při generování zpětné vazby";
55 | "CTFeedback.UnknownError" = "Neznámá chyba";
56 | "CTFeedback.Delete" = "Vymazat";
57 | "CTFeedback.requiredCameraAccess" = "Aplikace vyžaduje přístup k fotoaparátu";
58 | "CTFeedback.requiredLibraryAccess" = "Aplikace vyžaduje přístup ke knihovne fotek pro vybrání snímku obrazovky";
59 |
60 | "CTFeedback.BodyPlaceholder" = "Sem zadej text...";
61 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/da.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Spørgsmål";
8 |
9 | "Request" = "Forespørgsel";
10 |
11 | "Bug Report" = "Fejlmelding";
12 |
13 | "Other" = "Andet";
14 |
15 | "CTFeedback.Device" = "Enhed";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Navn";
20 |
21 | "CTFeedback.Version" = "Version";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Information om enheden";
26 |
27 | "CTFeedback.AppInfo" = "Information om appen";
28 |
29 | "CTFeedback.Feedback" = "Feedback";
30 |
31 | "CTFeedback.Topic" = "Emne";
32 |
33 | "CTFeedback.Topics" = "Emner";
34 |
35 | "CTFeedback.Error" = "Fejl";
36 |
37 | "CTFeedback.Mail" = "Send";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="Du har ikke en gyldig email konto";
40 |
41 | "CTFeedback.Dismiss" ="Annuller";
42 |
43 | "CTFeedback.AdditionalInfo"="Yderligere information";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Vælg et billede";
46 |
47 | "CTFeedback.Cancel" ="Annuller";
48 |
49 | "CTFeedback.Camera" ="Kamera";
50 |
51 | "CTFeedback.PhotoLibrary" ="Vælg fra album";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Indtast tekst her ...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/de.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Frage";
8 |
9 | "Request" = "Anfrage";
10 |
11 | "Bug Report" = "Fehlerbericht";
12 |
13 | "Other" = "Sonstiges";
14 |
15 | "CTFeedback.Device" = "Gerät";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Name";
20 |
21 | "CTFeedback.Version" = "Version";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Geräte-Angaben";
26 |
27 | "CTFeedback.AppInfo" = "App-Angaben";
28 |
29 | "CTFeedback.Feedback" = "Feedback";
30 |
31 | "CTFeedback.Topic" = "Thema";
32 |
33 | "CTFeedback.Topics" = "Themen";
34 |
35 | "CTFeedback.Error" = "Fehler";
36 |
37 | "CTFeedback.Mail" = "E-Mail";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" = "Es ist kein gültiger E-Mail-Account eingerichtet.";
40 |
41 | "CTFeedback.Dismiss" = "Okay";
42 |
43 | "CTFeedback.AdditionalInfo" = "Zusätzliche Angaben";
44 |
45 | "CTFeedback.AttachImageOrVideo" = "Anhang für Feedback wählen (Foto)";
46 |
47 | "CTFeedback.Cancel" = "Abbrechen";
48 |
49 | "CTFeedback.Camera" = "Kamera";
50 |
51 | "CTFeedback.PhotoLibrary" = "Aus Album auswählen";
52 |
53 |
54 | "CTFeedback.UserDetail" = "User Detail";
55 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
56 | "CTFeedback.UnknownError" = "Unknown Error";
57 | "CTFeedback.Delete" = "Delete";
58 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
59 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
60 |
61 | "CTFeedback.BodyPlaceholder" = "Hier Text eingeben...";
62 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/en.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Question";
8 |
9 | "Request" = "Request";
10 |
11 | "Bug Report" = "Bug Report";
12 |
13 | "Other" = "Other";
14 |
15 | "CTFeedback.Device" = "Device";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Name";
20 |
21 | "CTFeedback.Version" = "Version";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Device Info";
26 |
27 | "CTFeedback.AppInfo" = "App Info";
28 |
29 | "CTFeedback.Feedback" = "Feedback";
30 |
31 | "CTFeedback.Topic" = "Topic";
32 |
33 | "CTFeedback.Topics" = "Topics";
34 |
35 | "CTFeedback.Error" = "Error";
36 |
37 | "CTFeedback.Mail" = "Mail";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="You do not have a valid e-mail account";
40 |
41 | "CTFeedback.Dismiss" ="Dismiss";
42 |
43 | "CTFeedback.AdditionalInfo"="Additional Info";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Select the feedback attachment (picture)";
46 |
47 | "CTFeedback.Cancel" ="Cancel";
48 |
49 | "CTFeedback.Camera" ="Camera";
50 |
51 | "CTFeedback.PhotoLibrary" ="Select from the album";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Enter text here...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/fa-IR.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "سوال";
8 |
9 | "Request" = "درخواست";
10 |
11 | "Bug Report" = "گزارش مشکل";
12 |
13 | "Other" = "دیگر";
14 |
15 | "CTFeedback.Device" = "دستگاه";
16 |
17 | "CTFeedback.iOS" = "آیاواس";
18 |
19 | "CTFeedback.Name" = "نام";
20 |
21 | "CTFeedback.Version" = "نسخه";
22 |
23 | "CTFeedback.Build" = "ساخت";
24 |
25 | "CTFeedback.DeviceInfo" = "اطلاعات دستگاه";
26 |
27 | "CTFeedback.AppInfo" = "اطلاعات برنامه";
28 |
29 | "CTFeedback.Feedback" = "نظر";
30 |
31 | "CTFeedback.Topic" = "موضوع";
32 |
33 | "CTFeedback.Topics" = "موضوعها";
34 |
35 | "CTFeedback.Error" = "خطا";
36 |
37 | "CTFeedback.Mail" = "ارسال پیام";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="شما ایمیل دستگاه خود را تنظیم نکردهاید";
40 |
41 | "CTFeedback.Dismiss" ="بستن";
42 |
43 | "CTFeedback.AdditionalInfo"="اطلاعات اضافه";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="پیوست خود را انتخاب کنید (تصویر)";
46 |
47 | "CTFeedback.Cancel" ="لغو";
48 |
49 | "CTFeedback.Camera" ="دوربین";
50 |
51 | "CTFeedback.PhotoLibrary" ="از آلبوم خود انتخاب کنید";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "متن را اینجا وارد کنید";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/fr.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Question";
8 |
9 | "Request" = "Requête";
10 |
11 | "Bug Report" = "Rapport de bug";
12 |
13 | "Other" = "Autre";
14 |
15 | "CTFeedback.Device" = "Appareil";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Nom";
20 |
21 | "CTFeedback.Version" = "Version";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Informations sur l'appareil";
26 |
27 | "CTFeedback.AppInfo" = "Informations sur l'application";
28 |
29 | "CTFeedback.Feedback" = "Support";
30 |
31 | "CTFeedback.Topic" = "Sujet";
32 |
33 | "CTFeedback.Topics" = "Sujets";
34 |
35 | "CTFeedback.Error" = "Error";
36 |
37 | "CTFeedback.Mail" = "Mail";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" = "Vous n'avez pas configuré de compte mail";
40 |
41 | "CTFeedback.Dismiss" = "Fermer";
42 |
43 | "CTFeedback.AdditionalInfo" = "Informations complémentaires";
44 |
45 | "CTFeedback.AttachImageOrVideo" = "Sélectionner une pièce-jointe (image)";
46 |
47 | "CTFeedback.Cancel" = "Annuler";
48 |
49 | "CTFeedback.Camera" = "Appareil photo";
50 |
51 | "CTFeedback.PhotoLibrary" = "Sélectionner depuis l'album";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.Delete" = "Delete";
54 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
55 | "CTFeedback.UnknownError" = "Unknown Error";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Entrez le texte ici...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/hr-HR.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Pitanje";
8 |
9 | "Request" = "Zahtjev";
10 |
11 | "Bug Report" = "Greška";
12 |
13 | "Other" = "Drugo";
14 |
15 | "CTFeedback.Device" = "Uređaj";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Ime";
20 |
21 | "CTFeedback.Version" = "Verzija";
22 |
23 | "CTFeedback.Build" = "Podverzija";
24 |
25 | "CTFeedback.DeviceInfo" = "Informacije o uređaju";
26 |
27 | "CTFeedback.AppInfo" = "Informacije o aplikaciji";
28 |
29 | "CTFeedback.Feedback" = "Povratna informacija";
30 |
31 | "CTFeedback.Topic" = "Tema";
32 |
33 | "CTFeedback.Topics" = "Teme";
34 |
35 | "CTFeedback.Error" = "Greška";
36 |
37 | "CTFeedback.Mail" = "E-mail";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="Nemate podešen e-mail račun";
40 |
41 | "CTFeedback.Dismiss" ="Zatvori";
42 |
43 | "CTFeedback.AdditionalInfo"="Dodatne informacije";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Izaberite prilog (sliku)";
46 |
47 | "CTFeedback.Cancel" ="Otkaži";
48 |
49 | "CTFeedback.Camera" ="Kamera";
50 |
51 | "CTFeedback.PhotoLibrary" ="Izaberite iz albuma";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Ovdje unesite tekst ...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/it.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Domanda";
8 |
9 | "Request" = "Richiesta";
10 |
11 | "Bug Report" = "Segnalazione Bug";
12 |
13 | "Other" = "Altro";
14 |
15 | "CTFeedback.Device" = "Dispositivo";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Nome";
20 |
21 | "CTFeedback.Version" = "Versione";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Informazioni sul Dispositivo";
26 |
27 | "CTFeedback.AppInfo" = "Informazioni sull'App";
28 |
29 | "CTFeedback.Feedback" = "Feedback";
30 |
31 | "CTFeedback.Topic" = "Argomento";
32 |
33 | "CTFeedback.Topics" = "Argomenti";
34 |
35 | "CTFeedback.Error" = "Errore";
36 |
37 | "CTFeedback.Mail" = "Invia";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="Account di posta non configurato";
40 |
41 | "CTFeedback.Dismiss" ="Chiudi";
42 |
43 | "CTFeedback.AdditionalInfo"="Informazioni Aggiuntive";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Seleziona un allegato (immagine)";
46 |
47 | "CTFeedback.Cancel" ="Annulla";
48 |
49 | "CTFeedback.Camera" ="Fotocamera";
50 |
51 | "CTFeedback.PhotoLibrary" ="Seleziona dalla libreria";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Inserisci qui il testo ...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/ja.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "質問";
8 |
9 | "Request" = "リクエスト";
10 |
11 | "Bug Report" = "バグレポート";
12 |
13 | "Other" = "その他";
14 |
15 | "CTFeedback.Device" = "デバイス";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "アプリ名";
20 |
21 | "CTFeedback.Version" = "バージョン";
22 |
23 | "CTFeedback.Build" = "ビルド";
24 |
25 | "CTFeedback.DeviceInfo" = "デバイス情報";
26 |
27 | "CTFeedback.AppInfo" = "アプリ情報";
28 |
29 | "CTFeedback.Feedback" = "フィードバック";
30 |
31 | "CTFeedback.Topic" = "トピック";
32 |
33 | "CTFeedback.Topics" = "トピック";
34 |
35 | "CTFeedback.Error" = "エラー";
36 |
37 | "CTFeedback.Mail" = "メール";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="有効な電子メールアカウントを持っていません";
40 |
41 | "CTFeedback.Dismiss" ="閉じる";
42 |
43 | "CTFeedback.AdditionalInfo"="追加情報";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="フィードバック添付画像を選択";
46 |
47 | "CTFeedback.Cancel" ="キャンセル";
48 |
49 | "CTFeedback.Camera" ="カメラ";
50 |
51 | "CTFeedback.PhotoLibrary" ="アルバムから選択";
52 | "CTFeedback.UserDetail" = "ユーザ情報";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "削除";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "ここにテキストを入力してください...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/ko.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "질문";
8 |
9 | "Request" = "요청";
10 |
11 | "Bug Report" = "버그 리포트";
12 |
13 | "Other" = "기타";
14 |
15 | "CTFeedback.Device" = "디바이스";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "이름";
20 |
21 | "CTFeedback.Version" = "버젼";
22 |
23 | "CTFeedback.Build" = "빌드";
24 |
25 | "CTFeedback.DeviceInfo" = "디바이스 정보";
26 |
27 | "CTFeedback.AppInfo" = "앱 정보";
28 |
29 | "CTFeedback.Feedback" = "피드백";
30 |
31 | "CTFeedback.Topic" = "주제";
32 |
33 | "CTFeedback.Topics" = "주제들";
34 |
35 | "CTFeedback.Error" = "오류";
36 |
37 | "CTFeedback.Mail" = "메일";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="정상적인 이메일 계정을 갖고 있지 않습니다";
40 |
41 | "CTFeedback.Dismiss" ="닫기";
42 |
43 | "CTFeedback.AdditionalInfo"="추가 정보";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="같이 전달할 첨부사진 고르기";
46 |
47 | "CTFeedback.Cancel" ="취소";
48 |
49 | "CTFeedback.Camera" ="카메라에서 선택";
50 |
51 | "CTFeedback.PhotoLibrary" ="앨범에서 선택";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "여기에 텍스트를 입력하세요 ...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/nl.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Vraag";
8 |
9 | "Request" = "Verzoek";
10 |
11 | "Bug Report" = "Bug verslag";
12 |
13 | "Other" = "Overig";
14 |
15 | "CTFeedback.Device" = "Toestel";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Naam";
20 |
21 | "CTFeedback.Version" = "Versie";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Toestel informatie";
26 |
27 | "CTFeedback.AppInfo" = "App informatie";
28 |
29 | "CTFeedback.Feedback" = "Feedback";
30 |
31 | "CTFeedback.Topic" = "Onderwerp";
32 |
33 | "CTFeedback.Topics" = "Topics";
34 |
35 | "CTFeedback.Error" = "Error";
36 |
37 | "CTFeedback.Mail" = "Mail";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" = "Je hebt geen geldige e-mail account";
40 |
41 | "CTFeedback.Dismiss" = "Sluiten";
42 |
43 | "CTFeedback.AdditionalInfo" = "Extra informatie";
44 |
45 | "CTFeedback.AttachImageOrVideo" = "Selecteer een afbeelding";
46 |
47 | "CTFeedback.Cancel" = "Annuleren";
48 |
49 | "CTFeedback.Camera" = "Camera";
50 |
51 | "CTFeedback.PhotoLibrary" = "Selecteer uit album";
52 |
53 | "CTFeedback.UserDetail" = "Gebruiker detail";
54 |
55 | "CTFeedback.UserDetail" = "User Detail";
56 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
57 | "CTFeedback.UnknownError" = "Unknown Error";
58 | "CTFeedback.Delete" = "Delete";
59 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
60 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
61 |
62 | "CTFeedback.BodyPlaceholder" = "Voeg hier tekst in...";
63 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/ru.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | // Edited by Dennis Kutlubaev (alwawee@gmail.com)
8 |
9 | "Question" = "Вопрос";
10 |
11 | "Request" = "Предложение";
12 |
13 | "Bug Report" = "Уведомление об ошибке";
14 |
15 | "Other" = "Другое";
16 |
17 | "CTFeedback.Device" = "Устройство";
18 |
19 | "CTFeedback.iOS" = "iOS";
20 |
21 | "CTFeedback.Name" = "Название";
22 |
23 | "CTFeedback.Version" = "Версия";
24 |
25 | "CTFeedback.Build" = "Сборка";
26 |
27 | "CTFeedback.DeviceInfo" = "Информация об устройстве";
28 |
29 | "CTFeedback.AppInfo" = "Информация о приложении";
30 |
31 | "CTFeedback.Feedback" = "Обратная связь";
32 |
33 | "CTFeedback.Topic" = "Тема";
34 |
35 | "CTFeedback.Topics" = "Темы";
36 |
37 | "CTFeedback.Error" = "Ошибка";
38 |
39 | "CTFeedback.Mail" = "Отправить";
40 |
41 | "CTFeedback.MailConfigurationErrorMessage" ="Отсутствует учётная запись электронной почты.";
42 |
43 | "CTFeedback.Dismiss" ="Dismiss";
44 |
45 | "CTFeedback.AdditionalInfo"="Дополнительная информация";
46 |
47 | "CTFeedback.AttachImageOrVideo" ="Прикрепить";
48 |
49 | "CTFeedback.Cancel" ="Отмена";
50 |
51 | "CTFeedback.Camera" ="Камера";
52 |
53 | "CTFeedback.PhotoLibrary" ="Фотоальбом";
54 |
55 | "CTFeedback.UserDetail"="Информация о пользователе";
56 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
57 | "CTFeedback.UnknownError" = "Unknown Error";
58 | "CTFeedback.Delete" = "Delete";
59 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
60 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
61 |
62 | "CTFeedback.BodyPlaceholder" = "Введите текст...";
63 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/sk.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | CTFeedbackSwiftLanguages
4 |
5 | Created by Sebastian Szöcs on 9/28/21.
6 |
7 | */
8 | "Question" = "Otázka";
9 |
10 | "Request" = "Požiadavka";
11 |
12 | "Bug Report" = "Hlásenie chyby";
13 |
14 | "Other" = "Ostatné";
15 |
16 | "CTFeedback.Device" = "Zariadenie";
17 |
18 | "CTFeedback.iOS" = "iOS";
19 |
20 | "CTFeedback.Name" = "Apka";
21 |
22 | "CTFeedback.Version" = "Verzia";
23 |
24 | "CTFeedback.Build" = "Build";
25 |
26 | "CTFeedback.DeviceInfo" = "Informácie o zariadení";
27 |
28 | "CTFeedback.AppInfo" = "Informácie o apke";
29 |
30 | "CTFeedback.Feedback" = "Spätná väzba";
31 |
32 | "CTFeedback.Topic" = "Téma";
33 |
34 | "CTFeedback.Topics" = "Témy";
35 |
36 | "CTFeedback.Error" = "Chyba";
37 |
38 | "CTFeedback.Mail" = "Mail";
39 |
40 | "CTFeedback.MailConfigurationErrorMessage" ="Nemáš platné e-mailové konto";
41 |
42 | "CTFeedback.Dismiss" ="Zrušiť";
43 |
44 | "CTFeedback.AdditionalInfo"="Dodatočné informácie";
45 |
46 | "CTFeedback.AttachImageOrVideo" ="Vyber prílohu pre spätnú väzbu (obrázok)";
47 |
48 | "CTFeedback.Cancel" ="Zrušiť";
49 |
50 | "CTFeedback.Camera" ="Kamera";
51 |
52 | "CTFeedback.PhotoLibrary" ="Vybrať z albumu";
53 | "CTFeedback.UserDetail" = "Detail užívateľa";
54 | "CTFeedback.FeedbackGenerationErrorMessage" = "Vyskytla sa chyba pri generovaní spätnej väzby";
55 | "CTFeedback.UnknownError" = "Neznáma chyba";
56 | "CTFeedback.Delete" = "Vymazať";
57 | "CTFeedback.requiredCameraAccess" = "Apka vyžaduje prístup ku kamere pre pridanie obrázku";
58 | "CTFeedback.requiredLibraryAccess" = "Apka vyžaduje prístup ku knižnici fotiek pre vybranie snímku obrazovky";
59 |
60 | "CTFeedback.BodyPlaceholder" = "Sem zadaj text...";
61 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/sr.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Питање";
8 |
9 | "Request" = "Захтјев";
10 |
11 | "Bug Report" = "Грешка";
12 |
13 | "Other" = "Друго";
14 |
15 | "CTFeedback.Device" = "Уређај";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Име";
20 |
21 | "CTFeedback.Version" = "Верзија";
22 |
23 | "CTFeedback.Build" = "Подверзија";
24 |
25 | "CTFeedback.DeviceInfo" = "Информације о иређају";
26 |
27 | "CTFeedback.AppInfo" = "Информације о програму";
28 |
29 | "CTFeedback.Feedback" = "Повратна информација";
30 |
31 | "CTFeedback.Topic" = "Тема";
32 |
33 | "CTFeedback.Topics" = "Теме";
34 |
35 | "CTFeedback.Error" = "Грешка";
36 |
37 | "CTFeedback.Mail" = "Е-маил";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="Немате подешен е-маил рачун";
40 |
41 | "CTFeedback.Dismiss" ="Затвори";
42 |
43 | "CTFeedback.AdditionalInfo"="Додатне информације";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Изаберите прилог (слику)";
46 |
47 | "CTFeedback.Cancel" ="Откажи";
48 |
49 | "CTFeedback.Camera" ="Камера";
50 |
51 | "CTFeedback.PhotoLibrary" ="Изаберите из албума";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "Овде унесите текст ...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/sv-SE.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "Förfrågan";
8 |
9 | "Request" = "Förslag";
10 |
11 | "Bug Report" = "Bugg";
12 |
13 | "Other" = "Annan";
14 |
15 | "CTFeedback.Device" = "Enhet";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "Namn";
20 |
21 | "CTFeedback.Version" = "Version";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "Enhetsinformation ";
26 |
27 | "CTFeedback.AppInfo" = "App Info";
28 |
29 | "CTFeedback.Feedback" = "Feedback";
30 |
31 | "CTFeedback.Topic" = "Ämne";
32 |
33 | "CTFeedback.Topics" = "Ämnen";
34 |
35 | "CTFeedback.Error" = "Felmeddelande";
36 |
37 | "CTFeedback.Mail" = "Skicka";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="Det går inte att verifiera ett giltligt epost-konto";
40 |
41 | "CTFeedback.Dismiss" ="Avfärda";
42 |
43 | "CTFeedback.AdditionalInfo"="Ytterligare information";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="Välj bifogad fil(bild) ";
46 |
47 | "CTFeedback.Cancel" ="Ångra";
48 |
49 | "CTFeedback.Camera" ="Kamera";
50 |
51 | "CTFeedback.PhotoLibrary" ="Välj från album";
52 |
53 | "CTFeedback.UserDetail"="Användardetaljer";
54 |
55 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
56 | "CTFeedback.UnknownError" = "Unknown Error";
57 | "CTFeedback.Delete" = "Delete";
58 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
59 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
60 |
61 | "CTFeedback.BodyPlaceholder" = "Ange text här ...";
62 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/tr.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | // Edited by Gürhan Yerlikaya (gurhanyerlikaya@gmail.com)
8 |
9 | "Question" = "Soru";
10 |
11 | "Request" = "İstek";
12 |
13 | "Bug Report" = "Hata bildirimi";
14 |
15 | "Other" = "Diğer";
16 |
17 | "CTFeedback.Device" = "Cihaz";
18 |
19 | "CTFeedback.iOS" = "iOS";
20 |
21 | "CTFeedback.Name" = "İsim";
22 |
23 | "CTFeedback.Version" = "Sürüm";
24 |
25 | "CTFeedback.Build" = "Build";
26 |
27 | "CTFeedback.DeviceInfo" = "Cihaz Bilgisi";
28 |
29 | "CTFeedback.AppInfo" = "Uygulama bilgisi";
30 |
31 | "CTFeedback.Feedback" = "Geri Bildirim";
32 |
33 | "CTFeedback.Topic" = "Konu";
34 |
35 | "CTFeedback.Topics" = "Konular";
36 |
37 | "CTFeedback.Error" = "Hata";
38 |
39 | "CTFeedback.Mail" = "Gönder";
40 |
41 | "CTFeedback.MailConfigurationErrorMessage" ="Cihazda tanımlı e-posta bulunamadı.";
42 |
43 | "CTFeedback.Dismiss" ="Son ver";
44 |
45 | "CTFeedback.AdditionalInfo"="Ek bilgi";
46 |
47 | "CTFeedback.AttachImageOrVideo" ="Detay";
48 |
49 | "CTFeedback.Cancel" ="İptal";
50 |
51 | "CTFeedback.Camera" ="Kamera";
52 |
53 | "CTFeedback.PhotoLibrary" ="Cihaz’dan ekle";
54 |
55 | "CTFeedback.UserDetail"="Kullanıcı detayı";
56 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
57 | "CTFeedback.UnknownError" = "Unknown Error";
58 | "CTFeedback.Delete" = "Delete";
59 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
60 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
61 |
62 | "CTFeedback.BodyPlaceholder" = "Yazıyı buraya girin...";
63 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/ur.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "سوال";
8 |
9 | "Request" = "درخواست";
10 |
11 | "Bug Report" = "بَگ رپورٹ";
12 |
13 | "Other" = "دیگر";
14 |
15 | "CTFeedback.Device" = "آلہ";
16 |
17 | "CTFeedback.iOS" = "آئی او ایس";
18 |
19 | "CTFeedback.Name" = "نام";
20 |
21 | "CTFeedback.Version" = "ورژن";
22 |
23 | "CTFeedback.Build" = "ساخت";
24 |
25 | "CTFeedback.DeviceInfo" = "معلوماتِ آلہ";
26 |
27 | "CTFeedback.AppInfo" = "معلوماتِ اطلاق";
28 |
29 | "CTFeedback.Feedback" = "رائے";
30 |
31 | "CTFeedback.Topic" = "موضوع";
32 |
33 | "CTFeedback.Topics" = "موضوعات";
34 |
35 | "CTFeedback.Error" = "غلطی";
36 |
37 | "CTFeedback.Mail" = "میل";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="آپ کے پاس جائز ای میل کھاتہ نہیں ہے";
40 |
41 | "CTFeedback.Dismiss" ="منسوخ";
42 |
43 | "CTFeedback.AdditionalInfo"="اضافی معلومات";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="رائے کا منسلکہ(تصویر) منتخب کیجیے";
46 |
47 | "CTFeedback.Cancel" ="منسوخ";
48 |
49 | "CTFeedback.Camera" ="کیمرہ";
50 |
51 | "CTFeedback.PhotoLibrary" ="البم سے منتخب کیجیے";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "یہاں متن درج کریں";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/zh-Hans.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "问题";
8 |
9 | "Request" = "需求";
10 |
11 | "Bug Report" = "程序错误报告";
12 |
13 | "Other" = "其他";
14 |
15 | "CTFeedback.Device" = "设备";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "名字";
20 |
21 | "CTFeedback.Version" = "版本";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "设备信息";
26 |
27 | "CTFeedback.AppInfo" = "应用信息";
28 |
29 | "CTFeedback.Feedback" = "反馈";
30 |
31 | "CTFeedback.Topic" = "主题";
32 |
33 | "CTFeedback.Topics" = "主题";
34 |
35 | "CTFeedback.Error" = "错误";
36 |
37 | "CTFeedback.Mail" = "邮件";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="您没有一个有效的邮件账户";
40 |
41 | "CTFeedback.Dismiss" ="Dismiss";
42 |
43 | "CTFeedback.AdditionalInfo"="附加信息";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="选择反馈附件(图片)";
46 |
47 | "CTFeedback.Cancel" ="取消";
48 |
49 | "CTFeedback.Camera" ="拍照";
50 |
51 | "CTFeedback.PhotoLibrary" ="从相册中选取";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "在此输入文字...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/Resources/zh-Hant.lproj/CTFeedbackLocalizable.strings:
--------------------------------------------------------------------------------
1 | /* Localizable.strings
2 | CTFeedbackDemo
3 |
4 | Created by Ryoichi Izumita on 2013/10/31.
5 | Copyright (c) 2013 CAPH. All rights reserved. */
6 |
7 | "Question" = "問題";
8 |
9 | "Request" = "需求";
10 |
11 | "Bug Report" = "程式錯誤回報";
12 |
13 | "Other" = "其他";
14 |
15 | "CTFeedback.Device" = "設備";
16 |
17 | "CTFeedback.iOS" = "iOS";
18 |
19 | "CTFeedback.Name" = "名字";
20 |
21 | "CTFeedback.Version" = "版本";
22 |
23 | "CTFeedback.Build" = "Build";
24 |
25 | "CTFeedback.DeviceInfo" = "設備資訊";
26 |
27 | "CTFeedback.AppInfo" = "軟體資訊";
28 |
29 | "CTFeedback.Feedback" = "反饋";
30 |
31 | "CTFeedback.Topic" = "主題";
32 |
33 | "CTFeedback.Topics" = "主題";
34 |
35 | "CTFeedback.Error" = "錯誤";
36 |
37 | "CTFeedback.Mail" = "郵件";
38 |
39 | "CTFeedback.MailConfigurationErrorMessage" ="您沒有一個有效的郵件賬戶";
40 |
41 | "CTFeedback.Dismiss" ="Dismiss";
42 |
43 | "CTFeedback.AdditionalInfo"="附加信息";
44 |
45 | "CTFeedback.AttachImageOrVideo" ="選擇反饋附件(圖片)";
46 |
47 | "CTFeedback.Cancel" ="取消";
48 |
49 | "CTFeedback.Camera" ="拍照";
50 |
51 | "CTFeedback.PhotoLibrary" ="從相冊中選取";
52 | "CTFeedback.UserDetail" = "User Detail";
53 | "CTFeedback.FeedbackGenerationErrorMessage" = "Feedback Generation Error";
54 | "CTFeedback.UnknownError" = "Unknown Error";
55 | "CTFeedback.Delete" = "Delete";
56 | "CTFeedback.requiredCameraAccess" = "Camera access is absolutely necessary to use this app";
57 | "CTFeedback.requiredLibraryAccess" = "Library access is absolutely necessary to use this app";
58 |
59 | "CTFeedback.BodyPlaceholder" = "在此輸入文字...";
60 |
--------------------------------------------------------------------------------
/CTFeedbackSwift/TopicsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopicsViewController.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/08.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class TopicsViewController: UITableViewController {
12 | let feedbackEditingService: FeedbackEditingServiceProtocol
13 | let topics: [TopicProtocol]
14 |
15 | init(service: FeedbackEditingServiceProtocol) {
16 | self.feedbackEditingService = service
17 | self.topics = self.feedbackEditingService.topics
18 | super.init(style: .plain)
19 | }
20 |
21 | required init?(coder aDecoder: NSCoder) { fatalError() }
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 |
26 | title = CTLocalizedString("CTFeedback.Topics")
27 | }
28 |
29 | override func didReceiveMemoryWarning() {
30 | super.didReceiveMemoryWarning()
31 | // Dispose of any resources that can be recreated.
32 | }
33 | }
34 |
35 | extension TopicsViewController {
36 | // MARK: - Table view data source
37 |
38 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
39 | // #warning Incomplete implementation, return the number of rows
40 | return topics.count
41 | }
42 |
43 | override func tableView(_ tableView: UITableView,
44 | cellForRowAt indexPath: IndexPath) -> UITableViewCell {
45 | let identifier = "Cell"
46 | let cell = tableView.dequeueReusableCell(withIdentifier: identifier)
47 | ?? UITableViewCell(style: .default, reuseIdentifier: identifier)
48 | let topic = topics[indexPath.row]
49 | cell.textLabel?.text = topic.localizedTitle
50 | return cell
51 | }
52 | }
53 |
54 | extension TopicsViewController {
55 | // MARK: - Table view delegate
56 |
57 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
58 | let topic = topics[indexPath.row]
59 | feedbackEditingService.update(selectedTopic: topic)
60 | dismiss(animated: true)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Bundle+ExtensionsTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class Bundle_ExtensionsTests:XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testPlatformNamesPlistPath() {
16 | XCTAssertNotNil(Bundle.platformNamesPlistPath)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/CellFactoryTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class CellFactoryTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testReuseIdentifier() {
16 | XCTAssertEqual(TestCellFactory.reuseIdentifier, "TestCellFactory")
17 | }
18 | }
19 |
20 | class AnyCellFactoryTests: XCTestCase {
21 | func testSuitable() {
22 | let concreteFactory = TestCellFactory.self
23 | let factory = AnyCellFactory(concreteFactory)
24 | XCTAssertTrue(factory.suitable(for: ""))
25 | }
26 |
27 | func testConfigure() {
28 | let concreteFactory = TestCellFactory.self
29 | let factory = AnyCellFactory(concreteFactory)
30 | let cell = UITableViewCell()
31 | let indexPath = IndexPath(row: 0, section: 0)
32 | _ = factory.configure(cell,
33 | with: "test",
34 | for: indexPath,
35 | eventHandler: "Handler")
36 | XCTAssertTrue(concreteFactory.cell === cell)
37 | XCTAssertEqual(concreteFactory.item, "test")
38 | XCTAssertEqual(concreteFactory.indexPath, indexPath)
39 | XCTAssertEqual(concreteFactory.eventHandler, "Handler")
40 | }
41 | }
42 |
43 | class UITableView_ExtensionsTests: XCTestCase {
44 | func testDequeueCell() {
45 | let concreteFactory = TestCellFactory.self
46 | let factory = AnyCellFactory(concreteFactory)
47 | let tableView = UITableView()
48 | tableView.register(with: factory)
49 | let indexPath = IndexPath(row: 0, section: 0)
50 | let cell: UITableViewCell = tableView.dequeueCell(to: "Item",
51 | from: [factory],
52 | for: indexPath,
53 | eventHandler: "EventHandler")
54 | XCTAssertTrue(concreteFactory.cell === cell)
55 | XCTAssertEqual(concreteFactory.item, "Item")
56 | XCTAssertEqual(concreteFactory.indexPath, indexPath)
57 | XCTAssertEqual(concreteFactory.eventHandler, "EventHandler")
58 | }
59 | }
60 |
61 | class TestCellFactory: CellFactoryProtocol {
62 | static var cell: UITableViewCell?
63 | static var item: String?
64 | static var indexPath: IndexPath?
65 | static var eventHandler: String?
66 |
67 | static func configure(_ cell: UITableViewCell,
68 | with item: String,
69 | for indexPath: IndexPath,
70 | eventHandler: String?) {
71 | self.cell = cell
72 | self.item = item
73 | self.indexPath = indexPath
74 | self.eventHandler = eventHandler
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/FeedbackEditing/FeedbackEditingServiceTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FeedbackEditingServiceTests.swift
3 | // CTFeedbackSwift
4 | //
5 | // Created by 和泉田 領一 on 2017/09/17.
6 | // Copyright © 2017 CAPH TECH. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import CTFeedbackSwift
11 |
12 | class FeedbackEditingServiceTests: XCTestCase {
13 | var itemsRepository: MockFeedbackEditingItemsRepository!
14 | var eventHandler: MockFeedbackEditingEventHandler!
15 | var service: FeedbackEditingService!
16 |
17 | override func setUp() {
18 | super.setUp()
19 |
20 | ready()
21 | }
22 |
23 | override func tearDown() {
24 | // Put teardown code here. This method is called after the invocation of each test method in the class.
25 | super.tearDown()
26 | }
27 |
28 | private func ready() {
29 | itemsRepository = MockFeedbackEditingItemsRepository()
30 | eventHandler = MockFeedbackEditingEventHandler()
31 | service = FeedbackEditingService(editingItemsRepository: itemsRepository,
32 | feedbackEditingEventHandler: eventHandler)
33 | }
34 |
35 | func testTopics() {
36 | itemsRepository.set(item: TopicItem(TopicItem.defaultTopics))
37 | let topics = service.topics
38 | XCTAssertEqual(topics.count, 4)
39 | }
40 |
41 | func testHasAttachedMediaWithNoMedia() {
42 | let item = AttachmentItem(isHidden: false)
43 | itemsRepository.set(item: item)
44 | XCTAssertFalse(service.hasAttachedMedia)
45 | }
46 |
47 | func testHasAttachedMediaWithImage() {
48 | var item = AttachmentItem(isHidden: false)
49 | item.media = .image(UIImage())
50 | itemsRepository.set(item: item)
51 | XCTAssertTrue(service.hasAttachedMedia)
52 | }
53 |
54 | func testUpdateUserEmailText() {
55 | itemsRepository.set(item: UserEmailItem(isHidden: false))
56 | XCTAssertNil(itemsRepository.item(of: UserEmailItem.self)?.email)
57 | service.update(userEmailText: "test")
58 | XCTAssertEqual(itemsRepository.item(of: UserEmailItem.self)?.email, "test")
59 | }
60 |
61 | func testUpdateBodyText() {
62 | itemsRepository.set(item: BodyItem(bodyText: .none))
63 | XCTAssertNil(itemsRepository.item(of: BodyItem.self)?.bodyText)
64 | service.update(bodyText: "test")
65 | XCTAssertEqual(itemsRepository.item(of: BodyItem.self)?.bodyText, "test")
66 | }
67 |
68 | func testUpdateSelectedTopic() {
69 | itemsRepository.set(item: TopicItem(TopicItem.defaultTopics))
70 | XCTAssertNil(eventHandler.invokedUpdatedParameters)
71 | service.update(selectedTopic: TopicItem.defaultTopics[1])
72 | XCTAssertEqual(eventHandler.invokedUpdatedParameters?.indexPath,
73 | IndexPath(row: 0, section: 0))
74 | }
75 |
76 | func testUpdateAttachmentMedia() {
77 | itemsRepository.set(item: AttachmentItem(isHidden: false))
78 | service.update(attachmentMedia: .image(UIImage()))
79 | XCTAssertEqual(eventHandler.invokedUpdatedParameters?.indexPath,
80 | IndexPath(row: 0, section: 0))
81 | }
82 |
83 | func testGenerateFeedback() {
84 | let dataSource = FeedbackItemsDataSource(topics: TopicItem.defaultTopics)
85 | service = FeedbackEditingService(editingItemsRepository: dataSource,
86 | feedbackEditingEventHandler: eventHandler)
87 | do {
88 | let configuration = FeedbackConfiguration(subject: "String",
89 | additionalDiagnosticContent: "additional",
90 | topics: TopicItem.defaultTopics,
91 | toRecipients: ["test@example.com"],
92 | ccRecipients: ["cc@example.com"],
93 | bccRecipients: ["bcc@example.com"])
94 | let feedback = try service.generateFeedback(configuration: configuration)
95 | XCTAssertEqual(feedback.subject, "String")
96 | XCTAssertEqual(feedback.to, ["test@example.com"])
97 | XCTAssertEqual(feedback.cc, ["cc@example.com"])
98 | XCTAssertEqual(feedback.bcc, ["bcc@example.com"])
99 | XCTAssertFalse(feedback.isHTML)
100 | } catch {
101 | XCTFail()
102 | }
103 | }
104 | }
105 |
106 | class MockFeedbackEditingItemsRepository: FeedbackEditingItemsRepositoryProtocol {
107 | var stubbedItems: [Any] = []
108 |
109 | func item
- (of type: Item.Type) -> Item? {
110 | return stubbedItems.filter { item in item is Item }.first as? Item
111 | }
112 |
113 | @discardableResult
114 | func set
- (item: Item) -> IndexPath? {
115 | if let index = stubbedItems.index(where: { stored in stored is Item }) {
116 | stubbedItems.remove(at: index)
117 | }
118 | stubbedItems.append(item)
119 | return IndexPath(row: 0, section: 0)
120 | }
121 | }
122 |
123 | class MockFeedbackEditingEventHandler: FeedbackEditingEventProtocol {
124 | var invokedUpdated = false
125 | var invokedUpdatedCount = 0
126 | var invokedUpdatedParameters: (indexPath: IndexPath, Void)?
127 | var invokedUpdatedParametersList = [(indexPath: IndexPath, Void)]()
128 |
129 | func updated(at indexPath: IndexPath) {
130 | invokedUpdated = true
131 | invokedUpdatedCount += 1
132 | invokedUpdatedParameters = (indexPath, ())
133 | invokedUpdatedParametersList.append((indexPath, ()))
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/FeedbackEditing/FeedbackGeneratorTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class FeedbackGeneratorTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testGenerateNoHTML() {
16 | let configuration = FeedbackConfiguration(subject: "Subject",
17 | additionalDiagnosticContent: "Additional",
18 | topics: TopicItem.defaultTopics,
19 | toRecipients: ["to@example.com"],
20 | ccRecipients: ["cc@example.com"],
21 | bccRecipients: ["bcc@example.com"],
22 | usesHTML: false)
23 | do {
24 | let feedback = try FeedbackGenerator.generate(configuration: configuration,
25 | repository: configuration.dataSource)
26 | XCTAssertEqual(feedback.subject, "Subject")
27 | XCTAssertTrue(feedback.body.contains("Additional"))
28 | XCTAssertFalse(feedback.isHTML)
29 | XCTAssertEqual(feedback.to, ["to@example.com"])
30 | XCTAssertEqual(feedback.cc, ["cc@example.com"])
31 | XCTAssertEqual(feedback.bcc, ["bcc@example.com"])
32 | } catch {
33 | XCTFail()
34 | }
35 | }
36 |
37 | func testGenerateNoHTMLWithHidesAppInfoSection() {
38 | let configuration = FeedbackConfiguration(subject: "Subject",
39 | additionalDiagnosticContent: "Additional",
40 | topics: TopicItem.defaultTopics,
41 | toRecipients: ["to@example.com"],
42 | ccRecipients: ["cc@example.com"],
43 | bccRecipients: ["bcc@example.com"],
44 | hidesAppInfoSection: true,
45 | usesHTML: false)
46 | do {
47 | let feedback = try FeedbackGenerator.generate(configuration: configuration,
48 | repository: configuration.dataSource)
49 | XCTAssertEqual(feedback.subject, "Subject")
50 | XCTAssertTrue(feedback.body.contains("Additional"))
51 | XCTAssertFalse(feedback.isHTML)
52 | XCTAssertEqual(feedback.to, ["to@example.com"])
53 | XCTAssertEqual(feedback.cc, ["cc@example.com"])
54 | XCTAssertEqual(feedback.bcc, ["bcc@example.com"])
55 | } catch {
56 | XCTFail()
57 | }
58 | }
59 |
60 | func testGenerateHTML() {
61 | let configuration = FeedbackConfiguration(subject: "Subject",
62 | additionalDiagnosticContent: "Additional",
63 | topics: TopicItem.defaultTopics,
64 | toRecipients: ["to@example.com"],
65 | ccRecipients: ["cc@example.com"],
66 | bccRecipients: ["bcc@example.com"],
67 | usesHTML: false)
68 | do {
69 | let feedback = try FeedbackGenerator.generate(configuration: configuration,
70 | repository: configuration.dataSource)
71 | XCTAssertEqual(feedback.subject, "Subject")
72 | XCTAssertTrue(feedback.body.contains("Additional"))
73 | XCTAssertFalse(feedback.isHTML)
74 | XCTAssertEqual(feedback.to, ["to@example.com"])
75 | XCTAssertEqual(feedback.cc, ["cc@example.com"])
76 | XCTAssertEqual(feedback.bcc, ["bcc@example.com"])
77 | } catch {
78 | XCTFail()
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/FeedbackItemsDataSourceTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class FeedbackItemsDataSourceTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testNumberOfSections() {
16 | let dataSource = FeedbackItemsDataSource(topics: TopicItem.defaultTopics,
17 | hidesUserEmailCell: true,
18 | hidesAttachmentCell: false,
19 | hidesAppInfoSection: true)
20 | XCTAssertEqual(dataSource.numberOfSections, 3)
21 | }
22 |
23 | func testSection() {
24 | let dataSource = FeedbackItemsDataSource(topics: TopicItem.defaultTopics,
25 | hidesUserEmailCell: false,
26 | hidesAttachmentCell: false,
27 | hidesAppInfoSection: true)
28 | XCTAssertEqual(dataSource.section(at: 0).title, "User Detail")
29 | }
30 |
31 | func testItem() {
32 | let dataSource = FeedbackItemsDataSource(topics: TopicItem.defaultTopics,
33 | hidesUserEmailCell: true,
34 | hidesAttachmentCell: false,
35 | hidesAppInfoSection: true)
36 | let item: TopicItem? = dataSource.item(of: TopicItem.self)
37 | XCTAssertNotNil(item)
38 | }
39 |
40 | func testSetItem() {
41 | let dataSource = FeedbackItemsDataSource(topics: TopicItem.defaultTopics,
42 | hidesUserEmailCell: true,
43 | hidesAttachmentCell: false,
44 | hidesAppInfoSection: true)
45 | guard var item = dataSource.item(of: BodyItem.self) else {
46 | XCTFail()
47 | return
48 | }
49 |
50 | item.bodyText = "body"
51 | let indexPath: IndexPath? = dataSource.set(item: item)
52 | XCTAssertNotNil(indexPath)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/FunctionsTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import MobileCoreServices
3 | @testable import CTFeedbackSwift
4 |
5 | class FunctionsTests: XCTestCase {
6 | override func setUp() {
7 | super.setUp()
8 | // Put setup code here. This method is called before the invocation of each test method in the class.
9 | }
10 |
11 | override func tearDown() {
12 | // Put teardown code here. This method is called after the invocation of each test method in the class.
13 | super.tearDown()
14 | }
15 |
16 | // func testGetURLFromImagePickerInfo() {
17 | // let url = URL(string: "https://example.com")
18 | // let validImageInfo: [String : Any] = [UIImagePickerControllerMediaType : kUTTypeImage,
19 | // UIImagePickerControllerImageURL : url]
20 | // XCTAssertEqual(getURLFromImagePickerInfo(validInfo), url)
21 | //
22 | // let validMovieInfo: [String : Any] = [UIImagePickerControllerMediaType : kUTTypeMovie,
23 | // UIImagePickerControllerMediaURL : url]
24 | // XCTAssertEqual(getURLFromImagePickerInfo(validMovieInfo), url)
25 | //
26 | // let invalidImageInfo: [String : Any] = [UIImagePickerControllerMediaType : kUTTypeImage,
27 | // UIImagePickerControllerMediaURL : url]
28 | // XCTAssertNil(getURLFromImagePickerInfo(invalidImageInfo))
29 | //
30 | // let invalidMovieInfo: [String : Any] = [UIImagePickerControllerMediaType : kUTTypeMovie,
31 | // UIImagePickerControllerImageURL : url]
32 | // XCTAssertNil(getURLFromImagePickerInfo(invalidMovieInfo))
33 | //
34 | // let invalidInfo: [String : Any] = ["invalid" : url]
35 | // XCTAssertNil(getURLFromImagePickerInfo(invalidInfo))
36 | // }
37 | }
38 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/AppBuild/AppBuildCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class AppBuildCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = AppBuildCell(style: .value1, reuseIdentifier: AppBuildCell.reuseIdentifier)
17 | let item = AppBuildItem(isHidden: false)
18 | AppBuildCell.configure(cell,
19 | with: item,
20 | for: IndexPath(row: 0, section: 0),
21 | eventHandler: .none)
22 | XCTAssertEqual(cell.textLabel?.text, "Build")
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/AppName/AppNameCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class AppNameCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = AppNameCell(style: .value1, reuseIdentifier: AppNameCell.reuseIdentifier)
17 | let item = AppNameItem(isHidden: false)
18 | AppNameCell.configure(cell,
19 | with: item,
20 | for: IndexPath(row: 0, section: 0),
21 | eventHandler: .none)
22 | XCTAssertEqual(cell.textLabel?.text, "Name")
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/AppVersion/AppVersionCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class AppVersionCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = AppVersionCell(style: .value1, reuseIdentifier: AppVersionCell.reuseIdentifier)
17 | let item = AppVersionItem(isHidden: false)
18 | AppVersionCell.configure(cell,
19 | with: item,
20 | for: IndexPath(row: 0, section: 0),
21 | eventHandler: .none)
22 | XCTAssertEqual(cell.textLabel?.text, "Version")
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/Attachment/AttachmentCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class AttachmentCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = AttachmentCell(style: .default,
17 | reuseIdentifier: AttachmentCell.reuseIdentifier)
18 | var item = AttachmentItem(isHidden: false)
19 | let image = UIImage(color: .red)!
20 | item.media = .image(image)
21 | let handler = MockAttachmentCellEventHandler()
22 | AttachmentCell.configure(cell,
23 | with: item,
24 | for: IndexPath(row: 0, section: 0),
25 | eventHandler: handler)
26 | XCTAssertTrue(cell.imageView?.image === image)
27 | }
28 |
29 | func testTapImageView() {
30 | let cell = AttachmentCell(style: .default,
31 | reuseIdentifier: AttachmentCell.reuseIdentifier)
32 | var item = AttachmentItem(isHidden: false)
33 | let image = UIImage(color: .red)!
34 | item.media = .image(image)
35 | let handler = MockAttachmentCellEventHandler()
36 | AttachmentCell.configure(cell,
37 | with: item,
38 | for: IndexPath(row: 0, section: 0),
39 | eventHandler: handler)
40 | cell.imageViewTapped(UITapGestureRecognizer())
41 | XCTAssertTrue(handler.invokedShowImage)
42 | }
43 | }
44 |
45 | class MockAttachmentCellEventHandler: AttachmentCellEventProtocol {
46 | var invokedShowImage = false
47 | var invokedShowImageCount = 0
48 | var invokedShowImageParameters: (item: AttachmentItem, Void)?
49 | var invokedShowImageParametersList = [(item: AttachmentItem, Void)]()
50 |
51 | func showImage(of item: AttachmentItem) {
52 | invokedShowImage = true
53 | invokedShowImageCount += 1
54 | invokedShowImageParameters = (item, ())
55 | invokedShowImageParametersList.append((item, ()))
56 | }
57 | }
58 |
59 | extension UIImage {
60 | convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) {
61 | let rect = CGRect(origin: .zero, size: size)
62 | UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
63 | color.setFill()
64 | UIRectFill(rect)
65 | let image = UIGraphicsGetImageFromCurrentImageContext()
66 | UIGraphicsEndImageContext()
67 |
68 | guard let cgImage = image?.cgImage else { return nil }
69 | self.init(cgImage: cgImage)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/Attachment/AttachmentItemTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class AttachmentItemTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testAttached() {
16 | var item = AttachmentItem(isHidden: false)
17 | XCTAssertFalse(item.attached)
18 |
19 | item.media = .image(UIImage(color: .red)!)
20 | XCTAssertTrue(item.attached)
21 |
22 | item.media = .video(UIImage(color: .red)!, URL(string: "https://example.com")!)
23 | XCTAssertTrue(item.attached)
24 | }
25 |
26 | func testImage() {
27 | var item = AttachmentItem(isHidden: false)
28 | XCTAssertNil(item.image)
29 |
30 | let image = UIImage(color: .red)!
31 | item.media = .image(image)
32 | XCTAssertNotNil(item.image)
33 | XCTAssertTrue(item.image === image)
34 |
35 | item.media = .video(image, URL(string: "https://example.com")!)
36 | XCTAssertNotNil(item.image)
37 | XCTAssertTrue(item.image === image)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/Body/BodyCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class BodyCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testEventHandling() {
16 | let cell = BodyCell(style: .default, reuseIdentifier: BodyCell.reuseIdentifier)
17 | let item = BodyItem(bodyText: "test")
18 | let handler = MockBodyCellEventHandler()
19 | let indexPath = IndexPath(row: 0, section: 0)
20 | BodyCell.configure(cell, with: item, for: indexPath, eventHandler: handler)
21 | cell.textViewDidChange(cell.textView)
22 | XCTAssertTrue(handler.invokedBodyCellHeightChanged)
23 | XCTAssertEqual(handler.invokedBodyTextDidChangeParameters?.text, "test")
24 | }
25 | }
26 |
27 | class MockBodyCellEventHandler: BodyCellEventProtocol {
28 | var invokedBodyCellHeightChanged = false
29 | var invokedBodyCellHeightChangedCount = 0
30 |
31 | func bodyCellHeightChanged() {
32 | invokedBodyCellHeightChanged = true
33 | invokedBodyCellHeightChangedCount += 1
34 | }
35 |
36 | var invokedBodyTextDidChange = false
37 | var invokedBodyTextDidChangeCount = 0
38 | var invokedBodyTextDidChangeParameters: (text: String?, Void)?
39 | var invokedBodyTextDidChangeParametersList = [(text: String?, Void)]()
40 |
41 | func bodyTextDidChange(_ text: String?) {
42 | invokedBodyTextDidChange = true
43 | invokedBodyTextDidChangeCount += 1
44 | invokedBodyTextDidChangeParameters = (text, ())
45 | invokedBodyTextDidChangeParametersList.append((text, ()))
46 | }
47 | }
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/DeviceName/DeviceNameCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class DeviceNameCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = DeviceNameCell(style: .default,
17 | reuseIdentifier: DeviceNameCell.reuseIdentifier)
18 | let item = DeviceNameItem()
19 | let indexPath = IndexPath(row: 0, section: 0)
20 | DeviceNameCell.configure(cell, with: item, for: indexPath, eventHandler: .none)
21 | XCTAssertEqual(cell.textLabel?.text, "Device")
22 |
23 | switch cell.detailTextLabel?.text {
24 | case "Simulator", "arm64", "x86_64":
25 | break
26 | default:
27 | XCTFail(cell.detailTextLabel?.text ?? "")
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/DeviceName/DeviceNameItemTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class DeviceNameItemTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testDeviceName() {
16 | let item = DeviceNameItem()
17 | switch item.deviceName {
18 | case "Simulator", "arm64", "x86_64":
19 | break
20 | default:
21 | XCTFail(item.deviceName)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/SystemVersion/SystemVersionCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class SystemVersionCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = SystemVersionCell(style: .default,
17 | reuseIdentifier: SystemVersionCell.reuseIdentifier)
18 | let item = SystemVersionItem()
19 | let indexPath = IndexPath(row: 0, section: 0)
20 | SystemVersionCell.configure(cell, with: item, for: indexPath, eventHandler: .none)
21 | XCTAssertEqual(cell.textLabel?.text, "iOS")
22 | XCTAssertEqual(cell.detailTextLabel?.text, item.version)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/SystemVersion/SystemVersionItemTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class SystemVersionItemTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testVersion() {
16 | let item: SystemVersionItem = SystemVersionItem()
17 | XCTAssertEqual(item.version, UIDevice.current.systemVersion)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/Topic/TopicCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class TopicCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testConfigure() {
16 | let cell = TopicCell(style: .default, reuseIdentifier: TopicCell.reuseIdentifier)
17 | let item = TopicItem(TopicItem.defaultTopics)
18 | let indexPath = IndexPath(row: 0, section: 0)
19 | TopicCell.configure(cell, with: item, for: indexPath, eventHandler: .none)
20 | XCTAssertEqual(cell.textLabel?.text, "Topic")
21 | XCTAssertEqual(cell.detailTextLabel?.text, item.selected?.localizedTitle)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/Topic/TopicItemTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class TopicItemTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testSelected() {
16 | var item = TopicItem([])
17 | let topics = TopicItem.defaultTopics
18 |
19 | XCTAssertNil(item.selected)
20 |
21 | item.topics = topics
22 | XCTAssertEqual(item.selected?.title, topics.first?.title)
23 |
24 | item.selected = topics[1]
25 | XCTAssertEqual(item.selected?.title, topics[1].title)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/CTFeedbackSwiftTests/Items/UserEmail/UserEmailCellTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import CTFeedbackSwift
3 |
4 | class UserEmailCellTests: XCTestCase {
5 | override func setUp() {
6 | super.setUp()
7 | // Put setup code here. This method is called before the invocation of each test method in the class.
8 | }
9 |
10 | override func tearDown() {
11 | // Put teardown code here. This method is called after the invocation of each test method in the class.
12 | super.tearDown()
13 | }
14 |
15 | func testHandleTextDidChange() {
16 | let cell = UserEmailCell(style: .default,
17 | reuseIdentifier: UserEmailCell.reuseIdentifier)
18 | let item = UserEmailItem(isHidden: false)
19 | let indexPath = IndexPath(row: 0, section: 0)
20 | let handler = MockUserEmailCellEventHandler()
21 | UserEmailCell.configure(cell, with: item, for: indexPath, eventHandler: handler)
22 | cell.textField.text = "test"
23 | _ = cell.textField(cell.textField,
24 | shouldChangeCharactersIn: NSRange(location: 0, length: 4),
25 | replacementString: "")
26 | XCTAssertEqual(handler.invokedUserEmailTextDidChangeParameters?.text, "test")
27 | }
28 | }
29 |
30 | class MockUserEmailCellEventHandler: UserEmailCellEventProtocol {
31 | var invokedUserEmailTextDidChange = false
32 | var invokedUserEmailTextDidChangeCount = 0
33 | var invokedUserEmailTextDidChangeParameters: (text: String?, Void)?
34 | var invokedUserEmailTextDidChangeParametersList = [(text: String?, Void)]()
35 |
36 | func userEmailTextDidChange(_ text: String?) {
37 | invokedUserEmailTextDidChange = true
38 | invokedUserEmailTextDidChangeCount += 1
39 | invokedUserEmailTextDidChangeParameters = (text, ())
40 | invokedUserEmailTextDidChangeParametersList.append((text, ()))
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Ryoichi Izumita
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 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "CTFeedbackSwift",
7 | defaultLocalization: "en",
8 | platforms: [
9 | // Some platform where run yours library
10 | .iOS(.v10), .tvOS(.v10), .watchOS(.v4)
11 | ],
12 | products: [
13 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
14 | .library(name: "CTFeedbackSwift", targets: ["CTFeedbackSwift"])
15 | ],
16 | targets: [
17 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
18 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
19 | .target(name: "CTFeedbackSwift", path: "CTFeedbackSwift")
20 | ]
21 | )
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CTFeedbackSwift
2 | CTFeedbackSwift is a framework to compose a feedback for iOS 9.0+
3 |
4 | [CTFeedback](https://github.com/rizumita/CTFeedback) is written in Objective-C. CTFeedbackSwift is rebooted with Swift.
5 |
6 | 
7 |
8 | ## Install
9 |
10 | CTFeedbackSwift is now support Carthage.
11 |
12 | Cartfile
13 |
14 | ```
15 | github "rizumita/CTFeedbackSwift"
16 | ```
17 |
18 | And do along Carthage documents.
19 |
20 | ## How to use
21 |
22 | ```Swift
23 | let configuration = FeedbackConfiguration(toRecipients: ["test@example.com"], usesHTML: true)
24 | let controller = FeedbackViewController(configuration: configuration)
25 | navigationController?.pushViewController(controller, animated: true)
26 | ```
27 |
28 | ## License
29 |
30 | MIT License
31 |
--------------------------------------------------------------------------------