├── README.md
├── ShareExtension
├── Base.lproj
│ └── MainInterface.storyboard
├── DictionaryCell.swift
├── ImageCell.swift
├── Info.plist
├── ShareViewController.swift
├── ShareViewModel.swift
├── String+Utility.swift
├── TextCell.swift
└── UITableViewModel.swift
├── ShareInspector.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── ShareInspector
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ ├── Icon-App-83.5x83.5@2x.png
│ │ └── Icon-App-iTunes.png
│ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
└── ViewController.swift
└── screenshots
├── Device-PhotosApp-LivePhoto.png
├── Device-Safari-WebPage.png
├── Screenshot-PhotosApp-LivePhoto.png
└── Screenshot-Safari-WebPage.png
/README.md:
--------------------------------------------------------------------------------
1 | # Share Inspector
2 |
3 | An iOS app that provides a [share extension](https://developer.apple.com/design/human-interface-guidelines/ios/extensions/sharing-and-actions/) for inspecting the data the host app provides via the share sheet.
4 |
5 | Made by Cocologics, makers of [ProCamera](https://www.procamera-app.com).
6 |
7 | ## Usage
8 |
9 | 1. Download or clone the repository.
10 | 2. Open the project in Xcode and run it on the simulator or an iOS device.
11 | 3. Open the share sheet in any app and pick Share Inspector in the share sheet.
12 |
13 | ## Requirements
14 |
15 | iOS 12.0 or later.
16 | No dependencies.
17 |
18 | ## Screenshots
19 |
20 | ### Receiving a Live Photo shared from Photos
21 |
22 |
23 |
24 | ### Receiving a web page shared from Safari
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ShareExtension/Base.lproj/MainInterface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
39 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
80 |
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 |
128 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
--------------------------------------------------------------------------------
/ShareExtension/DictionaryCell.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A UITableViewCell that displays a label and the contents of a dictionary.
4 | /// The dictionary keys must be strings.
5 | final class DictionaryCell: UITableViewCell, ReusableCell, ResizingCell {
6 | static let reuseIdentifier = "DictionaryCell"
7 | static let shouldRegisterCellClassWithTableView = false
8 |
9 | @IBOutlet var label: UILabel!
10 | /// The stack view in which the elements of the dictionary are displayed
11 | @IBOutlet var elementsStack: UIStackView!
12 | @IBOutlet var expandButton: UIButton!
13 |
14 | var viewModel: LabeledValue<[String: Any]?>? {
15 | didSet { updateUI() }
16 | }
17 |
18 | var isExpanded: Bool = false {
19 | didSet {
20 | updateUI()
21 | cellDidResize?()
22 | }
23 | }
24 |
25 | var cellDidResize: (() -> ())?
26 |
27 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
28 | super.init(style: style, reuseIdentifier: reuseIdentifier)
29 | updateUI()
30 | }
31 |
32 | required init?(coder: NSCoder) {
33 | super.init(coder: coder)
34 | }
35 |
36 | override func awakeFromNib() {
37 | super.awakeFromNib()
38 | label.preferredMaxLayoutWidth = CGFloat.greatestFiniteMagnitude
39 | expandButton.titleLabel?.adjustsFontForContentSizeCategory = true
40 | updateUI()
41 | }
42 |
43 | override func prepareForReuse() {
44 | super.prepareForReuse()
45 | cellDidResize = nil
46 | }
47 |
48 | @IBAction func toggleExpandCollapse() {
49 | isExpanded.toggle()
50 | }
51 |
52 | private func updateUI() {
53 | // Remove all existing views in elementsStack
54 | for subview in elementsStack.arrangedSubviews {
55 | subview.removeFromSuperview()
56 | }
57 |
58 | // Rebuild elementsStack from current state
59 | if let viewModel = viewModel {
60 | label.text = viewModel.label
61 | expandButton.setTitle(isExpanded ? "Collapse" : "Expand", for: .normal)
62 |
63 | switch (viewModel.value, isExpanded) {
64 | case (let dict?, true):
65 | expandButton.isHidden = false
66 | let subStacks = dict
67 | .sorted(by: { $0.key < $1.key })
68 | .map(DictionaryCell.makeSubStack(element:))
69 | subStacks.forEach(elementsStack.addArrangedSubview)
70 | case (let dict?, false):
71 | expandButton.isHidden = false
72 | let infoLabel = UILabel()
73 | infoLabel.font = .preferredFont(forTextStyle: .body)
74 | infoLabel.text = "\(dict.count) key/value \(dict.count == 1 ? "pair" : "pairs")"
75 | elementsStack.addArrangedSubview(infoLabel)
76 | case (nil, _):
77 | expandButton.isHidden = true
78 | let nilLabel = UILabel()
79 | nilLabel.font = .preferredFont(forTextStyle: .body)
80 | nilLabel.text = "(nil)"
81 | elementsStack.addArrangedSubview(nilLabel)
82 | }
83 | } else {
84 | label.text = nil
85 | expandButton.isHidden = true
86 | }
87 | }
88 |
89 | private class func makeSubStack(element: (key: String, value: Any)) -> UIStackView {
90 | let (key, value) = element
91 | let keyLabel = UILabel()
92 | keyLabel.font = .preferredFont(forTextStyle: .body)
93 | keyLabel.numberOfLines = 0
94 | keyLabel.text = key
95 |
96 | let valueLabel = UILabel()
97 | valueLabel.font = .preferredFont(forTextStyle: .body)
98 | valueLabel.numberOfLines = 0
99 | valueLabel.text = String(describing: value)
100 |
101 | let stack = UIStackView(arrangedSubviews: [
102 | keyLabel,
103 | valueLabel
104 | ])
105 | stack.axis = .vertical
106 | stack.spacing = 4
107 | return stack
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/ShareExtension/ImageCell.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A UITableViewCell that displays a label and an image.
4 | /// The image is loaded dynamically by the cell.
5 | final class ImageCell: UITableViewCell, ReusableCell {
6 | static let reuseIdentifier = "ImageCell"
7 | static let shouldRegisterCellClassWithTableView = false
8 |
9 | static let smallImageSize: CGFloat = 50
10 | static let largeImageSize: CGFloat = 120
11 |
12 | @IBOutlet var label: UILabel!
13 | /// Displays meta information such as image size or error messages if loading fails.
14 | @IBOutlet var infoLabel: UILabel!
15 | @IBOutlet var thumbnailView: UIImageView!
16 | @IBOutlet var thumbnailViewHeightConstraint: NSLayoutConstraint!
17 | @IBOutlet var thumbnailViewWidthConstraint: NSLayoutConstraint!
18 |
19 | var viewModel: LabeledValue? {
20 | didSet {
21 | updateUI()
22 | viewModel?.value(CGSize(width: ImageCell.largeImageSize, height: 2 * ImageCell.largeImageSize)) { result in
23 | // TODO: Handle cell reuse. Do nothing if the cell has been reused in the meantime.
24 | DispatchQueue.main.async {
25 | self.loadedImage = result
26 | }
27 | }
28 | }
29 | }
30 |
31 | private var loadedImage: Result? {
32 | didSet { updateUI() }
33 | }
34 |
35 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
36 | super.init(style: style, reuseIdentifier: reuseIdentifier)
37 | updateUI()
38 | }
39 |
40 | required init?(coder: NSCoder) {
41 | super.init(coder: coder)
42 | }
43 |
44 | override func awakeFromNib() {
45 | super.awakeFromNib()
46 | label.preferredMaxLayoutWidth = CGFloat.greatestFiniteMagnitude
47 | infoLabel.preferredMaxLayoutWidth = CGFloat.greatestFiniteMagnitude
48 | updateUI()
49 | }
50 |
51 | private func updateUI() {
52 | if let viewModel = viewModel {
53 | label.text = viewModel.label
54 | switch loadedImage {
55 | case nil:
56 | thumbnailView.image = nil
57 | thumbnailViewHeightConstraint.constant = ImageCell.smallImageSize
58 | thumbnailViewWidthConstraint.constant = ImageCell.smallImageSize
59 | infoLabel.text = nil
60 | case .success(let image)?:
61 | let aspectRatio = image.size.width / image.size.height
62 | let isValidAspectRatio = aspectRatio.isFinite && aspectRatio > 0
63 | thumbnailView.image = image
64 | thumbnailViewHeightConstraint.constant = ImageCell.largeImageSize
65 | thumbnailViewWidthConstraint.constant = isValidAspectRatio ? aspectRatio * ImageCell.largeImageSize : ImageCell.largeImageSize
66 | infoLabel.text = "\(image.size.width) × \(image.size.height) pt"
67 | case .failure(let error):
68 | thumbnailView.image = nil
69 | if let error = error as? ShareInspectorError, error.code == .noPreviewImageProvided {
70 | thumbnailViewHeightConstraint.constant = ImageCell.smallImageSize
71 | thumbnailViewWidthConstraint.constant = ImageCell.smallImageSize
72 | infoLabel.text = "(none)"
73 | } else {
74 | thumbnailViewHeightConstraint.constant = ImageCell.largeImageSize
75 | thumbnailViewWidthConstraint.constant = ImageCell.largeImageSize
76 | infoLabel.text = "Loading error: \(error.localizedDescription)"
77 | }
78 | }
79 | } else {
80 | label.text = nil
81 | infoLabel.text = nil
82 | thumbnailView.image = nil
83 | thumbnailViewHeightConstraint.constant = ImageCell.smallImageSize
84 | thumbnailViewWidthConstraint.constant = ImageCell.smallImageSize
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/ShareExtension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Share Inspector
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | XPC!
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | NSExtensionActivationRule
28 | TRUEPREDICATE
29 |
30 | NSExtensionMainStoryboard
31 | MainInterface
32 | NSExtensionPointIdentifier
33 | com.apple.share-services
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/ShareExtension/ShareViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | final class ShareViewController: UIViewController {
4 | var viewModel = ShareViewModel(extensionContext: nil) {
5 | didSet {
6 | guard isViewLoaded else { return }
7 | tableView?.reloadData()
8 | }
9 | }
10 |
11 | @IBOutlet var tableView: UITableView?
12 | private var reuseIdentifiers: Set = []
13 |
14 | override func loadView() {
15 | super.loadView()
16 | tableView!.rowHeight = UITableView.automaticDimension
17 | viewModel = ShareViewModel(extensionContext: extensionContext)
18 | }
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | // Set our tint color on the parent navigation controller.
23 | // We do this from here because this is our entry point for the Share Extension.
24 | navigationController?.view.tintColor = .systemGreen
25 | }
26 |
27 | @IBAction func done(_ sender: UIBarButtonItem) {
28 | extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
29 | }
30 | }
31 |
32 | extension ShareViewController: UITableViewDataSource {
33 | func numberOfSections(in tableView: UITableView) -> Int {
34 | return viewModel.sections.count
35 | }
36 |
37 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
38 | return viewModel.sections[section].cells.count
39 | }
40 |
41 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
42 | return viewModel.sections[section].sectionTitle
43 | }
44 |
45 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
46 | let section = viewModel.sections[indexPath.section]
47 | let descriptor = section.cells[indexPath.row]
48 |
49 | // Register cell types lazily
50 | if descriptor.shouldRegisterCellClassWithTableView && !reuseIdentifiers.contains(descriptor.reuseIdentifier) {
51 | tableView.register(descriptor.cellClass, forCellReuseIdentifier: descriptor.reuseIdentifier)
52 | reuseIdentifiers.insert(descriptor.reuseIdentifier)
53 | }
54 |
55 | let cell = tableView.dequeueReusableCell(withIdentifier: descriptor.reuseIdentifier, for: indexPath)
56 | if let resizingCell = cell as? ResizingCell {
57 | resizingCell.cellDidResize = { [weak tableView] in
58 | guard let tableView = tableView else { return }
59 | tableView.beginUpdates()
60 | tableView.endUpdates()
61 | }
62 | }
63 | descriptor.configure(cell)
64 | return cell
65 | }
66 | }
67 |
68 | extension ShareViewController: UITableViewDelegate {
69 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
70 | // Hack: Reload the cell in order to resize it (to fix autolayout issues)
71 | tableView.beginUpdates()
72 | tableView.reloadRows(at: [indexPath], with: .automatic)
73 | tableView.endUpdates()
74 | tableView.deselectRow(at: indexPath, animated: true)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ShareExtension/ShareViewModel.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | typealias LoadImageHandler = (_ preferredSize: CGSize, _ callback: @escaping (Result) -> ()) -> ()
5 |
6 | struct LabeledValue {
7 | var label: String
8 | var value: Value
9 | }
10 |
11 | enum Text {
12 | case plain(String)
13 | case rich(NSAttributedString)
14 | }
15 |
16 | extension LabeledValue where Value == Text {
17 | var cellDescriptor: CellDescriptor {
18 | return CellDescriptor { (cell: TextCell) in
19 | cell.viewModel = self
20 | }
21 | }
22 | }
23 |
24 | extension LabeledValue where Value == [String: Any]? {
25 | var cellDescriptor: CellDescriptor {
26 | return CellDescriptor { (cell: DictionaryCell) in
27 | cell.viewModel = self
28 | }
29 | }
30 | }
31 |
32 | extension LabeledValue where Value == LoadImageHandler {
33 | var cellDescriptor: CellDescriptor {
34 | return CellDescriptor { (cell: ImageCell) in
35 | cell.viewModel = self
36 | }
37 | }
38 | }
39 |
40 | /// View model for ShareViewController
41 | struct ShareViewModel {
42 | var sections: [Section]
43 |
44 | init(extensionContext: NSExtensionContext?) {
45 | self.sections = ShareViewModel.makeSections(extensionContext: extensionContext)
46 | }
47 |
48 | private static func makeSections(extensionContext: NSExtensionContext?) -> [Section] {
49 | var sections: [Section] = []
50 |
51 | // Overview section
52 | guard let extensionContext = extensionContext else {
53 | sections.append(Notice(label: "Error", message: "Share extension received no NSExtensionContext."))
54 | return sections
55 | }
56 | sections.append(Overview(sharedItemsCount: extensionContext.inputItems.count))
57 |
58 | guard let sharedItems = extensionContext.inputItems as? [NSExtensionItem] else {
59 | sections.append(Notice(label: "Error", message: "Error: Elements in extensionContext.inputItems are not of type NSExtensionItem."))
60 | return sections
61 | }
62 |
63 | // Sections for the shared items
64 | // For each shared item, we create:
65 | // - An overview section with the data provided by NSExtensionItem.
66 | // - One attachment section per attachment (NSItemProvider) of the shared item.
67 | for (itemNumber, sharedItem) in zip(1..., sharedItems) {
68 | let attachments = sharedItem.attachments ?? []
69 |
70 | // Shared item overview
71 | sections.append(SharedItemOverview(
72 | itemNumber: itemNumber,
73 | attributedTitle: sharedItem.attributedTitle,
74 | attributedContentText: sharedItem.attributedContentText,
75 | attachmentCount: attachments.count,
76 | userInfo: sharedItem.userInfo as? [String: Any]))
77 |
78 | // Attachments
79 | for (attachmentNumber, itemProvider) in zip(1..., attachments) {
80 | sections.append(Attachment(
81 | itemNumber: itemNumber,
82 | attachmentNumber: attachmentNumber,
83 | attachmentCount: attachments.count,
84 | itemProvider: itemProvider))
85 | }
86 | }
87 |
88 | return sections
89 | }
90 | }
91 |
92 | extension ShareViewModel {
93 | /// A section for displaying a piece of text (e.g. an error message)
94 | struct Notice: Section {
95 | var label: String
96 | var message: String
97 |
98 | var sectionTitle: String? { return nil }
99 | var cells: [CellDescriptor] {
100 | return [
101 | LabeledValue(label: label, value: Text.plain(message)).cellDescriptor
102 | ]
103 | }
104 | }
105 |
106 | struct Overview: Section {
107 | var sharedItemsCount: Int
108 |
109 | var sectionTitle: String? { return nil }
110 | var cells: [CellDescriptor] {
111 | return [
112 | LabeledValue(
113 | label: "Number of shared items",
114 | value: Text.plain("\(sharedItemsCount)")).cellDescriptor,
115 | ]
116 | }
117 | }
118 |
119 | struct SharedItemOverview: Section {
120 | var itemNumber: Int
121 | var attributedTitle: NSAttributedString?
122 | var attributedContentText: NSAttributedString?
123 | var attachmentCount: Int
124 | var userInfo: [String: Any]?
125 |
126 | var sectionTitle: String? {
127 | return "Item \(itemNumber) (NSExtensionItem)"
128 | }
129 |
130 | var cells: [CellDescriptor] {
131 | return [
132 | LabeledValue(
133 | label: "attributedTitle",
134 | value: attributedTitle.map(Text.rich) ?? Text.plain("(nil)")).cellDescriptor,
135 | LabeledValue(
136 | label: "attributedContentText",
137 | value: attributedContentText.map(Text.rich) ?? Text.plain("(nil)")).cellDescriptor,
138 | LabeledValue(
139 | label: "Number of attachments",
140 | value: Text.plain("\(attachmentCount)")).cellDescriptor,
141 | LabeledValue(
142 | label: "userInfo",
143 | value: userInfo).cellDescriptor,
144 | ]
145 | }
146 | }
147 |
148 | struct Attachment: Section {
149 | var itemNumber: Int
150 | var attachmentNumber: Int
151 | var attachmentCount: Int
152 | var registeredTypeIdentifiers: [String]
153 | var suggestedName: String?
154 | var loadPreviewImage: LoadImageHandler
155 |
156 | init(itemNumber: Int, attachmentNumber: Int, attachmentCount: Int, itemProvider: NSItemProvider) {
157 | self.itemNumber = itemNumber
158 | self.attachmentNumber = attachmentNumber
159 | self.attachmentCount = attachmentCount
160 | self.registeredTypeIdentifiers = itemProvider.registeredTypeIdentifiers
161 | self.suggestedName = itemProvider.suggestedName
162 | self.loadPreviewImage = Attachment.makeLoadPreviewImageHandler(itemProvider: itemProvider)
163 | }
164 |
165 | var sectionTitle: String? {
166 | return "Item \(itemNumber) · Attachment \(attachmentNumber) of \(attachmentCount) (NSItemProvider)"
167 | }
168 |
169 | var cells: [CellDescriptor] {
170 | let bullet = registeredTypeIdentifiers.count == 1 ? "" : "• "
171 | let typeIdentifiersList = registeredTypeIdentifiers
172 | .map { line in "\(bullet)\(line)" }
173 | .joined(separator: "\n")
174 | return [
175 | LabeledValue(
176 | label: "Preview Image",
177 | value: loadPreviewImage).cellDescriptor,
178 | LabeledValue(
179 | label: "registeredTypeIdentifiers",
180 | value: Text.plain(typeIdentifiersList)).cellDescriptor,
181 | LabeledValue(
182 | label: "suggestedName",
183 | value: Text.plain(suggestedName ?? "(nil)")).cellDescriptor,
184 | ]
185 | }
186 |
187 | private static func makeLoadPreviewImageHandler(itemProvider: NSItemProvider) -> LoadImageHandler {
188 | let loadPreviewImage: LoadImageHandler = { preferredSize, callback in
189 | let options: [AnyHashable: Any] = [
190 | NSItemProviderPreferredImageSizeKey: NSValue(cgSize: preferredSize)
191 | ]
192 | let completionHandler: (NSSecureCoding?, Error?) -> () = { result, error in
193 | switch (result, error) {
194 | case (let image as UIImage, _):
195 | callback(.success(image))
196 | case (_?, _):
197 | callback(.failure(error ?? ShareInspectorError.unableToCastToUIImage(actualType: "\(type(of: result))")))
198 | case (nil, let error?):
199 | callback(.failure(error))
200 | case (nil, nil):
201 | callback(.failure(ShareInspectorError.noPreviewImageProvided))
202 | }
203 | }
204 | itemProvider.loadPreviewImage(options: options, completionHandler: completionHandler)
205 | }
206 | return loadPreviewImage
207 | }
208 | }
209 | }
210 |
211 | struct ShareInspectorError: Error {
212 | enum Code {
213 | case unableToCastToUIImage
214 | case noPreviewImageProvided
215 | }
216 |
217 | var code: Code
218 | var message: String
219 |
220 | static func unableToCastToUIImage(actualType: String) -> ShareInspectorError {
221 | return ShareInspectorError(code: .unableToCastToUIImage, message: "Expected preview image to be UIImage, host app provided \(actualType)")
222 | }
223 | static let noPreviewImageProvided = ShareInspectorError(code: .noPreviewImageProvided, message: "Host app provided no preview image")
224 | }
225 |
--------------------------------------------------------------------------------
/ShareExtension/String+Utility.swift:
--------------------------------------------------------------------------------
1 | extension StringProtocol {
2 | var lineCount: Int {
3 | guard !isEmpty else {
4 | return 0
5 | }
6 | return reduce(1) { lineCount, character in
7 | lineCount + (character.isNewline ? 1 : 0)
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareExtension/TextCell.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A UITableViewCell that displays a label and a string value.
4 | /// The value can be plain (`String`) or rich text (`NSAttributedString)`.
5 | final class TextCell: UITableViewCell, ReusableCell {
6 | static let reuseIdentifier = "TextCell"
7 | static let shouldRegisterCellClassWithTableView = false
8 |
9 | @IBOutlet var contentStack: UIStackView!
10 | @IBOutlet var label: UILabel!
11 | @IBOutlet var valueLabel: UILabel!
12 |
13 | var viewModel: LabeledValue? {
14 | didSet { updateUI() }
15 | }
16 |
17 | override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
18 | super.init(style: style, reuseIdentifier: reuseIdentifier)
19 | updateUI()
20 | }
21 |
22 | required init?(coder: NSCoder) {
23 | super.init(coder: coder)
24 | }
25 |
26 | override func awakeFromNib() {
27 | super.awakeFromNib()
28 | label.preferredMaxLayoutWidth = CGFloat.greatestFiniteMagnitude
29 | valueLabel.preferredMaxLayoutWidth = CGFloat.greatestFiniteMagnitude
30 | updateUI()
31 | }
32 |
33 | override func layoutSubviews() {
34 | super.layoutSubviews()
35 |
36 | let layoutAxis = preferredLayoutAxis
37 | switch layoutAxis {
38 | case .horizontal where contentStack.axis != .horizontal:
39 | contentStack.axis = .horizontal
40 | contentStack.distribution = .fill
41 | contentStack.alignment = .firstBaseline
42 | valueLabel.textAlignment = .right
43 | case .vertical where contentStack.axis != .vertical:
44 | contentStack.axis = .vertical
45 | contentStack.distribution = .fill
46 | contentStack.alignment = .fill
47 | valueLabel.textAlignment = .left
48 | default:
49 | break
50 | }
51 | }
52 |
53 | private func updateUI() {
54 | if let viewModel = viewModel {
55 | label.text = viewModel.label
56 | switch viewModel.value {
57 | case .plain(let text): valueLabel.text = text
58 | case .rich(let attributedText): valueLabel.attributedText = attributedText
59 | }
60 | } else {
61 | label.text = nil
62 | valueLabel.text = nil
63 | }
64 | }
65 |
66 | private var preferredLayoutAxis: NSLayoutConstraint.Axis {
67 | let labelWidth = label.intrinsicContentSize.width
68 | let valueWidth = valueLabel.intrinsicContentSize.width
69 | let hasValidIntrinsicWidth = labelWidth != UIView.noIntrinsicMetric && valueWidth != UIView.noIntrinsicMetric
70 | guard hasValidIntrinsicWidth else {
71 | return .vertical
72 | }
73 |
74 | let valueHasLineBreaks = (valueLabel.text ?? "").lineCount > 1
75 | guard !valueHasLineBreaks else {
76 | return .vertical
77 | }
78 |
79 | let requiredWidthIfHorizontal = labelWidth + contentStack.spacing + valueWidth
80 | let hasEnoughHorizontalSpace = contentStack.bounds.width >= requiredWidthIfHorizontal
81 | return hasEnoughHorizontalSpace ? .horizontal : .vertical
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/ShareExtension/UITableViewModel.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A section in a table view.
4 | protocol Section {
5 | var sectionTitle: String? { get }
6 | var cells: [CellDescriptor] { get }
7 | }
8 |
9 | /// A recipe for creating a specific table view cell.
10 | ///
11 | /// Inspired by: [objc.io, Generic Table View Controllers](https://talk.objc.io/episodes/S01E26-generic-table-view-controllers-part-2)
12 | struct CellDescriptor {
13 | let cellClass: UITableViewCell.Type
14 | let reuseIdentifier: String
15 | let shouldRegisterCellClassWithTableView: Bool
16 | // Type-erased in order to use multiple concrete CellDescriptor values
17 | // in a single table view.
18 | let configure: (UITableViewCell) -> ()
19 |
20 | init(configure: @escaping (Cell) -> ()) {
21 | self.cellClass = Cell.self
22 | self.reuseIdentifier = Cell.self.reuseIdentifier
23 | self.shouldRegisterCellClassWithTableView = Cell.self.shouldRegisterCellClassWithTableView
24 | self.configure = { cell in
25 | configure(cell as! Cell)
26 | }
27 | }
28 | }
29 |
30 | protocol ReusableCell {
31 | static var reuseIdentifier: String { get }
32 | /// Should be false if the table view doesn't have to register the cell class.
33 | /// For example, this is the case for cells that are created as prototype cells
34 | /// of the table view in a storyboard.
35 | /// Should be true for cells that are created in code.
36 | static var shouldRegisterCellClassWithTableView: Bool { get }
37 | }
38 |
39 | protocol ResizingCell: UITableViewCell {
40 | var cellDidResize: (() -> ())? { get set }
41 | }
42 |
--------------------------------------------------------------------------------
/ShareInspector.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 5D0A79E122E9F02D007C84B1 /* DictionaryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0A79E022E9F02D007C84B1 /* DictionaryCell.swift */; };
11 | 5D0A79E322EA28A9007C84B1 /* ImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0A79E222EA28A9007C84B1 /* ImageCell.swift */; };
12 | 5D0A79E522EAE522007C84B1 /* String+Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0A79E422EAE522007C84B1 /* String+Utility.swift */; };
13 | 5D74E33B22E8571100EFF3AA /* ShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D74E33A22E8571100EFF3AA /* ShareViewModel.swift */; };
14 | 5D74E34222E8D60300EFF3AA /* TextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D74E34122E8D60300EFF3AA /* TextCell.swift */; };
15 | 5D74E34422E8D95300EFF3AA /* UITableViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D74E34322E8D95300EFF3AA /* UITableViewModel.swift */; };
16 | 5DDBB6C722E5C89F00BEA421 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DDBB6C622E5C89F00BEA421 /* AppDelegate.swift */; };
17 | 5DDBB6C922E5C89F00BEA421 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DDBB6C822E5C89F00BEA421 /* ViewController.swift */; };
18 | 5DDBB6CC22E5C89F00BEA421 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5DDBB6CA22E5C89F00BEA421 /* Main.storyboard */; };
19 | 5DDBB6CE22E5C8A000BEA421 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5DDBB6CD22E5C8A000BEA421 /* Assets.xcassets */; };
20 | 5DDBB6D122E5C8A000BEA421 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5DDBB6CF22E5C8A000BEA421 /* LaunchScreen.storyboard */; };
21 | 5DDBB6F222E5CA6400BEA421 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DDBB6F122E5CA6400BEA421 /* ShareViewController.swift */; };
22 | 5DDBB6F522E5CA6400BEA421 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5DDBB6F322E5CA6400BEA421 /* MainInterface.storyboard */; };
23 | 5DDBB6F922E5CA6400BEA421 /* ShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5DDBB6EF22E5CA6400BEA421 /* ShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
24 | /* End PBXBuildFile section */
25 |
26 | /* Begin PBXContainerItemProxy section */
27 | 5DDBB6F722E5CA6400BEA421 /* PBXContainerItemProxy */ = {
28 | isa = PBXContainerItemProxy;
29 | containerPortal = 5DDBB6BB22E5C89F00BEA421 /* Project object */;
30 | proxyType = 1;
31 | remoteGlobalIDString = 5DDBB6EE22E5CA6400BEA421;
32 | remoteInfo = ShareExtension;
33 | };
34 | /* End PBXContainerItemProxy section */
35 |
36 | /* Begin PBXCopyFilesBuildPhase section */
37 | 5DDBB6FD22E5CA6400BEA421 /* Embed App Extensions */ = {
38 | isa = PBXCopyFilesBuildPhase;
39 | buildActionMask = 2147483647;
40 | dstPath = "";
41 | dstSubfolderSpec = 13;
42 | files = (
43 | 5DDBB6F922E5CA6400BEA421 /* ShareExtension.appex in Embed App Extensions */,
44 | );
45 | name = "Embed App Extensions";
46 | runOnlyForDeploymentPostprocessing = 0;
47 | };
48 | /* End PBXCopyFilesBuildPhase section */
49 |
50 | /* Begin PBXFileReference section */
51 | 5D0A79E022E9F02D007C84B1 /* DictionaryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryCell.swift; sourceTree = ""; };
52 | 5D0A79E222EA28A9007C84B1 /* ImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCell.swift; sourceTree = ""; };
53 | 5D0A79E422EAE522007C84B1 /* String+Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Utility.swift"; sourceTree = ""; };
54 | 5D74E33A22E8571100EFF3AA /* ShareViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewModel.swift; sourceTree = ""; };
55 | 5D74E33C22E85ADD00EFF3AA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
56 | 5D74E34122E8D60300EFF3AA /* TextCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextCell.swift; sourceTree = ""; };
57 | 5D74E34322E8D95300EFF3AA /* UITableViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewModel.swift; sourceTree = ""; };
58 | 5DDBB6C322E5C89F00BEA421 /* ShareInspector.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShareInspector.app; sourceTree = BUILT_PRODUCTS_DIR; };
59 | 5DDBB6C622E5C89F00BEA421 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
60 | 5DDBB6C822E5C89F00BEA421 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
61 | 5DDBB6CB22E5C89F00BEA421 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
62 | 5DDBB6CD22E5C8A000BEA421 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
63 | 5DDBB6D022E5C8A000BEA421 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
64 | 5DDBB6D222E5C8A000BEA421 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
65 | 5DDBB6EF22E5CA6400BEA421 /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
66 | 5DDBB6F122E5CA6400BEA421 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; };
67 | 5DDBB6F422E5CA6400BEA421 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; };
68 | 5DDBB6F622E5CA6400BEA421 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
69 | /* End PBXFileReference section */
70 |
71 | /* Begin PBXFrameworksBuildPhase section */
72 | 5DDBB6C022E5C89F00BEA421 /* Frameworks */ = {
73 | isa = PBXFrameworksBuildPhase;
74 | buildActionMask = 2147483647;
75 | files = (
76 | );
77 | runOnlyForDeploymentPostprocessing = 0;
78 | };
79 | 5DDBB6EC22E5CA6400BEA421 /* Frameworks */ = {
80 | isa = PBXFrameworksBuildPhase;
81 | buildActionMask = 2147483647;
82 | files = (
83 | );
84 | runOnlyForDeploymentPostprocessing = 0;
85 | };
86 | /* End PBXFrameworksBuildPhase section */
87 |
88 | /* Begin PBXGroup section */
89 | 5DDBB6BA22E5C89F00BEA421 = {
90 | isa = PBXGroup;
91 | children = (
92 | 5D74E33C22E85ADD00EFF3AA /* README.md */,
93 | 5DDBB6C522E5C89F00BEA421 /* ShareInspector */,
94 | 5DDBB6F022E5CA6400BEA421 /* ShareExtension */,
95 | 5DDBB6C422E5C89F00BEA421 /* Products */,
96 | );
97 | sourceTree = "";
98 | };
99 | 5DDBB6C422E5C89F00BEA421 /* Products */ = {
100 | isa = PBXGroup;
101 | children = (
102 | 5DDBB6C322E5C89F00BEA421 /* ShareInspector.app */,
103 | 5DDBB6EF22E5CA6400BEA421 /* ShareExtension.appex */,
104 | );
105 | name = Products;
106 | sourceTree = "";
107 | };
108 | 5DDBB6C522E5C89F00BEA421 /* ShareInspector */ = {
109 | isa = PBXGroup;
110 | children = (
111 | 5DDBB6CD22E5C8A000BEA421 /* Assets.xcassets */,
112 | 5DDBB6C622E5C89F00BEA421 /* AppDelegate.swift */,
113 | 5DDBB6D222E5C8A000BEA421 /* Info.plist */,
114 | 5DDBB6CF22E5C8A000BEA421 /* LaunchScreen.storyboard */,
115 | 5DDBB6CA22E5C89F00BEA421 /* Main.storyboard */,
116 | 5DDBB6C822E5C89F00BEA421 /* ViewController.swift */,
117 | );
118 | path = ShareInspector;
119 | sourceTree = "";
120 | };
121 | 5DDBB6F022E5CA6400BEA421 /* ShareExtension */ = {
122 | isa = PBXGroup;
123 | children = (
124 | 5D0A79E022E9F02D007C84B1 /* DictionaryCell.swift */,
125 | 5D0A79E222EA28A9007C84B1 /* ImageCell.swift */,
126 | 5DDBB6F122E5CA6400BEA421 /* ShareViewController.swift */,
127 | 5D74E33A22E8571100EFF3AA /* ShareViewModel.swift */,
128 | 5D0A79E422EAE522007C84B1 /* String+Utility.swift */,
129 | 5D74E34122E8D60300EFF3AA /* TextCell.swift */,
130 | 5D74E34322E8D95300EFF3AA /* UITableViewModel.swift */,
131 | 5DDBB6F322E5CA6400BEA421 /* MainInterface.storyboard */,
132 | 5DDBB6F622E5CA6400BEA421 /* Info.plist */,
133 | );
134 | path = ShareExtension;
135 | sourceTree = "";
136 | };
137 | /* End PBXGroup section */
138 |
139 | /* Begin PBXNativeTarget section */
140 | 5DDBB6C222E5C89F00BEA421 /* ShareInspector */ = {
141 | isa = PBXNativeTarget;
142 | buildConfigurationList = 5DDBB6D522E5C8A000BEA421 /* Build configuration list for PBXNativeTarget "ShareInspector" */;
143 | buildPhases = (
144 | 5DDBB6BF22E5C89F00BEA421 /* Sources */,
145 | 5DDBB6C022E5C89F00BEA421 /* Frameworks */,
146 | 5DDBB6C122E5C89F00BEA421 /* Resources */,
147 | 5DDBB6FD22E5CA6400BEA421 /* Embed App Extensions */,
148 | );
149 | buildRules = (
150 | );
151 | dependencies = (
152 | 5DDBB6F822E5CA6400BEA421 /* PBXTargetDependency */,
153 | );
154 | name = ShareInspector;
155 | productName = ShareInspector;
156 | productReference = 5DDBB6C322E5C89F00BEA421 /* ShareInspector.app */;
157 | productType = "com.apple.product-type.application";
158 | };
159 | 5DDBB6EE22E5CA6400BEA421 /* ShareExtension */ = {
160 | isa = PBXNativeTarget;
161 | buildConfigurationList = 5DDBB6FC22E5CA6400BEA421 /* Build configuration list for PBXNativeTarget "ShareExtension" */;
162 | buildPhases = (
163 | 5DDBB6EB22E5CA6400BEA421 /* Sources */,
164 | 5DDBB6EC22E5CA6400BEA421 /* Frameworks */,
165 | 5DDBB6ED22E5CA6400BEA421 /* Resources */,
166 | );
167 | buildRules = (
168 | );
169 | dependencies = (
170 | );
171 | name = ShareExtension;
172 | productName = ShareExtension;
173 | productReference = 5DDBB6EF22E5CA6400BEA421 /* ShareExtension.appex */;
174 | productType = "com.apple.product-type.app-extension";
175 | };
176 | /* End PBXNativeTarget section */
177 |
178 | /* Begin PBXProject section */
179 | 5DDBB6BB22E5C89F00BEA421 /* Project object */ = {
180 | isa = PBXProject;
181 | attributes = {
182 | LastSwiftUpdateCheck = 1020;
183 | LastUpgradeCheck = 1020;
184 | ORGANIZATIONNAME = "Ole Begemann";
185 | TargetAttributes = {
186 | 5DDBB6C222E5C89F00BEA421 = {
187 | CreatedOnToolsVersion = 10.2.1;
188 | };
189 | 5DDBB6EE22E5CA6400BEA421 = {
190 | CreatedOnToolsVersion = 10.2.1;
191 | };
192 | };
193 | };
194 | buildConfigurationList = 5DDBB6BE22E5C89F00BEA421 /* Build configuration list for PBXProject "ShareInspector" */;
195 | compatibilityVersion = "Xcode 9.3";
196 | developmentRegion = en;
197 | hasScannedForEncodings = 0;
198 | knownRegions = (
199 | en,
200 | Base,
201 | );
202 | mainGroup = 5DDBB6BA22E5C89F00BEA421;
203 | productRefGroup = 5DDBB6C422E5C89F00BEA421 /* Products */;
204 | projectDirPath = "";
205 | projectRoot = "";
206 | targets = (
207 | 5DDBB6C222E5C89F00BEA421 /* ShareInspector */,
208 | 5DDBB6EE22E5CA6400BEA421 /* ShareExtension */,
209 | );
210 | };
211 | /* End PBXProject section */
212 |
213 | /* Begin PBXResourcesBuildPhase section */
214 | 5DDBB6C122E5C89F00BEA421 /* Resources */ = {
215 | isa = PBXResourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 5DDBB6D122E5C8A000BEA421 /* LaunchScreen.storyboard in Resources */,
219 | 5DDBB6CE22E5C8A000BEA421 /* Assets.xcassets in Resources */,
220 | 5DDBB6CC22E5C89F00BEA421 /* Main.storyboard in Resources */,
221 | );
222 | runOnlyForDeploymentPostprocessing = 0;
223 | };
224 | 5DDBB6ED22E5CA6400BEA421 /* Resources */ = {
225 | isa = PBXResourcesBuildPhase;
226 | buildActionMask = 2147483647;
227 | files = (
228 | 5DDBB6F522E5CA6400BEA421 /* MainInterface.storyboard in Resources */,
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | /* End PBXResourcesBuildPhase section */
233 |
234 | /* Begin PBXSourcesBuildPhase section */
235 | 5DDBB6BF22E5C89F00BEA421 /* Sources */ = {
236 | isa = PBXSourcesBuildPhase;
237 | buildActionMask = 2147483647;
238 | files = (
239 | 5DDBB6C922E5C89F00BEA421 /* ViewController.swift in Sources */,
240 | 5DDBB6C722E5C89F00BEA421 /* AppDelegate.swift in Sources */,
241 | );
242 | runOnlyForDeploymentPostprocessing = 0;
243 | };
244 | 5DDBB6EB22E5CA6400BEA421 /* Sources */ = {
245 | isa = PBXSourcesBuildPhase;
246 | buildActionMask = 2147483647;
247 | files = (
248 | 5D74E34422E8D95300EFF3AA /* UITableViewModel.swift in Sources */,
249 | 5D0A79E122E9F02D007C84B1 /* DictionaryCell.swift in Sources */,
250 | 5D74E34222E8D60300EFF3AA /* TextCell.swift in Sources */,
251 | 5DDBB6F222E5CA6400BEA421 /* ShareViewController.swift in Sources */,
252 | 5D0A79E522EAE522007C84B1 /* String+Utility.swift in Sources */,
253 | 5D74E33B22E8571100EFF3AA /* ShareViewModel.swift in Sources */,
254 | 5D0A79E322EA28A9007C84B1 /* ImageCell.swift in Sources */,
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | };
258 | /* End PBXSourcesBuildPhase section */
259 |
260 | /* Begin PBXTargetDependency section */
261 | 5DDBB6F822E5CA6400BEA421 /* PBXTargetDependency */ = {
262 | isa = PBXTargetDependency;
263 | target = 5DDBB6EE22E5CA6400BEA421 /* ShareExtension */;
264 | targetProxy = 5DDBB6F722E5CA6400BEA421 /* PBXContainerItemProxy */;
265 | };
266 | /* End PBXTargetDependency section */
267 |
268 | /* Begin PBXVariantGroup section */
269 | 5DDBB6CA22E5C89F00BEA421 /* Main.storyboard */ = {
270 | isa = PBXVariantGroup;
271 | children = (
272 | 5DDBB6CB22E5C89F00BEA421 /* Base */,
273 | );
274 | name = Main.storyboard;
275 | sourceTree = "";
276 | };
277 | 5DDBB6CF22E5C8A000BEA421 /* LaunchScreen.storyboard */ = {
278 | isa = PBXVariantGroup;
279 | children = (
280 | 5DDBB6D022E5C8A000BEA421 /* Base */,
281 | );
282 | name = LaunchScreen.storyboard;
283 | sourceTree = "";
284 | };
285 | 5DDBB6F322E5CA6400BEA421 /* MainInterface.storyboard */ = {
286 | isa = PBXVariantGroup;
287 | children = (
288 | 5DDBB6F422E5CA6400BEA421 /* Base */,
289 | );
290 | name = MainInterface.storyboard;
291 | sourceTree = "";
292 | };
293 | /* End PBXVariantGroup section */
294 |
295 | /* Begin XCBuildConfiguration section */
296 | 5DDBB6D322E5C8A000BEA421 /* Debug */ = {
297 | isa = XCBuildConfiguration;
298 | buildSettings = {
299 | ALWAYS_SEARCH_USER_PATHS = NO;
300 | CLANG_ANALYZER_NONNULL = YES;
301 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
303 | CLANG_CXX_LIBRARY = "libc++";
304 | CLANG_ENABLE_MODULES = YES;
305 | CLANG_ENABLE_OBJC_ARC = YES;
306 | CLANG_ENABLE_OBJC_WEAK = YES;
307 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
308 | CLANG_WARN_BOOL_CONVERSION = YES;
309 | CLANG_WARN_COMMA = YES;
310 | CLANG_WARN_CONSTANT_CONVERSION = YES;
311 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
312 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
313 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
314 | CLANG_WARN_EMPTY_BODY = YES;
315 | CLANG_WARN_ENUM_CONVERSION = YES;
316 | CLANG_WARN_INFINITE_RECURSION = YES;
317 | CLANG_WARN_INT_CONVERSION = YES;
318 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
319 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
320 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
321 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
322 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
323 | CLANG_WARN_STRICT_PROTOTYPES = YES;
324 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
325 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
326 | CLANG_WARN_UNREACHABLE_CODE = YES;
327 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
328 | CODE_SIGN_IDENTITY = "iPhone Developer";
329 | COPY_PHASE_STRIP = NO;
330 | DEBUG_INFORMATION_FORMAT = dwarf;
331 | ENABLE_STRICT_OBJC_MSGSEND = YES;
332 | ENABLE_TESTABILITY = YES;
333 | GCC_C_LANGUAGE_STANDARD = gnu11;
334 | GCC_DYNAMIC_NO_PIC = NO;
335 | GCC_NO_COMMON_BLOCKS = YES;
336 | GCC_OPTIMIZATION_LEVEL = 0;
337 | GCC_PREPROCESSOR_DEFINITIONS = (
338 | "DEBUG=1",
339 | "$(inherited)",
340 | );
341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
342 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
343 | GCC_WARN_UNDECLARED_SELECTOR = YES;
344 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
345 | GCC_WARN_UNUSED_FUNCTION = YES;
346 | GCC_WARN_UNUSED_VARIABLE = YES;
347 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
348 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
349 | MTL_FAST_MATH = YES;
350 | ONLY_ACTIVE_ARCH = YES;
351 | SDKROOT = iphoneos;
352 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
353 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
354 | };
355 | name = Debug;
356 | };
357 | 5DDBB6D422E5C8A000BEA421 /* Release */ = {
358 | isa = XCBuildConfiguration;
359 | buildSettings = {
360 | ALWAYS_SEARCH_USER_PATHS = NO;
361 | CLANG_ANALYZER_NONNULL = YES;
362 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
363 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
364 | CLANG_CXX_LIBRARY = "libc++";
365 | CLANG_ENABLE_MODULES = YES;
366 | CLANG_ENABLE_OBJC_ARC = YES;
367 | CLANG_ENABLE_OBJC_WEAK = YES;
368 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
369 | CLANG_WARN_BOOL_CONVERSION = YES;
370 | CLANG_WARN_COMMA = YES;
371 | CLANG_WARN_CONSTANT_CONVERSION = YES;
372 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
374 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
375 | CLANG_WARN_EMPTY_BODY = YES;
376 | CLANG_WARN_ENUM_CONVERSION = YES;
377 | CLANG_WARN_INFINITE_RECURSION = YES;
378 | CLANG_WARN_INT_CONVERSION = YES;
379 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
380 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
381 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
383 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
384 | CLANG_WARN_STRICT_PROTOTYPES = YES;
385 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
386 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
387 | CLANG_WARN_UNREACHABLE_CODE = YES;
388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
389 | CODE_SIGN_IDENTITY = "iPhone Developer";
390 | COPY_PHASE_STRIP = NO;
391 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
392 | ENABLE_NS_ASSERTIONS = NO;
393 | ENABLE_STRICT_OBJC_MSGSEND = YES;
394 | GCC_C_LANGUAGE_STANDARD = gnu11;
395 | GCC_NO_COMMON_BLOCKS = YES;
396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
398 | GCC_WARN_UNDECLARED_SELECTOR = YES;
399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
400 | GCC_WARN_UNUSED_FUNCTION = YES;
401 | GCC_WARN_UNUSED_VARIABLE = YES;
402 | IPHONEOS_DEPLOYMENT_TARGET = 12.2;
403 | MTL_ENABLE_DEBUG_INFO = NO;
404 | MTL_FAST_MATH = YES;
405 | SDKROOT = iphoneos;
406 | SWIFT_COMPILATION_MODE = wholemodule;
407 | SWIFT_OPTIMIZATION_LEVEL = "-O";
408 | VALIDATE_PRODUCT = YES;
409 | };
410 | name = Release;
411 | };
412 | 5DDBB6D622E5C8A000BEA421 /* Debug */ = {
413 | isa = XCBuildConfiguration;
414 | buildSettings = {
415 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
416 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
417 | CODE_SIGN_STYLE = Automatic;
418 | DEVELOPMENT_TEAM = B8YY74J254;
419 | INFOPLIST_FILE = ShareInspector/Info.plist;
420 | LD_RUNPATH_SEARCH_PATHS = (
421 | "$(inherited)",
422 | "@executable_path/Frameworks",
423 | );
424 | PRODUCT_BUNDLE_IDENTIFIER = com.cocologics.ShareInspector;
425 | PRODUCT_NAME = "$(TARGET_NAME)";
426 | SWIFT_VERSION = 5.0;
427 | TARGETED_DEVICE_FAMILY = "1,2";
428 | };
429 | name = Debug;
430 | };
431 | 5DDBB6D722E5C8A000BEA421 /* Release */ = {
432 | isa = XCBuildConfiguration;
433 | buildSettings = {
434 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
435 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
436 | CODE_SIGN_STYLE = Automatic;
437 | DEVELOPMENT_TEAM = B8YY74J254;
438 | INFOPLIST_FILE = ShareInspector/Info.plist;
439 | LD_RUNPATH_SEARCH_PATHS = (
440 | "$(inherited)",
441 | "@executable_path/Frameworks",
442 | );
443 | PRODUCT_BUNDLE_IDENTIFIER = com.cocologics.ShareInspector;
444 | PRODUCT_NAME = "$(TARGET_NAME)";
445 | SWIFT_VERSION = 5.0;
446 | TARGETED_DEVICE_FAMILY = "1,2";
447 | };
448 | name = Release;
449 | };
450 | 5DDBB6FA22E5CA6400BEA421 /* Debug */ = {
451 | isa = XCBuildConfiguration;
452 | buildSettings = {
453 | CODE_SIGN_STYLE = Automatic;
454 | DEVELOPMENT_TEAM = B8YY74J254;
455 | INFOPLIST_FILE = ShareExtension/Info.plist;
456 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
457 | LD_RUNPATH_SEARCH_PATHS = (
458 | "$(inherited)",
459 | "@executable_path/Frameworks",
460 | "@executable_path/../../Frameworks",
461 | );
462 | PRODUCT_BUNDLE_IDENTIFIER = com.cocologics.ShareInspector.ShareExtension;
463 | PRODUCT_NAME = "$(TARGET_NAME)";
464 | SKIP_INSTALL = YES;
465 | SWIFT_VERSION = 5.0;
466 | TARGETED_DEVICE_FAMILY = "1,2";
467 | };
468 | name = Debug;
469 | };
470 | 5DDBB6FB22E5CA6400BEA421 /* Release */ = {
471 | isa = XCBuildConfiguration;
472 | buildSettings = {
473 | CODE_SIGN_STYLE = Automatic;
474 | DEVELOPMENT_TEAM = B8YY74J254;
475 | INFOPLIST_FILE = ShareExtension/Info.plist;
476 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
477 | LD_RUNPATH_SEARCH_PATHS = (
478 | "$(inherited)",
479 | "@executable_path/Frameworks",
480 | "@executable_path/../../Frameworks",
481 | );
482 | PRODUCT_BUNDLE_IDENTIFIER = com.cocologics.ShareInspector.ShareExtension;
483 | PRODUCT_NAME = "$(TARGET_NAME)";
484 | SKIP_INSTALL = YES;
485 | SWIFT_VERSION = 5.0;
486 | TARGETED_DEVICE_FAMILY = "1,2";
487 | };
488 | name = Release;
489 | };
490 | /* End XCBuildConfiguration section */
491 |
492 | /* Begin XCConfigurationList section */
493 | 5DDBB6BE22E5C89F00BEA421 /* Build configuration list for PBXProject "ShareInspector" */ = {
494 | isa = XCConfigurationList;
495 | buildConfigurations = (
496 | 5DDBB6D322E5C8A000BEA421 /* Debug */,
497 | 5DDBB6D422E5C8A000BEA421 /* Release */,
498 | );
499 | defaultConfigurationIsVisible = 0;
500 | defaultConfigurationName = Release;
501 | };
502 | 5DDBB6D522E5C8A000BEA421 /* Build configuration list for PBXNativeTarget "ShareInspector" */ = {
503 | isa = XCConfigurationList;
504 | buildConfigurations = (
505 | 5DDBB6D622E5C8A000BEA421 /* Debug */,
506 | 5DDBB6D722E5C8A000BEA421 /* Release */,
507 | );
508 | defaultConfigurationIsVisible = 0;
509 | defaultConfigurationName = Release;
510 | };
511 | 5DDBB6FC22E5CA6400BEA421 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
512 | isa = XCConfigurationList;
513 | buildConfigurations = (
514 | 5DDBB6FA22E5CA6400BEA421 /* Debug */,
515 | 5DDBB6FB22E5CA6400BEA421 /* Release */,
516 | );
517 | defaultConfigurationIsVisible = 0;
518 | defaultConfigurationName = Release;
519 | };
520 | /* End XCConfigurationList section */
521 | };
522 | rootObject = 5DDBB6BB22E5C89F00BEA421 /* Project object */;
523 | }
524 |
--------------------------------------------------------------------------------
/ShareInspector.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ShareInspector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ShareInspector/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 | var window: UIWindow?
6 |
7 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
8 | return true
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-App-20x20@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-App-20x20@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-App-29x29@1x.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-App-29x29@2x.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "29x29",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-App-29x29@3x.png",
31 | "scale" : "3x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-App-40x40@2x.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "40x40",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-App-40x40@3x.png",
43 | "scale" : "3x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-App-60x60@2x.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "60x60",
53 | "idiom" : "iphone",
54 | "filename" : "Icon-App-60x60@3x.png",
55 | "scale" : "3x"
56 | },
57 | {
58 | "idiom" : "ipad",
59 | "size" : "20x20",
60 | "scale" : "1x"
61 | },
62 | {
63 | "idiom" : "ipad",
64 | "size" : "20x20",
65 | "scale" : "2x"
66 | },
67 | {
68 | "idiom" : "ipad",
69 | "size" : "29x29",
70 | "scale" : "1x"
71 | },
72 | {
73 | "idiom" : "ipad",
74 | "size" : "29x29",
75 | "scale" : "2x"
76 | },
77 | {
78 | "idiom" : "ipad",
79 | "size" : "40x40",
80 | "scale" : "1x"
81 | },
82 | {
83 | "idiom" : "ipad",
84 | "size" : "40x40",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-App-76x76@1x.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-App-76x76@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-App-83.5x83.5@2x.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "Icon-App-iTunes.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-iTunes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/ShareInspector/Assets.xcassets/AppIcon.appiconset/Icon-App-iTunes.png
--------------------------------------------------------------------------------
/ShareInspector/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ShareInspector/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 |
--------------------------------------------------------------------------------
/ShareInspector/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 |
28 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/ShareInspector/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Inspector
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ShareInspector/ViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class ViewController: UIViewController {}
4 |
--------------------------------------------------------------------------------
/screenshots/Device-PhotosApp-LivePhoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/screenshots/Device-PhotosApp-LivePhoto.png
--------------------------------------------------------------------------------
/screenshots/Device-Safari-WebPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/screenshots/Device-Safari-WebPage.png
--------------------------------------------------------------------------------
/screenshots/Screenshot-PhotosApp-LivePhoto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/screenshots/Screenshot-PhotosApp-LivePhoto.png
--------------------------------------------------------------------------------
/screenshots/Screenshot-Safari-WebPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cocologics/ShareInspector/b2fc5338e738fbfc6b83786b6403fb7ef2975901/screenshots/Screenshot-Safari-WebPage.png
--------------------------------------------------------------------------------